文件系统--mknod系统调用

来源:互联网 发布:vmware player mac版 编辑:程序博客网 时间:2024/06/07 01:19

在前面 介绍android的init进程的时候,我们看到其中有如下代码

    mkdir("/dev", 0755);      mkdir("/proc", 0755);      mkdir("/sys", 0755);        mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");      mkdir("/dev/pts", 0755);      mkdir("/dev/socket", 0755);      mount("devpts", "/dev/pts", "devpts", 0, NULL);      mount("proc", "/proc", "proc", 0, NULL);      mount("sysfs", "/sys", "sysfs", 0, NULL);    

在挂载完根文件系统后/dev , /proc...一般都是有的,这里主要是进行了挂载,注意这里挂载了tmpfs到/dev目录下面

我们来看下mknod系统调用的实现

SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev){return sys_mknodat(AT_FDCWD, filename, mode, dev);}

直接调用sys_mknodat函数实现

SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,unsigned, dev){int error;char *tmp;struct dentry *dentry;struct nameidata nd;if (S_ISDIR(mode))return -EPERM;printk("filename = %s.\n", filename);printk("mode = 0x%x.\n", mode);error = user_path_parent(dfd, filename, &nd, &tmp);//查找路径中的最后一个项的父目录项if (error)return error;printk("before lookup_create.\n");dentry = lookup_create(&nd, 0);//创建需要创建的最后一项的目录项printk("after lookup_create.\n");if (IS_ERR(dentry)) {error = PTR_ERR(dentry);goto out_unlock;}if (!IS_POSIXACL(nd.path.dentry->d_inode))mode &= ~current_umask();error = may_mknod(mode);//进行模式检查if (error)goto out_dput;error = mnt_want_write(nd.path.mnt);if (error)goto out_dput;error = security_path_mknod(&nd.path, dentry, mode, dev);if (error)goto out_drop_write;switch (mode & S_IFMT) {case 0: case S_IFREG:printk("S_IFREG .\n");error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);break;case S_IFCHR: case S_IFBLK:printk("S_IFCHR: case S_IFBLK.\n");error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,new_decode_dev(dev));break;case S_IFIFO: case S_IFSOCK:printk("S_IFIFO: case S_IFSOCK.\n");error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);break;}out_drop_write:mnt_drop_write(nd.path.mnt);out_dput:dput(dentry);out_unlock:mutex_unlock(&nd.path.dentry->d_inode->i_mutex);path_put(&nd.path);putname(tmp);return error;}
这里首先查找要创建文件路径的最后一项的父目录的目录项,然后建立要创建文件的目录项最后根据相应的类型调用相应的vfs函数,以字符设备为例,这里会调用

case S_IFCHR: case S_IFBLK:printk("S_IFCHR: case S_IFBLK.\n");error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,new_decode_dev(dev));

跟踪vfs_mknod

int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev){int error = may_create(dir, dentry);printk(" vfs_mknod.\n");printk(" vfs_mknod.filesystem = %s.\n",dir->i_sb->s_type->name);if (error)return error;if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))return -EPERM;if (!dir->i_op->mknod)return -EPERM;error = devcgroup_inode_mknod(mode, dev);if (error)return error;error = security_inode_mknod(dir, dentry, mode, dev);if (error)return error;printk(" before dir->i_op->mknod.\n");error = dir->i_op->mknod(dir, dentry, mode, dev);//调用具体的mknod函数if (!error)fsnotify_create(dir, dentry);return error;}

在这里做一些检查之后,就调用相应文件系统的mknod函数了,前面我们知道/dev目录属于tmpfs文件系统,我们看在挂载tmpfs的时候,会调用它的get_sb函数

static struct file_system_type tmpfs_fs_type = {.owner= THIS_MODULE,.name= "tmpfs",.get_sb= shmem_get_sb,.kill_sb= kill_litter_super,};

这里对应shmem_get_sb

static int shmem_get_sb(struct file_system_type *fs_type,int flags, const char *dev_name, void *data, struct vfsmount *mnt){return get_sb_nodev(fs_type, flags, data, shmem_fill_super, mnt);}

对应的填充超级块的函数是shmem_fill_super

int shmem_fill_super(struct super_block *sb, void *data, int silent){struct inode *inode;struct dentry *root;struct shmem_sb_info *sbinfo;int err = -ENOMEM;/* Round up to L1_CACHE_BYTES to resist false sharing */sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),L1_CACHE_BYTES), GFP_KERNEL);if (!sbinfo)return -ENOMEM;sbinfo->mode = S_IRWXUGO | S_ISVTX;sbinfo->uid = current_fsuid();sbinfo->gid = current_fsgid();sb->s_fs_info = sbinfo;#ifdef CONFIG_TMPFS/* * Per default we only allow half of the physical ram per * tmpfs instance, limiting inodes to one per page of lowmem; * but the internal instance is left unlimited. */if (!(sb->s_flags & MS_NOUSER)) {sbinfo->max_blocks = shmem_default_max_blocks();sbinfo->max_inodes = shmem_default_max_inodes();if (shmem_parse_options(data, sbinfo, false)) {err = -EINVAL;goto failed;}}sb->s_export_op = &shmem_export_ops;#elsesb->s_flags |= MS_NOUSER;#endifspin_lock_init(&sbinfo->stat_lock);sbinfo->free_blocks = sbinfo->max_blocks;sbinfo->free_inodes = sbinfo->max_inodes;sb->s_maxbytes = SHMEM_MAX_BYTES;sb->s_blocksize = PAGE_CACHE_SIZE;sb->s_blocksize_bits = PAGE_CACHE_SHIFT;sb->s_magic = TMPFS_MAGIC;sb->s_op = &shmem_ops;sb->s_time_gran = 1;#ifdef CONFIG_TMPFS_POSIX_ACLsb->s_xattr = shmem_xattr_handlers;sb->s_flags |= MS_POSIXACL;#endifinode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);if (!inode)goto failed;inode->i_uid = sbinfo->uid;inode->i_gid = sbinfo->gid;root = d_alloc_root(inode);if (!root)goto failed_iput;sb->s_root = root;return 0;failed_iput:iput(inode);failed:shmem_put_super(sb);return err;}

再来看一下shmem_get_inode,对应填充它的inode节点

static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,     int 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 = new_inode(sb);if (inode) {inode_init_owner(inode, dir, mode);inode->i_blocks = 0;inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;inode->i_generation = get_seconds();info = SHMEM_I(inode);memset(info, 0, (char *)inode - (char *)info);spin_lock_init(&info->lock);info->flags = flags & VM_NORESERVE;INIT_LIST_HEAD(&info->swaplist);cache_no_acl(inode);switch (mode & S_IFMT) {default:inode->i_op = &shmem_special_inode_operations;init_special_inode(inode, mode, dev);break;case S_IFREG:inode->i_mapping->a_ops = &shmem_aops;inode->i_op = &shmem_inode_operations;inode->i_fop = &shmem_file_operations;mpol_shared_policy_init(&info->policy, shmem_get_sbmpol(sbinfo));break;case S_IFDIR:inc_nlink(inode);/* Some things misbehave if size == 0 on a directory */inode->i_size = 2 * BOGO_DIRENT_SIZE;inode->i_op = &shmem_dir_inode_operations;inode->i_fop = &simple_dir_operations;break;case S_IFLNK:/* * Must not load anything in the rbtree, * mpol_free_shared_policy will not be called. */mpol_shared_policy_init(&info->policy, NULL);break;}} elseshmem_free_inode(sb);return inode;}

当我们创建/dev目录时,这里对应

case S_IFDIR:inc_nlink(inode);/* Some things misbehave if size == 0 on a directory */inode->i_size = 2 * BOGO_DIRENT_SIZE;inode->i_op = &shmem_dir_inode_operations;inode->i_fop = &simple_dir_operations;break;

对应的i_op就是shmem_dir_inode_operations


原创粉丝点击