首页 > 编程知识 正文

sys_mknod原理,linux syscall

时间:2023-05-03 21:33:17 阅读:165401 作者:406

进入上一个分析。 命令:使用mknod /dev/my_chr_dev0 c $major 0创建设备文件时,内核做了什么? 确实,内核始终创建inode结构并将其添加到系统中。 否则,打开设备文件时,lookup_fast )函数找不到相应的inode,打开失败。 也许,lookup_fast (也许你会说函数失败了。 另外,lookup_slow ) )函数是? 因为这里是特殊的文件,所以情况不同。 lookup_fast ) )函数失败时,打开失败。 lookup_slow ) )函数中不会动态创建inode,但创建inode的工作实际上是在mknod系统调用中进行的。 让我们简单分析一下其具体过程。

首先使用strace检查以下系统调用的传入参数:

strace-osyscallmknod/dev/test c 2430的结果如下:

. mknod ()/dev/test )、S_IFCHR|0666、makedev )、243、0 ) .现在,让我们来看看内核中mknod系统调用的定义。 在source/fs/namei.c .上

syscall_define3(mknod,const char __user *,filename,umode_t,mode,unsigned,dev ) returnsys_mknodat ) }现在,我们来看看sys_mknodat的定义:

syscall_define4(mknodat,int,dfd,const char __user *,filename,umode_t,mode,unsigned, dev ) ./*此处. switch(modes_ifmt ) ./*此处为inode */cases _ if chr : cases _ if blk : error=VFS _ mknod ) ……你可以看出,其实两步: 1、做枝节; 2、创建inode。 首先,我们来看看dentry的创建,user_path_create ()函数的定义。

inlinestructdentry * user _ path _ create (int DFD,const char __user *pathname,struct path *path,unsignedintlookup }

staticstructdentry * filename _ create (int DFD,struct filename *name,struct path *path,unsigned int lookup_flags ) ) .返回目录; }其中,filename_parentat ()函数主要完成了路径分析的工作,其中调用path_parentat )-link_path_walk )函数完成了路径分析工作。 在上一篇文章和中进行了说明,但在此省略详细的分析。 __lookup_hash ) )函数首先在系统缓存中搜索dentry,如果找不到,主要调用d_alloc )函数创建新的dentry并将其添加到系统中。 之前也介绍了主要使用的函数,这里不进行分析。 重点分析inode的创建过程。 vfs_mknod ) )函数:

intVFS_mknod(structinode*dir,struct dentry *dentry,umode_t mode,dev_t dev ) . error=dir-I _ op-MK Noor 这里是文件系统相关函数: dir-

>i_op->mknod()。这是父目录 /dev 的i_op->mknod 函数,这个函数指针指向的是shmem_mknod()函数:

static intshmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev){struct inode *inode;int error = -ENOSPC;inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);if (inode) {...d_instantiate(dentry, inode); /* 可简单理解成: dentry->d_inode = inode; */dget(dentry); /* Extra count - pin the dentry in core */}return error; ...}

其中主要工作是在 shmem_get_inode()函数中完成:

static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir, umode_t mode, dev_t dev, unsigned long flags){struct inode *inode;struct shmem_inode_info *info;struct shmem_sb_info *sbinfo = SHMEM_SB(sb);if (shmem_reserve_inode(sb))return NULL;/* 在内核空间创建 inode 结构体(分配内存) */inode = new_inode(sb);if (inode) {/* 下面是各种成员变量的初始化 */inode->i_ino = get_next_ino();inode_init_owner(inode, dir, mode);inode->i_blocks = 0;inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);inode->i_generation = get_seconds();info = SHMEM_I(inode);memset(info, 0, (char *)inode - (char *)info);spin_lock_init(&info->lock);info->seals = F_SEAL_SEAL;info->flags = flags & VM_NORESERVE;INIT_LIST_HEAD(&info->shrinklist);INIT_LIST_HEAD(&info->swaplist);simple_xattrs_init(&info->xattrs);cache_no_acl(inode);/***********************************************/switch (mode & S_IFMT) {default:inode->i_op = &shmem_special_inode_operations;init_special_inode(inode, mode, dev); /* 我们最感兴趣的在这里 */break;...}} elseshmem_free_inode(sb);return inode;}

可见在这个函数里面,首先通过new_inode()函数在内核空间分配内存,这里不再详细展开。然后对各个成员变量进行初始化,这里我们也不感兴趣,最感兴趣的地方在 init_special_inode()函数里面:

void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev){inode->i_mode = mode;if (S_ISCHR(mode)) {inode->i_fop = &def_chr_fops;inode->i_rdev = rdev;} ...}

可见这里保存了两个重要的成员变量:文件操作函数集和设备号。而这个文件操作函数集是一个通用的操作集,所有字符驱动文件打开时都会调用,在这个函数里面,通过设备号来找到真正的该设备的文件操作函数集。先看这个 def_chr_fops 的定义:

/* * Dummy default file-operations: the only thing this does * is contain the open that then fills in the correct operations * depending on the special file... */const struct file_operations def_chr_fops = {.open = chrdev_open,.llseek = noop_llseek,};

而这个 chrdev_open()函数就是我们上一篇里面分析的函数。可见这个 mknod 系统调用无非就是把文件的设备号保存到新创建的 inode 里面,而真正的驱动相关的文件操作函数集并没有保存在这里面,而是保存在 cdev_map->probes 数组中(上一篇分析过),但巧妙之处在于我们可以通过文件的设备号轻松的找到驱动相关的文件操作函数集。最后一点需要说明的是我们回到 shmem_mknod()函数,这里显式的调用了 dget() 函数。其实在通过调用d_alloc()函数创建新的 dentry 时,已经将将其引用计数设置为1:

dentry->d_lockref.count = 1这里再次调用 dget() 函数就是要保证通过 mknod 函数创建的 inode 永远不会被释放掉(除非 rm /dev/my_chr_dev0)。这样就保证了 lookup_fast()函数总能成功返回。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。