从用户态的open到内核驱动实现流程

 

从用户态的open到内核驱动实现流程

 

作者:李老师, 华清远见嵌入式学院讲师。

 

问题来源:

 

在讲授Linux初级驱动的时候,我发现困惑很多同学的是不真正理解从应用层到我们自己所写的驱动层的调用过程,所以写此文章来大概描述。

 

首先我们知道,在我们目前的Linux系统中,我们大概共约300左右个系统调用,其中linux/arch/arm/kernel/calls.S列出了所有的系统调用表。

 

在本文件中记录了所有当前平台系统中所提供的系统调用表,其中第五项就包括:

 

.long sys_open /* 5 */

 

---------------------------- -

查看sys_open() 函数,我们看到里面所完成的工作为:

1、查看打开的是否是大文件,如果是的话,置大文件标志位:O_LARGEFILE

2、做do_sys_open()函数调用。

3、检查2的调用返回值ret是否有效。

---------------------------- -

 

---------------------------- -

查看do_sys_open()函数所完成的工作为:

调用getname() ,getname函数主要功能是在使用文件名之前将其拷贝到内核数据区,正常结束时返回内核分配的空间首地址,出错时返回错误代码。

取得系统中可用的文件描述符fd。

调用do_filp_open()函数,此函数使用了一个数据结构nameidata来描述与文件相关的文件操作。

 

struct nameidata {

struct dentry                *dentry;        // 目录数据

struct vfsmount        *mnt;        // 虚拟文件挂载点数据

struct qstr        last;        // hash值

unsigned int        flags;        // 文件操作标识

int last_type;        // 类型

unsigned                depth;

char                        *saved_names[MAX_NESTED_LINKS + 1];

union {

struct open_intent open;

intent// 专用数据

};

---------------------------- -

 

---------------------------- -

struct file *do_filp_open(const char * filenameint flagsint mode){

int namei_flagserror;

struct nameidata nd;

namei_flags = flags;

if ((namei_flags + 1) & O_ACCMODE)

namei_flags++;        // 如果flags有O_WRONLY,则增加O_RDONLY

 

error = open_namei(filenamenamei_flagsmode, &nd);

// open_namei函数主要执行文件操作的inode部分的打开等操作。

if (!error)

return nameidata_to_filp(ndflags);

// 把文件的inod相关信息转换成文件结构。

return ERR_PTR(error);        // 返回错误代码

}

---------------------------- -

 

---------------------------- -

我们下面来看这个比较关键的函数:nameidata_to_filp() :

struct file * nameidata_to_filp(struct nameidata *ndint flags)

{

struct file *filp;

 

/* Pick up the filp from the open intent */

filp = nd->intent.open.file;

// 把相关 file结构的指针赋予 filp。 

/* Has the filesystem initialised the file for us? */

if (filp->f_path.dentry == NULL)

filp = __dentry_open(nd->dentrynd->mntflagsfilpNULL);

// ***** 关键函数 ***** //

else

path_release(nd);

return filp;

}

---------------------------- -

 

---------------------------- -

关键函数:__dentry_open() :

static struct file *__dentry_open(struct dentry *dentrystruct vfsmount *mnt,

int flagsstruct file *f,

int(*open)(struct inode *, struct file *))

{

......

f->f_pos = 0;

f->f_op = fops_get(inode->i_fop);

// 在这里进行赋值,f->f_op = &def_chr_fops,注意上文inode->i_fop中的赋值。

file_move(f, &inode->i_sb->s_files);

 

if (!open && f->f_op)

// 在调用__dentry_open时open赋值为空,所以!open为真。

open = f->f_op->open;

// 在这里将open赋为chrdev_open。

if (open) {

error = open(inodef);

// 这里调用chrdev_open, 参照下文。

if (error)

goto cleanup_all;

......

}

---------------------------- -

 

---------------------------- -

在函数chrdev_open中(/ fs / char_dev.v) :

int chrdev_open(struct inode * inodestruct file * filp)

{

......

kobj = kobj_lookup(cdev_mapinode->i_rdev, &idx);

// 执行kobj_lookup函数,在cdev_map里寻找相应的inode->i_rdev设备。

// cdev_map是一个256个probe结构组成的数组,用于查找具有相应设备号的设备。

// inode->i_rdev为设备号。

 

new = container_of(kobjstruct cdevkobj);

//从kobj的位置倒算出cdev的内存地址,获得包含相应kobj的cdev。

 

inode->i_cdev = p = new;

// 到这里p已经为我们要的设备cdev了。

 

filp->f_op = fops_get(p->ops);

/ / 拿到 cdev操作集。

// 至此以后read,write操作都通过file->f_op直接与我们要的设备操作集挂钩了。

......

}

---------------------------- -

 

到此,系统通过file->f_op 就与我们在设备驱动里面的定义的相关操作联系起来了,我们之前在写驱动实现的功能操作就被系统通过应用层的open 一步一步的调用到我们自己的open跟相关其他的操作了。


这里是用的open系统调用,是linux内核接口函数,不是库函数,返回fd,详细请google, 这个open最终会调用驱动中的open函数(代码流程是这样的open()->sys_open()->filp_open()->dentry_open()->驱动open)


/*
 *  linux/arch/arm/kernel/calls.S
 *
 *  Copyright (C) 1995-2005 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  This file is included thrice in entry-common.S
 */
/* 0 */		CALL(sys_restart_syscall)
		CALL(sys_exit)
		CALL(sys_fork_wrapper)
		CALL(sys_read)
		CALL(sys_write)
/* 5 */		CALL(sys_open)
		CALL(sys_close)
		CALL(sys_ni_syscall)		/* was sys_waitpid */
		CALL(sys_creat)
		CALL(sys_link)
/* 10 */	CALL(sys_unlink)
		CALL(sys_execve_wrapper)
		CALL(sys_chdir)
		CALL(OBSOLETE(sys_time))	/* used by libc4 */
		CALL(sys_mknod)
/* 15 */	CALL(sys_chmod)
		CALL(sys_lchown16)
		CALL(sys_ni_syscall)		/* was sys_break */
		CALL(sys_ni_syscall)		/* was sys_stat */
		CALL(sys_lseek)
/* 20 */	CALL(sys_getpid)
		CALL(sys_mount)
		CALL(OBSOLETE(sys_oldumount))	/* used by libc4 */
		CALL(sys_setuid16)
		CALL(sys_getuid16)
/* 25 */	CALL(OBSOLETE(sys_stime))
		CALL(sys_ptrace)
		CALL(OBSOLETE(sys_alarm))	/* used by libc4 */
		CALL(sys_ni_syscall)		/* was sys_fstat */
		CALL(sys_pause)
/* 30 */	CALL(OBSOLETE(sys_utime))	/* used by libc4 */
		CALL(sys_ni_syscall)		/* was sys_stty */
		CALL(sys_ni_syscall)		/* was sys_getty */
		CALL(sys_access)
		CALL(sys_nice)
/* 35 */	CALL(sys_ni_syscall)		/* was sys_ftime */
		CALL(sys_sync)
		CALL(sys_kill)
		CALL(sys_rename)
		CALL(sys_mkdir)
/* 40 */	CALL(sys_rmdir)
		CALL(sys_dup)
		CALL(sys_pipe)
		CALL(sys_times)
		CALL(sys_ni_syscall)		/* was sys_prof */
/* 45 */	CALL(sys_brk)
		CALL(sys_setgid16)
		CALL(sys_getgid16)
		CALL(sys_ni_syscall)		/* was sys_signal */
		CALL(sys_geteuid16)
/* 50 */	CALL(sys_getegid16)
		CALL(sys_acct)
		CALL(sys_umount)
		CALL(sys_ni_syscall)		/* was sys_lock */
		CALL(sys_ioctl)
/* 55 */	CALL(sys_fcntl)
		CALL(sys_ni_syscall)		/* was sys_mpx */
		CALL(sys_setpgid)
		CALL(sys_ni_syscall)		/* was sys_ulimit */
		CALL(sys_ni_syscall)		/* was sys_olduname */
/* 60 */	CALL(sys_umask)
		CALL(sys_chroot)
		CALL(sys_ustat)
		CALL(sys_dup2)
		CALL(sys_getppid)
/* 65 */	CALL(sys_getpgrp)
		CALL(sys_setsid)
		CALL(sys_sigaction)
		CALL(sys_ni_syscall)		/* was sys_sgetmask */
		CALL(sys_ni_syscall)		/* was sys_ssetmask */
/* 70 */	CALL(sys_setreuid16)
		CALL(sys_setregid16)
		CALL(sys_sigsuspend)
		CALL(sys_sigpending)
		CALL(sys_sethostname)
/* 75 */	CALL(sys_setrlimit)
		CALL(OBSOLETE(sys_old_getrlimit)) /* used by libc4 */
		CALL(sys_getrusage)
		CALL(sys_gettimeofday)
		CALL(sys_settimeofday)
/* 80 */	CALL(sys_getgroups16)
		CALL(sys_setgroups16)
		CALL(OBSOLETE(sys_old_select))	/* used by libc4 */
		CALL(sys_symlink)
		CALL(sys_ni_syscall)		/* was sys_lstat */
/* 85 */	CALL(sys_readlink)
		CALL(sys_uselib)
		CALL(sys_swapon)
		CALL(sys_reboot)
		CALL(OBSOLETE(sys_old_readdir))	/* used by libc4 */
/* 90 */	CALL(OBSOLETE(sys_old_mmap))	/* used by libc4 */
		CALL(sys_munmap)
		CALL(sys_truncate)
		CALL(sys_ftruncate)
		CALL(sys_fchmod)
/* 95 */	CALL(sys_fchown16)
		CALL(sys_getpriority)
		CALL(sys_setpriority)
		CALL(sys_ni_syscall)		/* was sys_profil */
		CALL(sys_statfs)
/* 100 */	CALL(sys_fstatfs)
		CALL(sys_ni_syscall)		/* sys_ioperm */
		CALL(OBSOLETE(ABI(sys_socketcall, sys_oabi_socketcall)))
		CALL(sys_syslog)
		CALL(sys_setitimer)
/* 105 */	CALL(sys_getitimer)
		CALL(sys_newstat)
		CALL(sys_newlstat)
		CALL(sys_newfstat)
		CALL(sys_ni_syscall)		/* was sys_uname */
/* 110 */	CALL(sys_ni_syscall)		/* was sys_iopl */
		CALL(sys_vhangup)
		CALL(sys_ni_syscall)
		CALL(OBSOLETE(sys_syscall))	/* call a syscall */
		CALL(sys_wait4)
/* 115 */	CALL(sys_swapoff)
		CALL(sys_sysinfo)
		CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))
		CALL(sys_fsync)
		CALL(sys_sigreturn_wrapper)
/* 120 */	CALL(sys_clone_wrapper)
		CALL(sys_setdomainname)
		CALL(sys_newuname)
		CALL(sys_ni_syscall)		/* modify_ldt */
		CALL(sys_adjtimex)
/* 125 */	CALL(sys_mprotect)
		CALL(sys_sigprocmask)
		CALL(sys_ni_syscall)		/* was sys_create_module */
		CALL(sys_init_module)
		CALL(sys_delete_module)
/* 130 */	CALL(sys_ni_syscall)		/* was sys_get_kernel_syms */
		CALL(sys_quotactl)
		CALL(sys_getpgid)
		CALL(sys_fchdir)
		CALL(sys_bdflush)
/* 135 */	CALL(sys_sysfs)
		CALL(sys_personality)
		CALL(sys_ni_syscall)		/* reserved for afs_syscall */
		CALL(sys_setfsuid16)
		CALL(sys_setfsgid16)
/* 140 */	CALL(sys_llseek)
		CALL(sys_getdents)
		CALL(sys_select)
		CALL(sys_flock)
		CALL(sys_msync)
/* 145 */	CALL(sys_readv)
		CALL(sys_writev)
		CALL(sys_getsid)
		CALL(sys_fdatasync)
		CALL(sys_sysctl)
/* 150 */	CALL(sys_mlock)
		CALL(sys_munlock)
		CALL(sys_mlockall)
		CALL(sys_munlockall)
		CALL(sys_sched_setparam)
/* 155 */	CALL(sys_sched_getparam)
		CALL(sys_sched_setscheduler)
		CALL(sys_sched_getscheduler)
		CALL(sys_sched_yield)
		CALL(sys_sched_get_priority_max)
/* 160 */	CALL(sys_sched_get_priority_min)
		CALL(sys_sched_rr_get_interval)
		CALL(sys_nanosleep)
		CALL(sys_mremap)
		CALL(sys_setresuid16)
/* 165 */	CALL(sys_getresuid16)
		CALL(sys_ni_syscall)		/* vm86 */
		CALL(sys_ni_syscall)		/* was sys_query_module */
		CALL(sys_poll)
		CALL(sys_ni_syscall)		/* was nfsservctl */
/* 170 */	CALL(sys_setresgid16)
		CALL(sys_getresgid16)
		CALL(sys_prctl)
		CALL(sys_rt_sigreturn_wrapper)
		CALL(sys_rt_sigaction)
/* 175 */	CALL(sys_rt_sigprocmask)
		CALL(sys_rt_sigpending)
		CALL(sys_rt_sigtimedwait)
		CALL(sys_rt_sigqueueinfo)
		CALL(sys_rt_sigsuspend)
/* 180 */	CALL(ABI(sys_pread64, sys_oabi_pread64))
		CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
		CALL(sys_chown16)
		CALL(sys_getcwd)
		CALL(sys_capget)
/* 185 */	CALL(sys_capset)
		CALL(sys_sigaltstack_wrapper)
		CALL(sys_sendfile)
		CALL(sys_ni_syscall)		/* getpmsg */
		CALL(sys_ni_syscall)		/* putpmsg */
/* 190 */	CALL(sys_vfork_wrapper)
		CALL(sys_getrlimit)
		CALL(sys_mmap2)
		CALL(ABI(sys_truncate64, sys_oabi_truncate64))
		CALL(ABI(sys_ftruncate64, sys_oabi_ftruncate64))
/* 195 */	CALL(ABI(sys_stat64, sys_oabi_stat64))
		CALL(ABI(sys_lstat64, sys_oabi_lstat64))
		CALL(ABI(sys_fstat64, sys_oabi_fstat64))
		CALL(sys_lchown)
		CALL(sys_getuid)
/* 200 */	CALL(sys_getgid)
		CALL(sys_geteuid)
		CALL(sys_getegid)
		CALL(sys_setreuid)
		CALL(sys_setregid)
/* 205 */	CALL(sys_getgroups)
		CALL(sys_setgroups)
		CALL(sys_fchown)
		CALL(sys_setresuid)
		CALL(sys_getresuid)
/* 210 */	CALL(sys_setresgid)
		CALL(sys_getresgid)
		CALL(sys_chown)
		CALL(sys_setuid)
		CALL(sys_setgid)
/* 215 */	CALL(sys_setfsuid)
		CALL(sys_setfsgid)
		CALL(sys_getdents64)
		CALL(sys_pivot_root)
		CALL(sys_mincore)
/* 220 */	CALL(sys_madvise)
		CALL(ABI(sys_fcntl64, sys_oabi_fcntl64))
		CALL(sys_ni_syscall) /* TUX */
		CALL(sys_ni_syscall)
		CALL(sys_gettid)
/* 225 */	CALL(ABI(sys_readahead, sys_oabi_readahead))
		CALL(sys_setxattr)
		CALL(sys_lsetxattr)
		CALL(sys_fsetxattr)
		CALL(sys_getxattr)
/* 230 */	CALL(sys_lgetxattr)
		CALL(sys_fgetxattr)
		CALL(sys_listxattr)
		CALL(sys_llistxattr)
		CALL(sys_flistxattr)
/* 235 */	CALL(sys_removexattr)
		CALL(sys_lremovexattr)
		CALL(sys_fremovexattr)
		CALL(sys_tkill)
		CALL(sys_sendfile64)
/* 240 */	CALL(sys_futex)
		CALL(sys_sched_setaffinity)
		CALL(sys_sched_getaffinity)
		CALL(sys_io_setup)
		CALL(sys_io_destroy)
/* 245 */	CALL(sys_io_getevents)
		CALL(sys_io_submit)
		CALL(sys_io_cancel)
		CALL(sys_exit_group)
		CALL(sys_lookup_dcookie)
/* 250 */	CALL(sys_epoll_create)
		CALL(ABI(sys_epoll_ctl, sys_oabi_epoll_ctl))
		CALL(ABI(sys_epoll_wait, sys_oabi_epoll_wait))
		CALL(sys_remap_file_pages)
		CALL(sys_ni_syscall)	/* sys_set_thread_area */
/* 255 */	CALL(sys_ni_syscall)	/* sys_get_thread_area */
		CALL(sys_set_tid_address)
		CALL(sys_timer_create)
		CALL(sys_timer_settime)
		CALL(sys_timer_gettime)
/* 260 */	CALL(sys_timer_getoverrun)
		CALL(sys_timer_delete)
		CALL(sys_clock_settime)
		CALL(sys_clock_gettime)
		CALL(sys_clock_getres)
/* 265 */	CALL(sys_clock_nanosleep)
		CALL(sys_statfs64_wrapper)
		CALL(sys_fstatfs64_wrapper)
		CALL(sys_tgkill)
		CALL(sys_utimes)
/* 270 */	CALL(sys_arm_fadvise64_64)
		CALL(sys_pciconfig_iobase)
		CALL(sys_pciconfig_read)
		CALL(sys_pciconfig_write)
		CALL(sys_mq_open)
/* 275 */	CALL(sys_mq_unlink)
		CALL(sys_mq_timedsend)
		CALL(sys_mq_timedreceive)
		CALL(sys_mq_notify)
		CALL(sys_mq_getsetattr)
/* 280 */	CALL(sys_waitid)
		CALL(sys_socket)
		CALL(ABI(sys_bind, sys_oabi_bind))
		CALL(ABI(sys_connect, sys_oabi_connect))
		CALL(sys_listen)
/* 285 */	CALL(sys_accept)
		CALL(sys_getsockname)
		CALL(sys_getpeername)
		CALL(sys_socketpair)
		CALL(sys_send)
/* 290 */	CALL(ABI(sys_sendto, sys_oabi_sendto))
		CALL(sys_recv)
		CALL(sys_recvfrom)
		CALL(sys_shutdown)
		CALL(sys_setsockopt)
/* 295 */	CALL(sys_getsockopt)
		CALL(ABI(sys_sendmsg, sys_oabi_sendmsg))
		CALL(sys_recvmsg)
		CALL(ABI(sys_semop, sys_oabi_semop))
		CALL(sys_semget)
/* 300 */	CALL(sys_semctl)
		CALL(sys_msgsnd)
		CALL(sys_msgrcv)
		CALL(sys_msgget)
		CALL(sys_msgctl)
/* 305 */	CALL(sys_shmat)
		CALL(sys_shmdt)
		CALL(sys_shmget)
		CALL(sys_shmctl)
		CALL(sys_add_key)
/* 310 */	CALL(sys_request_key)
		CALL(sys_keyctl)
		CALL(ABI(sys_semtimedop, sys_oabi_semtimedop))
/* vserver */	CALL(sys_ni_syscall)
		CALL(sys_ioprio_set)
/* 315 */	CALL(sys_ioprio_get)
		CALL(sys_inotify_init)
		CALL(sys_inotify_add_watch)
		CALL(sys_inotify_rm_watch)
		CALL(sys_mbind)
/* 320 */	CALL(sys_get_mempolicy)
		CALL(sys_set_mempolicy)
		CALL(sys_openat)
		CALL(sys_mkdirat)
		CALL(sys_mknodat)
/* 325 */	CALL(sys_fchownat)
		CALL(sys_futimesat)
		CALL(ABI(sys_fstatat64,  sys_oabi_fstatat64))
		CALL(sys_unlinkat)
		CALL(sys_renameat)
/* 330 */	CALL(sys_linkat)
		CALL(sys_symlinkat)
		CALL(sys_readlinkat)
		CALL(sys_fchmodat)
		CALL(sys_faccessat)
/* 335 */	CALL(sys_pselect6)
		CALL(sys_ppoll)
		CALL(sys_unshare)
		CALL(sys_set_robust_list)
		CALL(sys_get_robust_list)
/* 340 */	CALL(sys_splice)
		CALL(sys_sync_file_range2)
		CALL(sys_tee)
		CALL(sys_vmsplice)
		CALL(sys_move_pages)
/* 345 */	CALL(sys_getcpu)
		CALL(sys_epoll_pwait)
		CALL(sys_kexec_load)
		CALL(sys_utimensat)
		CALL(sys_signalfd)
/* 350 */	CALL(sys_timerfd_create)
		CALL(sys_eventfd)
		CALL(sys_fallocate)
		CALL(sys_timerfd_settime)
		CALL(sys_timerfd_gettime)
/* 355 */	CALL(sys_signalfd4)
		CALL(sys_eventfd2)
		CALL(sys_epoll_create1)
		CALL(sys_dup3)
		CALL(sys_pipe2)
/* 360 */	CALL(sys_inotify_init1)
		CALL(sys_preadv)
		CALL(sys_pwritev)
		CALL(sys_rt_tgsigqueueinfo)
		CALL(sys_perf_event_open)
/* 365 */	CALL(sys_recvmmsg)
		CALL(sys_accept4)
		CALL(sys_fanotify_init)
		CALL(sys_fanotify_mark)
		CALL(sys_prlimit64)
/* 370 */	CALL(sys_name_to_handle_at)
		CALL(sys_open_by_handle_at)
		CALL(sys_clock_adjtime)
		CALL(sys_syncfs)
		CALL(sys_sendmmsg)
/* 375 */	CALL(sys_setns)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
#endif
.rept syscalls_padding
		CALL(sys_ni_syscall)
.endr


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值