分享

文件系统--mknod系统调用

 joy_chen 2013-01-16

http://blog.csdn.net/new_abc/article/details/7694453


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

  1. mkdir("/dev", 0755);    
  2. mkdir("/proc", 0755);    
  3. mkdir("/sys", 0755);    
  4.   
  5. mount("tmpfs""/dev""tmpfs", 0, "mode=0755");    
  6. mkdir("/dev/pts", 0755);    
  7. mkdir("/dev/socket", 0755);    
  8. mount("devpts""/dev/pts""devpts", 0, NULL);    
  9. mount("proc""/proc""proc", 0, NULL);    
  10. mount("sysfs""/sys""sysfs", 0, NULL);    

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

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

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

直接调用sys_mknodat函数实现

  1. SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,  
  2.         unsigned, dev)  
  3. {  
  4.     int error;  
  5.     char *tmp;  
  6.     struct dentry *dentry;  
  7.     struct nameidata nd;  
  8.   
  9.     if (S_ISDIR(mode))  
  10.         return -EPERM;  
  11.     printk("filename = %s.\n", filename);  
  12.     printk("mode = 0x%x.\n", mode);  
  13.     error = user_path_parent(dfd, filename, &nd, &tmp);//查找路径中的最后一个项的父目录项  
  14.     if (error)  
  15.         return error;  
  16.     printk("before lookup_create.\n");  
  17.     dentry = lookup_create(&nd, 0);//创建需要创建的最后一项的目录项  
  18.     printk("lijj after lookup_create.\n");  
  19.     if (IS_ERR(dentry)) {  
  20.         error = PTR_ERR(dentry);  
  21.         goto out_unlock;  
  22.     }  
  23.     if (!IS_POSIXACL(nd.path.dentry->d_inode))  
  24.         mode &= ~current_umask();  
  25.     error = may_mknod(mode);//进行模式检查  
  26.     if (error)  
  27.         goto out_dput;  
  28.     error = mnt_want_write(nd.path.mnt);  
  29.     if (error)  
  30.         goto out_dput;  
  31.     error = security_path_mknod(&nd.path, dentry, mode, dev);  
  32.     if (error)  
  33.         goto out_drop_write;  
  34.     switch (mode & S_IFMT) {  
  35.         case 0: case S_IFREG:  
  36.             printk("lijj S_IFREG .\n");  
  37.             error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);  
  38.             break;  
  39.         case S_IFCHR: case S_IFBLK:  
  40.             printk("S_IFCHR: case S_IFBLK.\n");  
  41.             error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,  
  42.                     new_decode_dev(dev));  
  43.             break;  
  44.         case S_IFIFO: case S_IFSOCK:  
  45.             printk("S_IFIFO: case S_IFSOCK.\n");  
  46.             error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);  
  47.             break;  
  48.     }  
  49. out_drop_write:  
  50.     mnt_drop_write(nd.path.mnt);  
  51. out_dput:  
  52.     dput(dentry);  
  53. out_unlock:  
  54.     mutex_unlock(&nd.path.dentry->d_inode->i_mutex);  
  55.     path_put(&nd.path);  
  56.     putname(tmp);  
  57.   
  58.     return error;  
  59. }  
这里首先查找要创建文件路径的最后一项的父目录的目录项,然后建立要创建文件的目录项最后根据相应的类型调用相应的vfs函数,以字符设备为例,这里会调用

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

跟踪vfs_mknod

  1. int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)  
  2. {  
  3.     int error = may_create(dir, dentry);  
  4.     printk(" vfs_mknod.\n");  
  5.     printk(" vfs_mknod.filesystem = %s.\n",dir->i_sb->s_type->name);  
  6.     if (error)  
  7.         return error;  
  8.   
  9.     if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))  
  10.         return -EPERM;  
  11.   
  12.     if (!dir->i_op->mknod)  
  13.         return -EPERM;  
  14.   
  15.     error = devcgroup_inode_mknod(mode, dev);  
  16.     if (error)  
  17.         return error;  
  18.   
  19.     error = security_inode_mknod(dir, dentry, mode, dev);  
  20.     if (error)  
  21.         return error;  
  22.     printk(" before dir->i_op->mknod.\n");  
  23.     error = dir->i_op->mknod(dir, dentry, mode, dev);//调用具体的mknod函数  
  24.     if (!error)  
  25.         fsnotify_create(dir, dentry);  
  26.     return error;  
  27. }  

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

  1. static struct file_system_type tmpfs_fs_type = {  
  2.     .owner      = THIS_MODULE,  
  3.     .name       = "tmpfs",  
  4.     .get_sb     = shmem_get_sb,  
  5.     .kill_sb    = kill_litter_super,  
  6. };  

这里对应shmem_get_sb

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

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

  1. int shmem_fill_super(struct super_block *sb, void *data, int silent)  
  2. {  
  3.     struct inode *inode;  
  4.     struct dentry *root;  
  5.     struct shmem_sb_info *sbinfo;  
  6.     int err = -ENOMEM;  
  7.   
  8.     /* Round up to L1_CACHE_BYTES to resist false sharing */  
  9.     sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),  
  10.                 L1_CACHE_BYTES), GFP_KERNEL);  
  11.     if (!sbinfo)  
  12.         return -ENOMEM;  
  13.   
  14.     sbinfo->mode = S_IRWXUGO | S_ISVTX;  
  15.     sbinfo->uid = current_fsuid();  
  16.     sbinfo->gid = current_fsgid();  
  17.     sb->s_fs_info = sbinfo;  
  18.   
  19. #ifdef CONFIG_TMPFS  
  20.     /* 
  21.      * Per default we only allow half of the physical ram per 
  22.      * tmpfs instance, limiting inodes to one per page of lowmem; 
  23.      * but the internal instance is left unlimited. 
  24.      */  
  25.     if (!(sb->s_flags & MS_NOUSER)) {  
  26.         sbinfo->max_blocks = shmem_default_max_blocks();  
  27.         sbinfo->max_inodes = shmem_default_max_inodes();  
  28.         if (shmem_parse_options(data, sbinfo, false)) {  
  29.             err = -EINVAL;  
  30.             goto failed;  
  31.         }  
  32.     }  
  33.     sb->s_export_op = &shmem_export_ops;  
  34. #else  
  35.     sb->s_flags |= MS_NOUSER;  
  36. #endif  
  37.   
  38.     spin_lock_init(&sbinfo->stat_lock);  
  39.     sbinfo->free_blocks = sbinfo->max_blocks;  
  40.     sbinfo->free_inodes = sbinfo->max_inodes;  
  41.   
  42.     sb->s_maxbytes = SHMEM_MAX_BYTES;  
  43.     sb->s_blocksize = PAGE_CACHE_SIZE;  
  44.     sb->s_blocksize_bits = PAGE_CACHE_SHIFT;  
  45.     sb->s_magic = TMPFS_MAGIC;  
  46.     sb->s_op = &shmem_ops;  
  47.     sb->s_time_gran = 1;  
  48. #ifdef CONFIG_TMPFS_POSIX_ACL  
  49.     sb->s_xattr = shmem_xattr_handlers;  
  50.     sb->s_flags |= MS_POSIXACL;  
  51. #endif  
  52.   
  53.     inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);  
  54.     if (!inode)  
  55.         goto failed;  
  56.     inode->i_uid = sbinfo->uid;  
  57.     inode->i_gid = sbinfo->gid;  
  58.     root = d_alloc_root(inode);  
  59.     if (!root)  
  60.         goto failed_iput;  
  61.     sb->s_root = root;  
  62.     return 0;  
  63.   
  64. failed_iput:  
  65.     iput(inode);  
  66. failed:  
  67.     shmem_put_super(sb);  
  68.     return err;  
  69. }  

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

  1. static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,  
  2.                      int mode, dev_t dev, unsigned long flags)  
  3. {  
  4.     struct inode *inode;  
  5.     struct shmem_inode_info *info;  
  6.     struct shmem_sb_info *sbinfo = SHMEM_SB(sb);  
  7.   
  8.     if (shmem_reserve_inode(sb))  
  9.         return NULL;  
  10.   
  11.     inode = new_inode(sb);  
  12.     if (inode) {  
  13.         inode_init_owner(inode, dir, mode);  
  14.         inode->i_blocks = 0;  
  15.         inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;  
  16.         inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;  
  17.         inode->i_generation = get_seconds();  
  18.         info = SHMEM_I(inode);  
  19.         memset(info, 0, (char *)inode - (char *)info);  
  20.         spin_lock_init(&info->lock);  
  21.         info->flags = flags & VM_NORESERVE;  
  22.         INIT_LIST_HEAD(&info->swaplist);  
  23.         cache_no_acl(inode);  
  24.   
  25.         switch (mode & S_IFMT) {  
  26.         default:  
  27.             inode->i_op = &shmem_special_inode_operations;  
  28.             init_special_inode(inode, mode, dev);  
  29.             break;  
  30.         case S_IFREG:  
  31.             inode->i_mapping->a_ops = &shmem_aops;  
  32.             inode->i_op = &shmem_inode_operations;  
  33.             inode->i_fop = &shmem_file_operations;  
  34.             mpol_shared_policy_init(&info->policy,  
  35.                          shmem_get_sbmpol(sbinfo));  
  36.             break;  
  37.         case S_IFDIR:  
  38.             inc_nlink(inode);  
  39.             /* Some things misbehave if size == 0 on a directory */  
  40.             inode->i_size = 2 * BOGO_DIRENT_SIZE;  
  41.             inode->i_op = &shmem_dir_inode_operations;  
  42.             inode->i_fop = &simple_dir_operations;  
  43.             break;  
  44.         case S_IFLNK:  
  45.             /* 
  46.              * Must not load anything in the rbtree, 
  47.              * mpol_free_shared_policy will not be called. 
  48.              */  
  49.             mpol_shared_policy_init(&info->policy, NULL);  
  50.             break;  
  51.         }  
  52.     } else  
  53.         shmem_free_inode(sb);  
  54.     return inode;  
  55. }  

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

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

对应的i_op就是shmem_dir_inode_operations


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多