Linux最简单的文件系统aufs剖析详解

对于一个普通的编程小白来说,文件系统无非就是几个功能,创建文件,创建目录,打开文件和文件读写。对于通常的硬盘文件系统来说,这要涉及硬盘的读写和硬盘空间管理,而读写从文件系统一直到通用块设备再到硬盘驱动。我们这些就剖析最简单的文件系统,深入内核。
aufs文件系统源代码

#include  
#include  
#include  
#include  
#include  
#include  

#define AUFS_MAGIC  0x64668735  

static struct vfsmount *aufs_mount;  
static int aufs_mount_count;  

static struct inode *aufs_get_inode(struct super_block *sb, int mode, dev_t dev)  
{  
  struct inode *inode = new_inode(sb);  

  if (inode) {  
       inode->i_mode = mode;  
       inode->i_uid = current->fsuid;  
       inode->i_gid = current->fsgid;  
       inode->i_blksize = PAGE_CACHE_SIZE;  
       inode->i_blocks = 0;  
       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;  
       switch (mode & S_IFMT) {  
       default:  
           init_special_inode(inode, mode, dev);  
           break;  
       case S_IFREG:  
           printk("creat a  file \n");  
           break;  
       case S_IFDIR:  
           inode->i_op = &simple_dir_inode_operations;  
           inode->i_fop = &simple_dir_operations;  
           printk("creat a dir file \n");  

           inode->i_nlink++;  
           break;  
       }  
  }  
  return inode;  
}  
/* SMP-safe  创建iNode的函数 */  
static int aufs_mknod(struct inode *dir, struct dentry *dentry,  
           int mode, dev_t dev)  
{  
  struct inode *inode;  
  int error = -EPERM;  
 /* 判断inode是否存在 如果存在就返回退出函数 */
  if (dentry->d_inode)  
       return -EEXIST;  
 /* 如果inode不存在就调用aufs_get_inode函数创建inode */
  inode = aufs_get_inode(dir->i_sb, mode, dev);  
  if (inode) {  
  /*  */
       d_instantiate(dentry, inode);  
       dget(dentry);  
       error = 0;  
  }  
  return error;  
}  

static int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)  
{  
  int res;  
 /* 参数S_IFDIR表示创建一个目录文件的inode */
  res = aufs_mknod(dir, dentry, mode |S_IFDIR, 0);  
  if (!res)  
       dir->i_nlink++;  
  return res;  
}  

static int aufs_create(struct inode *dir, struct dentry *dentry, int mode)  
{  
  return aufs_mknod(dir, dentry, mode | S_IFREG, 0);  
}  

static int aufs_fill_super(struct super_block *sb, void *data, int silent)  
{  
  static struct tree_descr debug_files[] = {{""}};  

  return simple_fill_super(sb, AUFS_MAGIC, debug_files);  
}  

static struct super_block *aufs_get_sb(struct file_system_type *fs_type,  
                int flags, const char *dev_name,  
                void *data)  
{  
  return get_sb_single(fs_type, flags, data, aufs_fill_super);  
}  

static struct file_system_type au_fs_type = {  
  .owner =    THIS_MODULE,  
  .name =     "aufs",  
  .get_sb =   aufs_get_sb,  
  .kill_sb =  kill_litter_super,  
};  

 /* 创建文件的inode和dentry结构 */
static int aufs_create_by_name(const char *name, mode_t mode,  
                 struct dentry *parent,  
                 struct dentry **dentry)  
{  
  int error = 0;  

  /* If the parent is not specified, we create it in the root.  
   * We need the root dentry to do this, which is in the super  
   * block. A pointer to that is in the struct vfsmount that we  
   * have around.  
   */  
   /* 判断是否有父目录 没有就赋予文件系统的根dentry */
  if (!parent ) {  
       if (aufs_mount && aufs_mount->mnt_sb) {  
           parent = aufs_mount->mnt_sb->s_root;  
       }  
  }  
  if (!parent) {  
       printk("Ah! can not find a parent!\n");  
       return -EFAULT;  
  }  

  *dentry = NULL;  
  /* 原子锁  */
  mutex_lock(&parent->d_inode->i_mutex);  

  /* 调用lookup_one_len:首先在父目录下根据名字查找dentry结构 如果存在就返回指针 不存在就创建一个dentry */
  *dentry = lookup_one_len(name, parent, strlen(name));  
  if (!IS_ERR(dentry)) {  
       if ((mode & S_IFMT) == S_IFDIR)  
        /* 这里表示创建一个目录文件的inode */
            error = aufs_mkdir(parent->d_inode, *dentry, mode);  
       else  
       /* 创建一个文件的inode */
            error = aufs_create(parent->d_inode, *dentry, mode);  
  } else  
       error = PTR_ERR(dentry);  
  mutex_unlock(&parent->d_inode->i_mutex);  

  return error;  
}  

/* 创建一个文件 文件是用dentry和inode代表的 这里是创建dentry和inode */
struct dentry *aufs_create_file(const char *name, mode_t mode,  
                  struct dentry *parent, void *data,  
                  struct file_operations *fops)  
{  
  struct dentry *dentry = NULL;  
  int error;  

  printk("aufs: creating file '%s'\n",name);  

  error = aufs_create_by_name(name, mode, parent, &dentry);  
  if (error) {  
       dentry = NULL;  
       goto exit;  
  }  
  if (dentry->d_inode) {  
       if (data)  
            dentry->d_inode->u.generic_ip = data;  
       if (fops)  
            dentry->d_inode->i_fop = fops;  
  }  
exit:  
  return dentry;  
}  

 /* 目录创建 linux中目录也是文件 所以调用aufs_create_file创建文件 传入参数S_IFDIR指明创建的是一个目录 */
struct dentry *aufs_create_dir(const char *name, struct dentry *parent)  
{  
  return aufs_create_file(name,  
                  S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,  
                  parent, NULL, NULL);  
}  

static int __init aufs_init(void)  
{  
  int retval;  
       struct dentry *pslot;  

 /* 将文件系统登记到系统 */
  retval = register_filesystem(&au_fs_type);  

  if (!retval) {  
/* 创建super_block 根dentry 根inode */
       aufs_mount = kern_mount(&au_fs_type);
/* kern_mount错误就卸载文件系统 */
       if (IS_ERR(aufs_mount)) {  
           printk(KERN_ERR "aufs: could not mount!\n");  
           unregister_filesystem(&au_fs_type);  
           return retval;  
       }  
  }  
/* 创建目录和目录下的几个文件 */
  pslot = aufs_create_dir("woman star",NULL);  
  aufs_create_file("lbb", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("fbb", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("ljl", S_IFREG | S_IRUGO, pslot, NULL, NULL);  

  pslot = aufs_create_dir("man star",NULL);  
  aufs_create_file("ldh", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("lcw", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("jw", S_IFREG | S_IRUGO, pslot, NULL, NULL);  

  return retval;  
}  
static void __exit aufs_exit(void)  
{  
/* 退出函数中卸载super_block 根dentry 根inode */
  simple_release_fs(&aufs_mount, &aufs_mount_count);  
  /* 卸载文件系统 */
  unregister_filesystem(&au_fs_type);  
}  
 /* 模块入口出口函数声明 和模块声明 */
module_init(aufs_init);  
module_exit(aufs_exit);  
MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("This is a simple module");  
MODULE_VERSION("Ver 0.1"); 

对于没了解过linux模块概念的话 这里可以稍微讲解 这里可以用百度的官方解释
Linux内核模块:尽管Linux是”单块内核“(monolithic)的操作系统–这是说整个系统内核都运行于一个单独的保护域中,但是linux内核是模块化组成的,它允许内核在运行时动态地向其中插入或从中删除代码。这些代码(包括相关的子线程、数据、函数入口和函数出口)被一并组合在一个单独的二进制镜像中,即所谓的可装载内核模块中,或简称为模块。支持模块的好处是基本内核镜像尽可能的小,因为可选的功能和驱动程序可以利用模块形式再提供。模块允许我们方便地删除和重新载入内核代码,也方便了调试工作。而且当热插拔新设备时,可通过命令载入新的驱动程序。
上文解释的比较全面,简单而言就是我们可以通过insmod命令向内核添加模块 和使用rmmod删除模块

所以aufs也是用这种方法向内核insmod这个文件系统
Linux模块中有两个关键的函数 就是入口和出口函数
对于分析一个驱动代码或者其他模块 我们不是一上来就是愣头青的从头分析代码 而是从模块的入口函数看起

/* 入口函数 */
static int __init aufs_init(void)  
{  
  int retval;  
       struct dentry *pslot;  

 /* 将文件系统登记到系统 */
  retval = register_filesystem(&au_fs_type);  

  if (!retval) {  
/* 创建super_block 根dentry 根inode */
       aufs_mount = kern_mount(&au_fs_type);
/* kern_mount错误就卸载文件系统 */
       if (IS_ERR(aufs_mount)) {  
           printk(KERN_ERR "aufs: could not mount!\n");  
           unregister_filesystem(&au_fs_type);  
           return retval;  
       }  
  }  
/* 创建目录和目录下的几个文件 */
  pslot = aufs_create_dir("woman star",NULL);  
  aufs_create_file("lbb", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("fbb", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("ljl", S_IFREG | S_IRUGO, pslot, NULL, NULL);  

  pslot = aufs_create_dir("man star",NULL);  
  aufs_create_file("ldh", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("lcw", S_IFREG | S_IRUGO, pslot, NULL, NULL);  
  aufs_create_file("jw", S_IFREG | S_IRUGO, pslot, NULL, NULL);  

  return retval;  
}  
static void __exit aufs_exit(void)  
{  
/* 退出函数中卸载super_block 根dentry 根inode */
  simple_release_fs(&aufs_mount, &aufs_mount_count);  
  /* 卸载文件系统 */
  unregister_filesystem(&au_fs_type);  
}  
 /* 模块入口出口函数声明 和模块Licence 描述 版本说明 */
module_init(aufs_init);  
module_exit(aufs_exit);  
MODULE_LICENSE("GPL");
/* 以上三个声明为必须 下面两个声明可有可无 */  
MODULE_DESCRIPTION("This is a simple module");  
MODULE_VERSION("Ver 0.1"); 

分析aufs的入口函数
从代码可知 入口函数就主要就调用了register_filesystemkern_mount函数进行文件系统的创建 然后就是用函数aufs_create_diraufs_create_file创建目录和文件 入口函数就干了这几件事 那我们来分析这两个函数 看看内核是怎么创建一个文件系统的
register_filesystem函数实现代码

int register_filesystem(struct file_system_type * fs)
{
    int res = 0;
    struct file_system_type ** p;

    BUG_ON(strchr(fs->name, '.'));
    /* 检查文件系统的链表节点是否存在 */
    if (fs->next)
        return -EBUSY;
    INIT_LIST_HEAD(&fs->fs_supers);
    write_lock(&file_systems_lock);
    /* 查找同名的文件系统 */
    p = find_filesystem(fs->name, strlen(fs->name));
    if (*p)
    /* 存在则返回忙 */
        res = -EBUSY;
    else
    /* 不存在则加入文件系统链表 */
        *p = fs;
    write_unlock(&file_systems_lock);
    return res;
}

这个文件系统代码中先定义了file_system_type结构体 这个结构体是用来描述文件系统的 结构体代码如下
在这个文件系统中 我们只用到了其中的四个变量 所以我们只对着四个变量分析

struct file_system_type {
    /* 文件系统名字 */
    const char *name;
    int fs_flags;
    /* 获得超级块superblock的函数 */
    int (*get_sb) (struct file_system_type *, int,
               const char *, void *, struct vfsmount *);
    /* 销毁超级块superblock的函数 */
    void (*kill_sb) (struct super_block *);
    struct module *owner;
    struct file_system_type * next;
    struct list_head fs_supers;
    struct lock_class_key s_lock_key;
    struct lock_class_key s_umount_key;
    }

register_filesystem的函数参数为struct file_system_type * fs 意即传入一个file_system_type结构体指针 而这个结构体包含有这个文件系统的一些信息 比如获取超级块的函数,名字之类。
register_filesystem先检查文件系统的链表节点是否存在 然后寻找相同名字的文件系统 如果不存在相
同名字的文件系统,就把文件系统加入到系统的文件系统链表。如果已存在则返回忙 内核定义
了一个全局变量file_systems,用来保存所有登记的文件系统,find_filesystem就是利用了这个
全局变量file_systems执行了具体的查找过程
从register_filesystem的代码得知 register_filesystem函数并未创建超级块对象和vfsmount对象 而只是将文件系统登记入系统 所以主要的功能还是要在kern_mount里实现
kern_mount 函数实现代码

struct vfsmount *kern_mount(struct file_system_type *type)
{
    return vfs_kern_mount(type, 0, type->name, NULL);
}

可以看出kern_mount只是vfs_kern_mount的封装
vfs_kern_mount 函数实现代码

struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
    struct vfsmount *mnt;
    char *secdata = NULL;
    int error;
    /* type不存在 就返回错误 */
    if (!type)
        return ERR_PTR(-ENODEV);

    error = -ENOMEM;

    /* 根据文件系统的名字为文件系统创建一个vfsmount结构 */
    mnt = alloc_vfsmnt(name);
    /* mount有数据 则继续实行 否则goto退出 */
    if (!mnt)
        goto out;
    /* 传进来的data为NULL 不执行 */
    if (data) {
        secdata = alloc_secdata();
        if (!secdata)
            goto out_mnt;
    /* 安全相关代码 */
        error = security_sb_copy_data(type, data, secdata);
        if (error)
            goto out_free_secdata;
    }

    /* 调用file_system_type结构体里的get_sb创建一个超级块对象super_block 
     * 并且创建一个dentey结构作为文件系统的根dentry和一个inode作为文件系统的根inode
     */
    error = type->get_sb(type, flags, name, data, mnt);
    if (error < 0)
        goto out_free_secdata;

    /* 安全相关代码 */
    error = security_sb_kern_mount(mnt->mnt_sb, secdata);
    if (error)
        goto out_sb;

    /* mnt数据在申请的时候被赋予空值 */
    /* mnt_mountpoint为根dentry */
    mnt->mnt_mountpoint = mnt->mnt_root;

    /* vfsmount结构的父指针为本身 */
    /* 如果把文件系统mount到其他系统 就得把这两个参数设置为源文件系统 */
    mnt->mnt_parent = mnt;
    up_write(&mnt->mnt_sb->s_umount);
    free_secdata(secdata);
    return mnt;
out_sb:
    dput(mnt->mnt_root);
    up_write(&mnt->mnt_sb->s_umount);
    deactivate_super(mnt->mnt_sb);
out_free_secdata:
    free_secdata(secdata);
out_mnt:
    free_vfsmnt(mnt);
out:
    return ERR_PTR(error);
}

根据以上代码可知vfs_kern_mount调用了alloc_vfsmnt 函数和调用file_system_type结构体里的get_sb创建一个超级块对象super_block 并且创建一个dentey结构作为文件系统的根dentry和一个inode作为文件系统的根inode
这里使用的是函数aufs_get_sb来获取超级块对象
aufs_get_sb函数实现代码如下

static struct super_block *aufs_get_sb(struct file_system_type *fs_type,  
                int flags, const char *dev_name,  
                void *data)  
{  
  return get_sb_single(fs_type, flags, data, aufs_fill_super);  
}  

aufs_get_sb是get_sb_single的封装函数

int get_sb_single(struct file_system_type *fs_type,
    int flags, void *data,
    int (*fill_super)(struct super_block *, void *, int),
    struct vfsmount *mnt)
{
    struct super_block *s;
    int error;

    /* 获取一个超级块对象 */
    s = sget(fs_type, compare_single, set_anon_super, NULL);

    /* 如果文件系统的超级块对象已经存在 返回对象指针 */
    if (IS_ERR(s))
        return PTR_ERR(s);

    /* 如果超级块对象的根dentry不存在 则调用穿进来的函数指针fill_super为超级块对象赋值给根dentry和根inode */   
    if (!s->s_root) {
        s->s_flags = flags;
        error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
            up_write(&s->s_umount);
            deactivate_super(s);
            return error;
        }
        s->s_flags |= MS_ACTIVE;
    }
    do_remount_sb(s, flags, data, 0);
    /* 把创建的超级块对象赋值给vfsmount结构所指的超级块同时vfsmount所指的mnt_root点赋值给超级块所指的根dentry
     *于是从vfsmount结构就可以获得文件系统的超级块对象和根dentry 
     */
    return simple_set_mnt(mnt, s);
}

从代码可知get_sb_single函数使用sget函数来获得一个超级块对象 并且调用fill_super为超级块对象填充根dentry和根inode。
在这aufs文件系统里 fill_super就是aufs_fill_super函数
aufs_fill_super函数实现代码如下

static int aufs_fill_super(struct super_block *sb, void *data, int silent)  
{  
/* 定义空的tree_descr结构体 作用是描述一些文件 如果不为空,填充超级块的同时需要在根目录下创建一些文件,当前为空,说明不需要创建任何文件 */
  static struct tree_descr debug_files[] = {{""}};  
 /* 调用simple_fill_super函数填充根dentry和根inode */
  return simple_fill_super(sb, AUFS_MAGIC, debug_files);  
}  

simple_fill_super函数实现代码如下

int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files)
{
    static const struct super_operations simple_super_operations ={.statfs  = simple_statfs,};
    struct inode *inode;
    struct dentry *root;
    struct dentry *dentry;
    int i;
    /* 对超级块对象对象赋值 */
    /* 文件系统块大小 */
    s->s_blocksize = PAGE_CACHE_SIZE;
    /* 块大小的位 */
    s->s_blocksize_bits = PAGE_CACHE_SHIFT;
    s->s_magic = magic;
    /* 为超级对象赋予操作函数simple_statfs  */
    s->s_op = &simple_super_operations;
    s->s_time_gran = 1;

    /* 创建一个根inode结构 */
    inode = new_inode(s);
    if (!inode)
        return -ENOMEM;
    /*
     * because the root inode is 1, the files array must not contain an
     * entry at index 1
     */
     /* inode结构体赋值 */
    inode->i_ino = 1;
    /* 设置文件的类型和访问权限 */
    inode->i_mode = S_IFDIR | 0755;
    /* 设置组id和用户id */
    inode->i_uid = inode->i_gid = 0;
    /* 设置文件所占块数 */
    inode->i_blocks = 0;
    /* 设置文件的修改访问之间之类 */
    inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
    /* 设置操作函数 */
    inode->i_op = &simple_dir_inode_operations;
    inode->i_fop = &simple_dir_operations;
    inode->i_nlink = 2;

    /* 创建一个根dentry 根dentry的父结构是自身,它指向的超级块对象就是文件系统的超级块对象  */
    root = d_alloc_root(inode);
    if (!root) {
        iput(inode);
        return -ENOMEM;
    }

    /* 创建一系列的文件 并且设置inode */
    for (i = 0; !files->name || files->name[0]; i++, files++) {
        if (!files->name)
            continue;

        /* warn if it tries to conflict with the root inode */
        if (unlikely(i == 1))
            printk(KERN_WARNING "%s: %s passed in a files array"
                "with an index of 1!\n", __func__,
                s->s_type->name);

        dentry = d_alloc_name(root, files->name);
        if (!dentry)
            goto out;
        inode = new_inode(s);
        if (!inode)
            goto out;
        inode->i_mode = S_IFREG | files->mode;
        inode->i_uid = inode->i_gid = 0;
        inode->i_blocks = 0;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        inode->i_fop = files->ops;
        inode->i_ino = i;
        d_add(dentry, inode);
    }
    s->s_root = root;
    return 0;
out:
    d_genocide(root);
    dput(root);
    return -ENOMEM;
}

从上代码可知 创建了根dentry和根inode

所以register_filesystem和kern_mount所做的事就是将文件系统登记到系统并且创建super_block 根dentry 根inode。那么我们后面创建的文件和目录都应该链接到这个根dentry

然后就是aufs创建目录和文件的过程
aufs_create_dir函数实现代码如下

 /* 目录创建 linux中目录也是文件 所以调用aufs_create_file创建文件 传入参数S_IFDIR指明创建的是一个目录 */
struct dentry *aufs_create_dir(const char *name, struct dentry *parent)  
{  
  return aufs_create_file(name,  
                  S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,  
                  parent, NULL, NULL);  
}  

aufs_create_file函数实现代码如下

/* 创建一个文件 文件是用dentry和inode代表的 这里是创建dentry和inode */
struct dentry *aufs_create_file(const char *name, mode_t mode,  
                  struct dentry *parent, void *data,  
                  struct file_operations *fops)  
{  
  struct dentry *dentry = NULL;  
  int error;  

  printk("aufs: creating file '%s'\n",name);  

  error = aufs_create_by_name(name, mode, parent, &dentry);  
  if (error) {  
       dentry = NULL;  
       goto exit;  
  }  
  if (dentry->d_inode) {  
       if (data)  
            dentry->d_inode->u.generic_ip = data;  
       if (fops)  
            dentry->d_inode->i_fop = fops;  
  }  
exit:  
  return dentry;  
}  

上述代码主要就是调用了aufs_create_by_name创建文件的dentry和inode结构
aufs_create_by_name函数实现代码如下

 /* 创建文件的inode和dentry结构 */
static int aufs_create_by_name(const char *name, mode_t mode,  
                 struct dentry *parent,  
                 struct dentry **dentry)  
{  
  int error = 0;  

  /* If the parent is not specified, we create it in the root.  
   * We need the root dentry to do this, which is in the super  
   * block. A pointer to that is in the struct vfsmount that we  
   * have around.  
   */  
   /* 判断是否有父目录 没有就赋予文件系统的根dentry */
  if (!parent ) {  
       if (aufs_mount && aufs_mount->mnt_sb) {  
           parent = aufs_mount->mnt_sb->s_root;  
       }  
  }  
  if (!parent) {  
       printk("Ah! can not find a parent!\n");  
       return -EFAULT;  
  }  

  *dentry = NULL;  
  /* 原子锁  */
  mutex_lock(&parent->d_inode->i_mutex);  

  /* 调用lookup_one_len:首先在父目录下根据名字查找dentry结构 如果存在就返回指针 不存在就创建一个dentry */
  *dentry = lookup_one_len(name, parent, strlen(name));  
  if (!IS_ERR(dentry)) {  
       if ((mode & S_IFMT) == S_IFDIR)  
        /* 这里表示创建一个目录文件的inode */
            error = aufs_mkdir(parent->d_inode, *dentry, mode);  
       else  
       /* 创建一个文件的inode */
            error = aufs_create(parent->d_inode, *dentry, mode);  
  } else  
       error = PTR_ERR(dentry);  
  mutex_unlock(&parent->d_inode->i_mutex);  

  return error;  
}  

aufs_create_by_name函数的主要功能就是调用lookup_one_len函数根据名字查找dentry结构 存在就返回 不存在就创建一个 反正最后都是要得到一个dentry结构,和调用aufs_mkdir或者aufs_create创建inode结构

lookup_one_len函数实现代码如下

struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
{
    int err;
    struct qstr this;

    err = __lookup_one_len(name, &this, base, len);
    if (err)
        return ERR_PTR(err);
    /* 通过hash值查找同名字的dentry */
    return __lookup_hash(&this, base, NULL);
}

__lookup_one_len函数实现代码如下

static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
{
    unsigned long hash;
    unsigned int c;

    this->name = name;
    this->len = len;
    if (!len)
        return -EACCES;

    /* 根据名字计算hash值,看看是怎么计算的  */
    hash = init_name_hash();
    while (len--) {
        c = *(const unsigned char *)name++;
        if (c == '/' || c == '\0')
            return -EACCES;
        hash = partial_name_hash(c, hash);
    }
    this->hash = end_name_hash(hash);
    return 0;
}

浏览上面两个函数的代码可知 查找同名的dentry就是计算dentry名字的hash值 然后调用__lookup_hash来根据上述算出的hash值来找到同名的dentry结构

__lookup_hash函数实现代码如下

static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
{
    struct dentry *dentry;
    struct inode *inode;
    int err;

    inode = base->d_inode;
    /* 检查inode的权限 */
    err = permission(inode, MAY_EXEC, nd);
    dentry = ERR_PTR(err);
    if (err)
        goto out;

    dentry = __lookup_hash_kern(name, base, nd);
out:
    return dentry;
}

__lookup_hash是先检查inode的权限 然后调用__lookup_hash_kern函数来根据hash值获得同名的dentry结构
__lookup_hash_kern函数实现代码如下

static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
{
    struct dentry *dentry;
    struct inode *inode;
    int err;

    inode = base->d_inode;

    /*
     * See if the low-level filesystem might want
     * to use its own hash..
     */
     /* 查找文件系统是否提供了特有的hash函数d_hash 如果有就调用重新计算hash值 */
    if (base->d_op && base->d_op->d_hash) {
        err = base->d_op->d_hash(base, name);
        dentry = ERR_PTR(err);
        if (err < 0)
            goto out;
    }
    /* 在dentry cache里查找同名的dentry结构 如果返回为空 说明不存在同名的dentry结构 就调用d_alloc创建dentry结构 */
    dentry = cached_lookup(base, name, nd);
    if (!dentry) {
        struct dentry *new = d_alloc(base, name);
        dentry = ERR_PTR(-ENOMEM);
        if (!new)
            goto out;
    /* 创建dentry结构完成后 得再次调用文件系统的lookup查找是否有同名的dentry存在,防止同名的dentry已经被其他用户提前创建了 */
        dentry = inode->i_op->lookup(inode, new, nd);
        if (!dentry)
            dentry = new;
        else
            dput(new);
    }
out:
    return dentry;
}

cached_lookup函数实现代码如下

/* 使用了两次lookup 防止并发的d_move操作 */
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
{
    struct dentry * dentry = __d_lookup(parent, name);

    /* lockess __d_lookup may fail due to concurrent d_move() 
     * in some unrelated directory, so try with d_lookup
     */
    if (!dentry)
        dentry = d_lookup(parent, name);

    if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
        dentry = do_revalidate(dentry, nd);

    return dentry;
}

__d_lookup 函数代码如下

struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
{
    unsigned int len = name->len;
    unsigned int hash = name->hash;
    const unsigned char *str = name->name;
    /* 根据parent和hash值计算最终的hash值 从数组dentry_hashtable中获得hash链表的链表头 
     * 内核中的dentry结构都根据hash值链接到众多的hash链表中,这些hash链表的头结构保存在dentry_hashtable中
     */
    struct hlist_head *head = d_hash(parent,hash);
    struct dentry *found = NULL;
    struct hlist_node *node;
    struct dentry *dentry;

    rcu_read_lock();

    /* 获得链表头后 遍历hash链表 寻找匹配的dentry结构 */
    hlist_for_each_entry_rcu(dentry, node, head, d_hash) {
        struct qstr *qstr;

        if (dentry->d_name.hash != hash)
            continue;
        if (dentry->d_parent != parent)
            continue;

        spin_lock(&dentry->d_lock);

        /*
         * Recheck the dentry after taking the lock - d_move may have
         * changed things.  Don't bother checking the hash because we're
         * about to compare the whole name anyway.
         */
        if (dentry->d_parent != parent)
            goto next;

        /*
         * It is safe to compare names since d_move() cannot
         * change the qstr (protected by d_lock).
         */
        qstr = &dentry->d_name;
        /* 如果文件系统定义了d_compare就调用  */
        if (parent->d_op && parent->d_op->d_compare) {
            if (parent->d_op->d_compare(parent, qstr, name))
                goto next;
        } else {
            /* 判断长度是否相同 */
            if (qstr->len != len)
                goto next;
            /* 比较目录名字是否相同 */
            if (memcmp(qstr->name, str, len))
                goto next;
        }

        if (!d_unhashed(dentry)) {
            atomic_inc(&dentry->d_count);
            found = dentry;
        }
        spin_unlock(&dentry->d_lock);
        break;
next:
        spin_unlock(&dentry->d_lock);
    }
    rcu_read_unlock();

    return found;
}

兜了一整圈就是
aufs_create_dir->aufs_create_file->aufs_create_by_name:查找或者创建dentry和inode结构->lookup_one_len:计算hash值->__lookup_one_len**dentry->**__lookup_one_len:根据hash值查找->__lookup_hash->__lookup_hash_kern:根据hash值查找 知道同名就返回 找不到就创建

上面分析了寻找dentry结构相关代码 下面就解析下创建inode的代码
目录inode创建函数
aufs_mkdir函数实现代码如下

static int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)  
{  
  int res;  
 /* 参数S_IFDIR表示创建一个目录文件的inode */
  res = aufs_mknod(dir, dentry, mode |S_IFDIR, 0);  
  if (!res)  
       dir->i_nlink++;  
  return res;  
}  

aufs_mknod函数实现代码如下

/* SMP-safe  创建iNode的函数 */  
static int aufs_mknod(struct inode *dir, struct dentry *dentry,  
           int mode, dev_t dev)  
{  
  struct inode *inode;  
  int error = -EPERM;  
 /* 判断inode是否存在 如果存在就返回退出函数 */
  if (dentry->d_inode)  
       return -EEXIST;  
 /* 如果inode不存在就调用aufs_get_inode函数创建inode */
  inode = aufs_get_inode(dir->i_sb, mode, dev);  
  if (inode) {  
  /* 把dentry加入到inode的dentry链表头 */
       d_instantiate(dentry, inode);  
       dget(dentry);  
       error = 0;  
  }  
  return error;  
}  

aufs_get_inode函数实现代码如下

static struct inode *aufs_get_inode(struct super_block *sb, int mode, dev_t dev)  
{  
/* 申请一个inode结构 */
  struct inode *inode = new_inode(sb);  
 /* inode结构体成员的赋值 */
 /* current是内核定义的一个宏,它的作用是获得当前进程的结构指针 */
  if (inode) {  
       inode->i_mode = mode;  
       inode->i_uid = current->fsuid;  
       inode->i_gid = current->fsgid;  
       inode->i_blksize = PAGE_CACHE_SIZE;  
       inode->i_blocks = 0;  
       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;  
       /* 根据inode的类型 设置不同的操作函数 */
       switch (mode & S_IFMT) {  
       default:  
           /* 块设备文件或者字符设备文件 调用init_special_inode赋值 */
           init_special_inode(inode, mode, dev);  
           break;  
       case S_IFREG:  
           printk("creat a  file \n");  
           break;  
       case S_IFDIR:  
           /* 目录文件 设置i_op和i_fop */
           inode->i_op = &simple_dir_inode_operations;  
           inode->i_fop = &simple_dir_operations;  
           printk("creat a dir file \n");  

           inode->i_nlink++;  
           break;  
       }  
  }  
  return inode;  
}  

综上分析 整个aufs文件系统的代码已经为每个文件和目录创建了dentry结构,同时为每个文件和目录创建了inode结构。此时已经形成了一颗dentry树,不过还不能访问这颗树,要真正用起来还需要挂载到根文件系统。

你可能感兴趣的:(Linux设备驱动分析)