Linux内核源代码情景分析-从路径名到目标节点

先看外包装,__user_walk,假设name为/usr/local/hello.c

  1. int __user_walk(const char *name, unsigned flags, struct nameidata *nd)  
  2. {  
  3.     char *tmp;  
  4.     int err;  
  5.   
  6.     tmp = getname(name);//在系统空间分配一个页面,并从用户空间把文件名复制到这个页面  
  7.     err = PTR_ERR(tmp);  
  8.     if (!IS_ERR(tmp)) {  
  9.         err = 0;  
  10.         if (path_init(tmp, flags, nd))  
  11.             err = path_walk(tmp, nd);  
  12.         putname(tmp);  
  13.     }  
  14.     return err;  
  15. }  
    第一个参数name为路径名。

    第二个参数flags可以为以下的标志:

  1. #define LOOKUP_FOLLOW       (1) //如果找到的目标只是"符号连接"到其它文件或者目录的一个目录项,则要顺着连接链一直找到终点  
  2. #define LOOKUP_DIRECTORY    (2) //表示要寻找的目标必须是个目录  
  3. #define LOOKUP_CONTINUE     (4)  
  4. #define LOOKUP_POSITIVE     (8)  
  5. #define LOOKUP_PARENT       (16) //找到父节点  
  6. #define LOOKUP_NOALT        (32)  
    第三个参数nd是个结构指针,数据结构nameidata的定义如下:

  1. struct nameidata {  
  2.     struct dentry *dentry;  
  3.     struct vfsmount *mnt;  
  4.     struct qstr last;  
  5.     unsigned int flags;  
  6.     int last_type;  
  7. };  

    

    path_init,代码如下:

  1. int path_init(const char *name, unsigned int flags, struct nameidata *nd)  
  2. {  
  3.     nd->last_type = LAST_ROOT; /* if there are only slashes... */  
  4.     nd->flags = flags;  
  5.     if (*name=='/')  
  6.         return walk_init_root(name,nd);//如果路径名是以"/"开头的绝对路径,那就要通过这个函数从根目录开始查找  
  7.     read_lock(&current->fs->lock);  
  8.     nd->mnt = mntget(current->fs->pwdmnt);//如果路径名不以"/"开头,那就当前目录开始  
  9.     nd->dentry = dget(current->fs->pwd);  
  10.     read_unlock(&current->fs->lock);  
  11.     return 1;  
  12. }  

  1. static inline int  
  2. walk_init_root(const char *name, struct nameidata *nd)  
  3. {  
  4.     read_lock(&current->fs->lock);  
  5.     if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {  
  6.         nd->mnt = mntget(current->fs->altrootmnt);  
  7.         nd->dentry = dget(current->fs->altroot);  
  8.         read_unlock(&current->fs->lock);  
  9.         if (__emul_lookup_dentry(name,nd))  
  10.             return 0;  
  11.         read_lock(&current->fs->lock);  
  12.     }  
  13.     nd->mnt = mntget(current->fs->rootmnt);  
  14.     nd->dentry = dget(current->fs->root);  
  15.     read_unlock(&current->fs->lock);  
  16.     return 1;  
  17. }  


    返回到__user_walk,继续执行path_walk,代码如下:

  1. int path_walk(const char * name, struct nameidata *nd)//name为/usr/local/hello.c  
  2. {  
  3.     struct dentry *dentry;  
  4.     struct inode *inode;  
  5.     int err;  
  6.     unsigned int lookup_flags = nd->flags;  
  7.   
  8.     while (*name=='/')//跳过/usr/local/hello.c最开始的'/'  
  9.         name++;  
  10.     if (!*name)//如果只有'/',那么直接退出  
  11.         goto return_base;  
  12.   
  13.     inode = nd->dentry->d_inode;//根节点的indode结构  
  14.     if (current->link_count)  
  15.         lookup_flags = LOOKUP_FOLLOW;//如果找到的目标只是"符号连接"到其它文件或者目录的一个目录项,则要顺着连接链一直找到终点  
  16.   
  17.     /* At this point we know we have a real path component. */  
  18.     for(;;) {//第一次循环  
  19.         unsigned long hash;  
  20.         struct qstr this;  
  21.         unsigned int c;  
  22.   
  23.         err = permission(inode, MAY_EXEC);  
  24.         dentry = ERR_PTR(err);  
  25.         if (err)  
  26.             break;  
  27.   
  28.         this.name = name;//已经指向了usr的首字符'u'  
  29.         c = *(const unsigned char *)name;  
  30.   
  31.         hash = init_name_hash();  
  32.         do {  
  33.             name++;  
  34.             hash = partial_name_hash(c, hash);  
  35.             c = *(const unsigned char *)name;  
  36.         } while (c && (c != '/'));//如果字符c为空或者遇到了'/'则退出循环,本例中c指向的usr后面的'/'  
  37.         this.len = name - (const char *) this.name;//usr的长度  
  38.         this.hash = end_name_hash(hash);  
  39.   
  40.         /* remove trailing slashes? */  
  41.         if (!c)//如果字符c为空,那么说明是最后一个节点,且最后一个节点是文件  
  42.             goto last_component;  
  43.         while (*++name == '/');//跳过'/'  
  44.         if (!*name)//如果'/'后面为空,那么说明这也是最后一个节点,且最后一个节点是目录  
  45.             goto last_with_slashes;  
  46.   
  47.         /* 
  48.          * "." and ".." are special - ".." especially so because it has 
  49.          * to be able to know about the current root directory and 
  50.          * parent relationships. 
  51.          */  
  52.         if (this.name[0] == '.'switch (this.len) {//执行到这里,this代表中间节点,中间节点一定是目录  
  53.             default:  
  54.                 break;  
  55.             case 2:   
  56.                 if (this.name[1] != '.')//如果当前节点是..,那么要表示上一级目录  
  57.                     break;  
  58.                 follow_dotdot(nd);  
  59.                 inode = nd->dentry->d_inode;  
  60.                 /* fallthrough */  
  61.             case 1://如果当前的节点是 . ,表示当前目录  
  62.                 continue;  
  63.         }  
  64.         /* 
  65.          * See if the low-level filesystem might want 
  66.          * to use its own hash.. 
  67.          */  
  68.         if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {//如果有d_hash这个函数  
  69.             err = nd->dentry->d_op->d_hash(nd->dentry, &this);//使用这个函数,重新计算hash值  
  70.             if (err < 0)  
  71.                 break;  
  72.         }  
  73.         /* This does the actual lookups.. */  
  74.         dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//在内存中寻找该节点业已建立的dentry结构  
  75.         if (!dentry) {//如果没有找到  
  76.             dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//那么就要建立该节点的dentry结构  
  77.             err = PTR_ERR(dentry);  
  78.             if (IS_ERR(dentry))  
  79.                 break;  
  80.         }  
  81.         /* Check mountpoints.. */  
  82.         while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))//检查是否是挂载点  
  83.             ;  
  84.   
  85.         err = -ENOENT;  
  86.         inode = dentry->d_inode;  
  87.         if (!inode)  
  88.             goto out_dput;  
  89.         err = -ENOTDIR;   
  90.         if (!inode->i_op)  
  91.             goto out_dput;  
  92.   
  93.         if (inode->i_op->follow_link) {//看看这个指针是否为NULL,这个指针是在ext2_read_inode中设置的  
  94.             err = do_follow_link(dentry, nd);  
  95.             dput(dentry);  
  96.             if (err)  
  97.                 goto return_err;  
  98.             err = -ENOENT;  
  99.             inode = nd->dentry->d_inode;  
  100.             if (!inode)  
  101.                 break;  
  102.             err = -ENOTDIR;   
  103.             if (!inode->i_op)  
  104.                 break;  
  105.         } else {  
  106.             dput(nd->dentry);  
  107.             nd->dentry = dentry;//如果没有,直接附给nd->dentry  
  108.         }  
  109.         err = -ENOTDIR;   
  110.         if (!inode->i_op->lookup)//iop指针也是ext2_read_inode中设置的为ext2_dir_inode_operations,因为当前/usr为目录节点,所以一定要有ext2_lookup这个指针  
  111.             break;  
  112.         continue;  
  113.         /* here ends the main loop */  
  114.   
  115. last_with_slashes:  
  116.         ......  
  117. last_component:  
  118.         ......  
  119. }  
  1. struct qstr {  
  2.     const unsigned char * name;  
  3.     unsigned int len;  
  4.     unsigned int hash;  
  5. };  
    

    cached_lookup,在内存中寻找该节点业已建立的dentry结构,代码如下:

  1. static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)  
  2. {  
  3.     struct dentry * dentry = d_lookup(parent, name);  
  4.   
  5.     if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {  
  6.         if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {  
  7.             dput(dentry);  
  8.             dentry = NULL;  
  9.         }  
  10.     }  
  11.     return dentry;  
  12. }  
  1. struct dentry * d_lookup(struct dentry * parent, struct qstr * name)  
  2. {  
  3.     unsigned int len = name->len;  
  4.     unsigned int hash = name->hash;  
  5.     const unsigned char *str = name->name;  
  6.     struct list_head *head = d_hash(parent,hash);  
  7.     struct list_head *tmp;  
  8.   
  9.     spin_lock(&dcache_lock);  
  10.     tmp = head->next;  
  11.     for (;;) {  
  12.         struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);  
  13.         if (tmp == head)  
  14.             break;  
  15.         tmp = tmp->next;  
  16.         if (dentry->d_name.hash != hash)//比较hash值  
  17.             continue;  
  18.         if (dentry->d_parent != parent)//比较父节点的dentry结构是否一样  
  19.             continue;  
  20.         if (parent->d_op && parent->d_op->d_compare) {  
  21.             if (parent->d_op->d_compare(parent, &dentry->d_name, name))  
  22.                 continue;  
  23.         } else {  
  24.             if (dentry->d_name.len != len)//比较长度  
  25.                 continue;  
  26.             if (memcmp(dentry->d_name.name, str, len))//比较名字  
  27.                 continue;  
  28.         }  
  29.         __dget_locked(dentry);  
  30.         dentry->d_flags |= DCACHE_REFERENCED;  
  31.         spin_unlock(&dcache_lock);  
  32.         return dentry;//如果找到则返回节点的dentry结构  
  33.     }  
  34.     spin_unlock(&dcache_lock);  
  35.     return NULL;//如果没有找到,返回NULL  
  36. }  
    内核中有个杂凑表dentry_hashtable,是一个list_head指针数组,一旦在内存中建立起一个目录节点的dentry结构,就根据其节点名的杂凑值挂入杂凑表中的某个队列,需要寻找时则还是根据杂凑值从杂凑表查找。d_hash就是根据杂凑值找到杂凑表中的某一个队列头。

  1. static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)  
  2. {  
  3.     hash += (unsigned long) parent / L1_CACHE_BYTES;  
  4.     hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);  
  5.     return dentry_hashtable + (hash & D_HASHMASK);  
  6. }  
    根据name在队列里中寻找,是否已经存在这个dentry结构。

 

    如果没有找到,那么要建立该节点的dentry结构,real_lookup代码如下:

  1. static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)  
  2. {  
  3.     struct dentry * result;  
  4.     struct inode *dir = parent->d_inode;  
  5.   
  6.     down(&dir->i_sem);  
  7.     /* 
  8.      * First re-do the cached lookup just in case it was created 
  9.      * while we waited for the directory semaphore.. 
  10.      * 
  11.      * FIXME! This could use version numbering or similar to 
  12.      * avoid unnecessary cache lookups. 
  13.      */  
  14.     result = d_lookup(parent, name);//再一次在内存中寻找该节点业已建立的dentry结构  
  15.     if (!result) {//如果还是没有找到  
  16.         struct dentry * dentry = d_alloc(parent, name);//分配该节点的dentry结构  
  17.         result = ERR_PTR(-ENOMEM);  
  18.         if (dentry) {  
  19.             lock_kernel();  
  20.             result = dir->i_op->lookup(dir, dentry);//分配该节点的inode结构,并挂在dentry结构上  
  21.             unlock_kernel();  
  22.             if (result)  
  23.                 dput(dentry);  
  24.             else  
  25.                 result = dentry;  
  26.         }  
  27.         up(&dir->i_sem);  
  28.         return result;  
  29.     }  
  30.   
  31.     /* 
  32.      * Uhhuh! Nasty case: the cache was re-populated while 
  33.      * we waited on the semaphore. Need to revalidate. 
  34.      */  
  35.     up(&dir->i_sem);  
  36.     if (result->d_op && result->d_op->d_revalidate) {  
  37.         if (!result->d_op->d_revalidate(result, flags) && !d_invalidate(result)) {  
  38.             dput(result);  
  39.             result = ERR_PTR(-ENOENT);  
  40.         }  
  41.     }  
  42.     return result;  
  43. }  
    d_alloc,分配该节点的dentry结构,代码如下:

  1. struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)  
  2. {  
  3.     char * str;  
  4.     struct dentry *dentry;  
  5.   
  6.     dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); //分配了dentry结构  
  7.     if (!dentry)  
  8.         return NULL;  
  9.   
  10.     if (name->len > DNAME_INLINE_LEN-1) {  
  11.         str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);  
  12.         if (!str) {  
  13.             kmem_cache_free(dentry_cache, dentry);   
  14.             return NULL;  
  15.         }  
  16.     } else  
  17.         str = dentry->d_iname;   
  18.   
  19.     memcpy(str, name->name, name->len);  
  20.     str[name->len] = 0;  
  21.   
  22.     atomic_set(&dentry->d_count, 1);  
  23.     dentry->d_flags = 0;  
  24.     dentry->d_inode = NULL;  
  25.     dentry->d_parent = NULL;  
  26.     dentry->d_sb = NULL;  
  27.     dentry->d_name.name = str;//名字  
  28.     dentry->d_name.len = name->len;//长度  
  29.     dentry->d_name.hash = name->hash;//hash值  
  30.     dentry->d_op = NULL;  
  31.     dentry->d_fsdata = NULL;  
  32.     INIT_LIST_HEAD(&dentry->d_vfsmnt);//见下面关于dentry的说明  
  33.     INIT_LIST_HEAD(&dentry->d_hash);  
  34.     INIT_LIST_HEAD(&dentry->d_lru);  
  35.     INIT_LIST_HEAD(&dentry->d_subdirs);  
  36.     INIT_LIST_HEAD(&dentry->d_alias);  
  37.     if (parent) {  
  38.         dentry->d_parent = dget(parent);  
  39.         dentry->d_sb = parent->d_sb;  
  40.         spin_lock(&dcache_lock);  
  41.         list_add(&dentry->d_child, &parent->d_subdirs);  
  42.         spin_unlock(&dcache_lock);  
  43.     } else  
  44.         INIT_LIST_HEAD(&dentry->d_child);  
  45.   
  46.     dentry_stat.nr_dentry++;  
  47.     return dentry;  
  48. }  
    其中dentry结构,如下:

  1. struct dentry {  
  2.     atomic_t d_count;  
  3.     unsigned int d_flags;  
  4.     struct inode  * d_inode;    /* Where the name belongs to - NULL is negative */  
  5.     struct dentry * d_parent;   /* parent directory */  
  6.     struct list_head d_vfsmnt;  
  7.     struct list_head d_hash;    /* lookup hash list */  
  8.     struct list_head d_lru;     /* d_count = 0 LRU list */  
  9.     struct list_head d_child;   /* child of parent list */  
  10.     struct list_head d_subdirs; /* our children */  
  11.     struct list_head d_alias;   /* inode alias list */  
  12.     struct qstr d_name;  
  13.     unsigned long d_time;       /* used by d_revalidate */  
  14.     struct dentry_operations  *d_op;  
  15.     struct super_block * d_sb;  /* The root of the dentry tree */  
  16.     unsigned long d_reftime;    /* last time referenced */  
  17.     void * d_fsdata;        /* fs-specific data */  
  18.     unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */  
  19. };  
    1、每个dentry结构都通过队列头d_hash链入杂凑表dentry_hashtable中的某个队列里。

    2、共享计数为0的dentry结构都通过队列头d_lru链入LRU队列dentry_unused。在队列中等待释放或者"东山再起"。

    3、每个dentry结构都通过指针d_inode指向一个inode数据结构。但是多个dentry结构可以指向同一个indoe数据结构。

    4、指向同一个inode数据结构的dentry结构都通过队列头d_alias链接在一起,都在该inode结构的i_dentry队列中。

    5、每个dentry结构都通过指针d_parent指向其父目录节点的dentry结构,并通过队列头d_child跟同一目录中的其它节点的dentry结构链接在一起,都在父目录节点的d_subdirs队列中。

    6、每个dentry结构都通过指针d_sb指向一个super_block数据结构。

    7、每个dentry结构都通过指针d_op指向一个dentry_operations数据结构。

    8、每个dentry结构都有个队列头d_vfsmnt,用于文件系统的安装。

    返回到real_lookup中,如果该节点的dentry结构分配成功,那么调用dir->i_op->lookup(dir, dentry)来分配该节点的inode结构,并挂在dentry结构上。其中dir是父目录节点的inode结构。

    对于ext2文件系统来说,lookup为ext2_lookup。代码如下:

  1. static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)  
  2. {  
  3.     struct inode * inode;  
  4.     struct ext2_dir_entry_2 * de;  
  5.     struct buffer_head * bh;  
  6.   
  7.     if (dentry->d_name.len > EXT2_NAME_LEN)  
  8.         return ERR_PTR(-ENAMETOOLONG);  
  9.   
  10.     bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);//根据父节点的inode结构中inode->u.ext2_i.i_data找到对应的目录项  
  11.     inode = NULL;  
  12.     if (bh) {  
  13.         unsigned long ino = le32_to_cpu(de->inode);//得到该节点inode结构的节点号  
  14.         brelse (bh);  
  15.         inode = iget(dir->i_sb, ino);//通过这个节点号寻找该节点的inode结构  
  16.   
  17.         if (!inode)  
  18.             return ERR_PTR(-EACCES);  
  19.     }  
  20.     d_add(dentry, inode);//把该节点的inode结构和dentry连接在一起  
  21.     return NULL;  
  22. }  
    有关文件系统的细节,请看 文件系统,用这篇文章的术语,ext2_find_entry根据父节点的inode结构中inode->u.ext2_i.i_data找到对应的目录项,这个目录项的结构是ext2_dir_entry_2结构,读者在前面已经看过dentry结构,它们的区别是ext2_dir_entry_2结构对应硬盘上的页目录项结构,而dentry是动态建立的。

  1. struct ext2_dir_entry_2 {  
  2.     __u32   inode;          /* Inode number */  
  3.     __u16   rec_len;        /* Directory entry length */  
  4.     __u8    name_len;       /* Name length */  
  5.     __u8    file_type;  
  6.     char    name[EXT2_NAME_LEN];    /* File name */  
  7. };  
     ext2_find_entry找到的数据块通常有许多目录项,根据dentry->d_name.name, dentry->d_name.len找到对应的目录项结构ext2_dir_entry_2。


    然后根据de->inode,得到该节点inode结构的节点号,通过这个节点号寻找该节点的inode结构,iget如下:

  1. static inline struct inode *iget(struct super_block *sb, unsigned long ino)  
  2. {  
  3.     return iget4(sb, ino, NULL, NULL);  
  4. }  
  1. struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)  
  2. {  
  3.     struct list_head * head = inode_hashtable + hash(sb,ino);  
  4.     struct inode * inode;  
  5.   
  6.     spin_lock(&inode_lock);  
  7.     inode = find_inode(sb, ino, head, find_actor, opaque);//在杂凑表队列中寻找  
  8.     if (inode) {//找到了  
  9.         __iget(inode);//递增计数  
  10.         spin_unlock(&inode_lock);  
  11.         wait_on_inode(inode);  
  12.         return inode;  
  13.     }  
  14.     spin_unlock(&inode_lock);  
  15.   
  16.     /* 
  17.      * get_new_inode() will do the right thing, re-trying the search 
  18.      * in case it had to block at any point. 
  19.      */  
  20.     return get_new_inode(sb, ino, head, find_actor, opaque);//分配一个新的该节点的inode结构  
  21. }  
    inode结构也有个杂凑表inode_hashtable,已经建立的inode结构都通过结构中的i_hash(也是一个list_head)挂在该杂凑表的某一队列中,所以首先要通过find_inode()在杂凑表队列中寻找。
  1. static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)  
  2. {  
  3.     struct list_head *tmp;  
  4.     struct inode * inode;  
  5.   
  6.     tmp = head;  
  7.     for (;;) {  
  8.         tmp = tmp->next;  
  9.         inode = NULL;  
  10.         if (tmp == head)  
  11.             break;  
  12.         inode = list_entry(tmp, struct inode, i_hash);  
  13.         if (inode->i_ino != ino)//对比节点号  
  14.             continue;  
  15.         if (inode->i_sb != sb)//和超级块结构  
  16.             continue;  
  17.         if (find_actor && !find_actor(inode, ino, opaque))  
  18.             continue;  
  19.         break;  
  20.     }  
  21.     return inode;  
  22. }  
    如果没有找到,get_new_inode分配一个新的该节点的inode结构,代码如下:
  1. static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)  
  2. {  
  3.     struct inode * inode;  
  4.   
  5.     inode = alloc_inode();  
  6.     if (inode) {  
  7.         struct inode * old;  
  8.   
  9.         spin_lock(&inode_lock);  
  10.         /* We released the lock, so.. */  
  11.         old = find_inode(sb, ino, head, find_actor, opaque);//再一次在杂凑表队列中寻找  
  12.         if (!old) {//如果没有找到  
  13.             inodes_stat.nr_inodes++;  
  14.             list_add(&inode->i_list, &inode_in_use);  
  15.             list_add(&inode->i_hash, head);//加入到对应的hash表  
  16.             inode->i_sb = sb;//超级块结构  
  17.             inode->i_dev = sb->s_dev;//设备号  
  18.             inode->i_ino = ino;//节点号  
  19.             inode->i_flags = 0;  
  20.             atomic_set(&inode->i_count, 1);  
  21.             inode->i_state = I_LOCK;  
  22.             spin_unlock(&inode_lock);  
  23.   
  24.             clean_inode(inode);  
  25.             sb->s_op->read_inode(inode);  
  26.   
  27.             /* 
  28.              * This is special!  We do not need the spinlock 
  29.              * when clearing I_LOCK, because we're guaranteed 
  30.              * that nobody else tries to do anything about the 
  31.              * state of the inode when it is locked, as we 
  32.              * just created it (so there can be no old holders 
  33.              * that haven't tested I_LOCK). 
  34.              */  
  35.             inode->i_state &= ~I_LOCK;  
  36.             wake_up(&inode->i_wait);  
  37.   
  38.             return inode;  
  39.         }  
  40.   
  41.         /* 
  42.          * Uhhuh, somebody else created the same inode under 
  43.          * us. Use the old inode instead of the one we just 
  44.          * allocated. 
  45.          */  
  46.         __iget(old);//如果找到了inode结构  
  47.         spin_unlock(&inode_lock);  
  48.         destroy_inode(inode);  
  49.         inode = old;//使用找到的inode结构  
  50.         wait_on_inode(inode);  
  51.     }  
  52.     return inode;  
  53. }  
    alloc_inode,分配一个新的inode结构,代码如下:

  1. #define alloc_inode() \  
  2.      ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))  
    sb->s_op->read_inode,把硬盘上的inode结构读入,并合理的赋值给内存中这个动态的inode。下面我们分别介绍下动态的inode结构和硬盘上的ext2_inode结构。

    动态的inode结构:

  1. struct inode {  
  2.     struct list_head    i_hash;  
  3.     struct list_head    i_list;  
  4.     struct list_head    i_dentry;  
  5.       
  6.     struct list_head    i_dirty_buffers;  
  7.   
  8.     unsigned long       i_ino;  
  9.     atomic_t        i_count;  
  10.     kdev_t          i_dev;  
  11.     umode_t         i_mode;  
  12.     nlink_t         i_nlink;  
  13.     uid_t           i_uid;  
  14.     gid_t           i_gid;  
  15.     kdev_t          i_rdev;  
  16.     loff_t          i_size;  
  17.     time_t          i_atime;  
  18.     time_t          i_mtime;  
  19.     time_t          i_ctime;  
  20.     unsigned long       i_blksize;  
  21.     unsigned long       i_blocks;  
  22.     unsigned long       i_version;  
  23.     struct semaphore    i_sem;  
  24.     struct semaphore    i_zombie;  
  25.     struct inode_operations *i_op;  
  26.     struct file_operations  *i_fop; /* former ->i_op->default_file_ops */  
  27.     struct super_block  *i_sb;  
  28.     wait_queue_head_t   i_wait;  
  29.     struct file_lock    *i_flock;  
  30.     struct address_space    *i_mapping;  
  31.     struct address_space    i_data;   
  32.     struct dquot        *i_dquot[MAXQUOTAS];  
  33.     struct pipe_inode_info  *i_pipe;  
  34.     struct block_device *i_bdev;  
  35.   
  36.     unsigned long       i_dnotify_mask; /* Directory notify events */  
  37.     struct dnotify_struct   *i_dnotify; /* for directory notifications */  
  38.   
  39.     unsigned long       i_state;  
  40.   
  41.     unsigned int        i_flags;  
  42.     unsigned char       i_sock;  
  43.   
  44.     atomic_t        i_writecount;  
  45.     unsigned int        i_attr_flags;  
  46.     __u32           i_generation;  
  47.     union {  
  48.         struct minix_inode_info     minix_i;  
  49.         struct ext2_inode_info      ext2_i;  
  50.         struct hpfs_inode_info      hpfs_i;  
  51.         struct ntfs_inode_info      ntfs_i;  
  52.         struct msdos_inode_info     msdos_i;  
  53.         struct umsdos_inode_info    umsdos_i;  
  54.         struct iso_inode_info       isofs_i;  
  55.         struct nfs_inode_info       nfs_i;  
  56.         struct sysv_inode_info      sysv_i;  
  57.         struct affs_inode_info      affs_i;  
  58.         struct ufs_inode_info       ufs_i;  
  59.         struct efs_inode_info       efs_i;  
  60.         struct romfs_inode_info     romfs_i;  
  61.         struct shmem_inode_info     shmem_i;  
  62.         struct coda_inode_info      coda_i;  
  63.         struct smb_inode_info       smbfs_i;  
  64.         struct hfs_inode_info       hfs_i;  
  65.         struct adfs_inode_info      adfs_i;  
  66.         struct qnx4_inode_info      qnx4_i;  
  67.         struct bfs_inode_info       bfs_i;  
  68.         struct udf_inode_info       udf_i;  
  69.         struct ncp_inode_info       ncpfs_i;  
  70.         struct proc_inode_info      proc_i;  
  71.         struct socket           socket_i;  
  72.         struct usbdev_inode_info        usbdev_i;  
  73.         void                *generic_ip;  
  74.     } u;  
  75. }  


    硬盘上的 ext2_inode 结构

  1. struct ext2_inode {  
  2.     __u16   i_mode;     /* File mode */  
  3.     __u16   i_uid;      /* Low 16 bits of Owner Uid */  
  4.     __u32   i_size;     /* Size in bytes */  
  5.     __u32   i_atime;    /* Access time */  
  6.     __u32   i_ctime;    /* Creation time */  
  7.     __u32   i_mtime;    /* Modification time */  
  8.     __u32   i_dtime;    /* Deletion Time */  
  9.     __u16   i_gid;      /* Low 16 bits of Group Id */  
  10.     __u16   i_links_count;  /* Links count */  
  11.     __u32   i_blocks;   /* Blocks count */  
  12.     __u32   i_flags;    /* File flags */  
  13.     union {  
  14.         struct {  
  15.             __u32  l_i_reserved1;  
  16.         } linux1;  
  17.         struct {  
  18.             __u32  h_i_translator;  
  19.         } hurd1;  
  20.         struct {  
  21.             __u32  m_i_reserved1;  
  22.         } masix1;  
  23.     } osd1;             /* OS dependent 1 */  
  24.     __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */  
  25.     __u32   i_generation;   /* File version (for NFS) */  
  26.     __u32   i_file_acl; /* File ACL */  
  27.     __u32   i_dir_acl;  /* Directory ACL */  
  28.     __u32   i_faddr;    /* Fragment address */  
  29.     union {  
  30.         struct {  
  31.             __u8    l_i_frag;   /* Fragment number */  
  32.             __u8    l_i_fsize;  /* Fragment size */  
  33.             __u16   i_pad1;  
  34.             __u16   l_i_uid_high;   /* these 2 fields    */  
  35.             __u16   l_i_gid_high;   /* were reserved2[0] */  
  36.             __u32   l_i_reserved2;  
  37.         } linux2;  
  38.         struct {  
  39.             __u8    h_i_frag;   /* Fragment number */  
  40.             __u8    h_i_fsize;  /* Fragment size */  
  41.             __u16   h_i_mode_high;  
  42.             __u16   h_i_uid_high;  
  43.             __u16   h_i_gid_high;  
  44.             __u32   h_i_author;  
  45.         } hurd2;  
  46.         struct {  
  47.             __u8    m_i_frag;   /* Fragment number */  
  48.             __u8    m_i_fsize;  /* Fragment size */  
  49.             __u16   m_pad1;  
  50.             __u32   m_i_reserved2[2];  
  51.         } masix2;  
  52.     } osd2;             /* OS dependent 2 */  
  53. }  
       sb->s_op->read_inode,把硬盘上的inode结构读入,并合理的赋值给内存中这个动态的inode。
  1. void ext2_read_inode (struct inode * inode)  
  2. {  
  3.     struct buffer_head * bh;  
  4.     struct ext2_inode * raw_inode;  
  5.     unsigned long block_group;  
  6.     unsigned long group_desc;  
  7.     unsigned long desc;  
  8.     unsigned long block;  
  9.     unsigned long offset;  
  10.     struct ext2_group_desc * gdp;  
  11.   
  12.     if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&  
  13.          inode->i_ino != EXT2_ACL_DATA_INO &&  
  14.          inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||  
  15.         inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {  
  16.         ext2_error (inode->i_sb, "ext2_read_inode",  
  17.                 "bad inode number: %lu", inode->i_ino);  
  18.         goto bad_inode;  
  19.     }  
  20.     block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);  
  21.     if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) {  
  22.         ext2_error (inode->i_sb, "ext2_read_inode",  
  23.                 "group >= groups count");  
  24.         goto bad_inode;  
  25.     }  
  26.     group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);  
  27.     desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);  
  28.     bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];  
  29.     if (!bh) {  
  30.         ext2_error (inode->i_sb, "ext2_read_inode",  
  31.                 "Descriptor not loaded");  
  32.         goto bad_inode;  
  33.     }  
  34.   
  35.     gdp = (struct ext2_group_desc *) bh->b_data;  
  36.     /* 
  37.      * Figure out the offset within the block group inode table 
  38.      */  
  39.     offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *  
  40.         EXT2_INODE_SIZE(inode->i_sb);  
  41.     block = le32_to_cpu(gdp[desc].bg_inode_table) +  
  42.         (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));  
  43.     if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {  
  44.         ext2_error (inode->i_sb, "ext2_read_inode",  
  45.                 "unable to read inode block - "  
  46.                 "inode=%lu, block=%lu", inode->i_ino, block);  
  47.         goto bad_inode;  
  48.     }  
  49.     offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1);  
  50.     raw_inode = (struct ext2_inode *) (bh->b_data + offset);//根据节点号,找到硬盘上的ext2_inode结构  
  51.   
  52.     inode->i_mode = le16_to_cpu(raw_inode->i_mode);//mode也来来源于ext2_inode结构  
  53.     inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);  
  54.     inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);  
  55.     if(!(test_opt (inode->i_sb, NO_UID32))) {  
  56.         inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;  
  57.         inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;  
  58.     }  
  59.     inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);  
  60.     inode->i_size = le32_to_cpu(raw_inode->i_size);  
  61.     inode->i_atime = le32_to_cpu(raw_inode->i_atime);  
  62.     inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);  
  63.     inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);  
  64.     inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);  
  65.     /* We now have enough fields to check if the inode was active or not. 
  66.      * This is needed because nfsd might try to access dead inodes 
  67.      * the test is that same one that e2fsck uses 
  68.      * NeilBrown 1999oct15 
  69.      */  
  70.     if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.ext2_i.i_dtime)) {  
  71.         /* this inode is deleted */  
  72.         brelse (bh);  
  73.         goto bad_inode;  
  74.     }  
  75.     inode->i_blksize = PAGE_SIZE;    /* This is the optimal IO size (for stat), not the fs block size */  
  76.     inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);  
  77.     inode->i_version = ++event;  
  78.     inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);//联合体的ext2_i被复制  
  79.     inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);  
  80.     inode->u.ext2_i.i_frag_no = raw_inode->i_frag;  
  81.     inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;  
  82.     inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);  
  83.     if (S_ISDIR(inode->i_mode))  
  84.         inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);  
  85.     else {  
  86.         inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high);  
  87.         inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;  
  88.     }  
  89.     inode->i_generation = le32_to_cpu(raw_inode->i_generation);  
  90.     inode->u.ext2_i.i_block_group = block_group;  
  91.   
  92.     /* 
  93.      * NOTE! The in-memory inode i_data array is in little-endian order 
  94.      * even on big-endian machines: we do NOT byteswap the block numbers! 
  95.      */  
  96.     for (block = 0; block < EXT2_N_BLOCKS; block++)  
  97.         inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];  
  98.   
  99.     if (inode->i_ino == EXT2_ACL_IDX_INO ||  
  100.         inode->i_ino == EXT2_ACL_DATA_INO)  
  101.         /* Nothing to do */ ;  
  102.     else if (S_ISREG(inode->i_mode)) {//根据不同的该节点的inode结构不同状态,设置不同的指针  
  103.         inode->i_op = &ext2_file_inode_operations;  
  104.         inode->i_fop = &ext2_file_operations;  
  105.         inode->i_mapping->a_ops = &ext2_aops;  
  106.     } else if (S_ISDIR(inode->i_mode)) {//目前是目录  
  107.         inode->i_op = &ext2_dir_inode_operations;  
  108.         inode->i_fop = &ext2_dir_operations;  
  109.     } else if (S_ISLNK(inode->i_mode)) {  
  110.         if (!inode->i_blocks)  
  111.             inode->i_op = &ext2_fast_symlink_inode_operations;  
  112.         else {  
  113.             inode->i_op = &page_symlink_inode_operations;  
  114.             inode->i_mapping->a_ops = &ext2_aops;  
  115.         }  
  116.     } else   
  117.         init_special_inode(inode, inode->i_mode,  
  118.                    le32_to_cpu(raw_inode->i_block[0]));  
  119.     brelse (bh);  
  120.     inode->i_attr_flags = 0;  
  121.     if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {  
  122.         inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;  
  123.         inode->i_flags |= S_SYNC;  
  124.     }  
  125.     if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {  
  126.         inode->i_attr_flags |= ATTR_FLAG_APPEND;  
  127.         inode->i_flags |= S_APPEND;  
  128.     }  
  129.     if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {  
  130.         inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;  
  131.         inode->i_flags |= S_IMMUTABLE;  
  132.     }  
  133.     if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {  
  134.         inode->i_attr_flags |= ATTR_FLAG_NOATIME;  
  135.         inode->i_flags |= S_NOATIME;  
  136.     }  
  137.     return;  
  138.       
  139. bad_inode:  
  140.     make_bad_inode(inode);  
  141.     return;  
  142. }  
    其中ext2_dir_inode_operations如下:

  1. struct inode_operations ext2_dir_inode_operations = {  
  2.     create:     ext2_create,  
  3.     lookup:     ext2_lookup,  
  4.     link:       ext2_link,  
  5.     unlink:     ext2_unlink,  
  6.     symlink:    ext2_symlink,  
  7.     mkdir:      ext2_mkdir,  
  8.     rmdir:      ext2_rmdir,  
  9.     mknod:      ext2_mknod,  
  10.     rename:     ext2_rename,  
  11. };  

    iget获取到该节点的inode结构后,就返回ext2_lookup,继续执行d_add(dentry, inode),把该节点的inode结构和dentry连接在一起。

  1. static __inline__ void d_add(struct dentry * entry, struct inode * inode)  
  2. {  
  3.     d_instantiate(entry, inode);//该节点的inode结构和dentry连接在一起  
  4.     d_rehash(entry);//把dentry结构放入杂凑表的某一个队里中  
  5. }  
  1. void d_instantiate(struct dentry *entry, struct inode * inode)  
  2. {  
  3.     spin_lock(&dcache_lock);  
  4.     if (inode)  
  5.         list_add(&entry->d_alias, &inode->i_dentry);//可能一个inode结构对应多个entry结构  
  6.     entry->d_inode = inode;//链接在一起了  
  7.     spin_unlock(&dcache_lock);  
  8. }  
  1. void d_rehash(struct dentry * entry)  
  2. {  
  3.     struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);  
  4.     spin_lock(&dcache_lock);  
  5.     list_add(&entry->d_hash, list);  
  6.     spin_unlock(&dcache_lock);  
  7. }  
    而inode结构放入杂凑表的某个队列是在get_new_inode里面:
  1. list_add(&inode->i_hash, head);  
    

    real_lookup返回该节点的dentry结构。然后检查是否是挂在点,如果不是nd->dentry被赋值为dentry。由于是目录节点,所有lookup指针不能为NULL。

    第一轮循环,执行到这里,continue开始第二轮循环。

  1. if (!inode->i_op->lookup)  
  2.     break;  
  3. continue;  
    

    第二轮循环,如下:

  1. int path_walk(const char * name, struct nameidata *nd)  
  2. {  
  3.     struct dentry *dentry;  
  4.     struct inode *inode;  
  5.     int err;  
  6.     unsigned int lookup_flags = nd->flags;  
  7.   
  8.     while (*name=='/')  
  9.         name++;  
  10.     if (!*name)  
  11.         goto return_base;  
  12.   
  13.     inode = nd->dentry->d_inode;  
  14.     if (current->link_count)  
  15.         lookup_flags = LOOKUP_FOLLOW;  
  16.   
  17.     /* At this point we know we have a real path component. */  
  18.     for(;;) {  
  19.         unsigned long hash;  
  20.         struct qstr this;  
  21.         unsigned int c;  
  22.   
  23.         err = permission(inode, MAY_EXEC);  
  24.         dentry = ERR_PTR(err);  
  25.         if (err)  
  26.             break;  
  27.   
  28.         this.name = name;//指向local的第一个字符'l'  
  29.         c = *(const unsigned char *)name;  
  30.   
  31.         hash = init_name_hash();  
  32.         do {  
  33.             name++;  
  34.             hash = partial_name_hash(c, hash);  
  35.             c = *(const unsigned char *)name;  
  36.         } while (c && (c != '/'));  
  37.         this.len = name - (const char *) this.name;//local的长度  
  38.         this.hash = end_name_hash(hash);//hash值  
  39.   
  40.         /* remove trailing slashes? */  
  41.         if (!c)  
  42.             goto last_component;  
  43.         while (*++name == '/');  
  44.         if (!*name)  
  45.             goto last_with_slashes;  
  46.   
  47.         /* 
  48.          * "." and ".." are special - ".." especially so because it has 
  49.          * to be able to know about the current root directory and 
  50.          * parent relationships. 
  51.          */  
  52.         if (this.name[0] == '.'switch (this.len) {  
  53.             default:  
  54.                 break;  
  55.             case 2:   
  56.                 if (this.name[1] != '.')  
  57.                     break;  
  58.                 follow_dotdot(nd);  
  59.                 inode = nd->dentry->d_inode;  
  60.                 /* fallthrough */  
  61.             case 1:  
  62.                 continue;  
  63.         }  
  64.         /* 
  65.          * See if the low-level filesystem might want 
  66.          * to use its own hash.. 
  67.          */  
  68.         if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  69.             err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  70.             if (err < 0)  
  71.                 break;  
  72.         }  
  73.         /* This does the actual lookups.. */  
  74.         dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);  
  75.         if (!dentry) {  
  76.             dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);  
  77.             err = PTR_ERR(dentry);  
  78.             if (IS_ERR(dentry))  
  79.                 break;  
  80.         }  
  81.         /* Check mountpoints.. */  
  82.         while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))  
  83.             ;  
  84.   
  85.         err = -ENOENT;  
  86.         inode = dentry->d_inode;  
  87.         if (!inode)  
  88.             goto out_dput;  
  89.         err = -ENOTDIR;   
  90.         if (!inode->i_op)  
  91.             goto out_dput;  
  92.   
  93.         if (inode->i_op->follow_link) {  
  94.             err = do_follow_link(dentry, nd);  
  95.             dput(dentry);  
  96.             if (err)  
  97.                 goto return_err;  
  98.             err = -ENOENT;  
  99.             inode = nd->dentry->d_inode;  
  100.             if (!inode)  
  101.                 break;  
  102.             err = -ENOTDIR;   
  103.             if (!inode->i_op)  
  104.                 break;  
  105.         } else {  
  106.             dput(nd->dentry);  
  107.             nd->dentry = dentry;  
  108.         }  
  109.         err = -ENOTDIR;   
  110.         if (!inode->i_op->lookup)  
  111.             break;  
  112.         continue;  
  113.         /* here ends the main loop */  
  114.   
  115. last_with_slashes:  
  116.         ......  
  117. last_component:  
  118.         ......  
  119. }  
    除上面注释外,其他的流程和和第一次循环都一样。

    第二轮循环,也是执行到这里,continue开始第三轮循环:

  1. if (!inode->i_op->lookup)//由于/usr/local/hello.c,local仍然是目录节点  
  2.     break;  
  3. continue;  


    第三轮循环,如下:

  1. int path_walk(const char * name, struct nameidata *nd)  
  2. {  
  3.     struct dentry *dentry;  
  4.     struct inode *inode;  
  5.     int err;  
  6.     unsigned int lookup_flags = nd->flags;  
  7.   
  8.     while (*name=='/')  
  9.         name++;  
  10.     if (!*name)  
  11.         goto return_base;  
  12.   
  13.     inode = nd->dentry->d_inode;  
  14.     if (current->link_count)  
  15.         lookup_flags = LOOKUP_FOLLOW;  
  16.   
  17.     /* At this point we know we have a real path component. */  
  18.     for(;;) {  
  19.         unsigned long hash;  
  20.         struct qstr this;  
  21.         unsigned int c;  
  22.   
  23.         err = permission(inode, MAY_EXEC);  
  24.         dentry = ERR_PTR(err);  
  25.         if (err)  
  26.             break;  
  27.   
  28.         this.name = name;//指向了hello.c的第一个字符'h'  
  29.         c = *(const unsigned char *)name;  
  30.   
  31.         hash = init_name_hash();  
  32.         do {  
  33.             name++;  
  34.             hash = partial_name_hash(c, hash);  
  35.             c = *(const unsigned char *)name;  
  36.         } while (c && (c != '/'));  
  37.         this.len = name - (const char *) this.name;//hello.c的长度  
  38.         this.hash = end_name_hash(hash);  
  39.   
  40.         /* remove trailing slashes? */  
  41.         if (!c)//c为NULL了  
  42.             goto last_component;  
  43.         while (*++name == '/');  
  44.         if (!*name)  
  45.             goto last_with_slashes;  
  46.   
  47.         .....  
  48.   
  49. last_with_slashes:  
  50.         lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;//如果最后一个节点是目录,那么要加上这两个标志位  
  51. last_component:  
  52.         if (lookup_flags & LOOKUP_PARENT)//这个标志位表示是要寻找父节点  
  53.             goto lookup_parent;  
  54.         if (this.name[0] == '.'switch (this.len) {//如果最后一个节点是目录,且是dot或者dotdot  
  55.             default:  
  56.                 break;  
  57.             case 2:   
  58.                 if (this.name[1] != '.')  
  59.                     break;  
  60.                 follow_dotdot(nd);  
  61.                 inode = nd->dentry->d_inode;  
  62.                 /* fallthrough */  
  63.             case 1:  
  64.                 goto return_base;  
  65.         }  
  66.         if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  67.             err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  68.             if (err < 0)  
  69.                 break;  
  70.         }  
  71.         dentry = cached_lookup(nd->dentry, &this, 0);  
  72.         if (!dentry) {  
  73.             dentry = real_lookup(nd->dentry, &this, 0);//本次寻找的节点是文件  
  74.             err = PTR_ERR(dentry);  
  75.             if (IS_ERR(dentry))  
  76.                 break;  
  77.         }  
  78.         while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))//是否是挂载点  
  79.             ;  
  80.         inode = dentry->d_inode;  
  81.         if ((lookup_flags & LOOKUP_FOLLOW)//和第一次和第二次循环不同,必须LOOKUP_FOLLOW标志位置1  
  82.             && inode && inode->i_op && inode->i_op->follow_link) {  
  83.             err = do_follow_link(dentry, nd);  
  84.             dput(dentry);  
  85.             if (err)  
  86.                 goto return_err;  
  87.             inode = nd->dentry->d_inode;  
  88.         } else {  
  89.             dput(nd->dentry);  
  90.             nd->dentry = dentry;//赋值给nd->dentry  
  91.         }  
  92.         err = -ENOENT;  
  93.         if (!inode)  
  94.             goto no_inode;  
  95.         if (lookup_flags & LOOKUP_DIRECTORY) {//如果最后一个节点是目录,也就是这个标志为置1的时候,还要检查指针是否为NULL  
  96.             err = -ENOTDIR;   
  97.             if (!inode->i_op || !inode->i_op->lookup)  
  98.                 break;  
  99.         }  
  100.         goto return_base;  
  101. no_inode:  
  102.         err = -ENOENT;  
  103.         if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))  
  104.             break;  
  105.         goto return_base;  
  106. lookup_parent: ////nd->dentry是父节点的dentry结构  
  107.         nd->last = this;//nd->last是最后一个节点的名字  
  108.         nd->last_type = LAST_NORM;//最后一个节点的类型  
  109.         if (this.name[0] != '.')  
  110.             goto return_base;  
  111.         if (this.len == 1)  
  112.             nd->last_type = LAST_DOT;  
  113.         else if (this.len == 2 && this.name[1] == '.')  
  114.             nd->last_type = LAST_DOTDOT;  
  115. return_base:  
  116.         return 0;  
  117. out_dput:  
  118.         dput(dentry);  
  119.         break;  
  120.     }  
  121.     path_release(nd);  
  122. return_err:  
  123.     return err;  
  124. }  
    real_lookup由于hello.c节点是文件,所以执行如下代码段:
  1. if (inode->i_ino == EXT2_ACL_IDX_INO ||  
  2.         inode->i_ino == EXT2_ACL_DATA_INO)  
  3.         /* Nothing to do */ ;  
  4.     else if (S_ISREG(inode->i_mode)) {//hello.c是文件,所以执行这段代码  
  5.         inode->i_op = &ext2_file_inode_operations;  
  6.         inode->i_fop = &ext2_file_operations;  
  7.         inode->i_mapping->a_ops = &ext2_aops;  
  8.     } else if (S_ISDIR(inode->i_mode)) {  
  9.         inode->i_op = &ext2_dir_inode_operations;  
  10.         inode->i_fop = &ext2_dir_operations;  
  11.     } else if (S_ISLNK(inode->i_mode)) {  
  12.         if (!inode->i_blocks)  
  13.             inode->i_op = &ext2_fast_symlink_inode_operations;  
  14.         else {  
  15.             inode->i_op = &page_symlink_inode_operations;  
  16.             inode->i_mapping->a_ops = &ext2_aops;  
  17.         }  
  18.     } else   
  19.         init_special_inode(inode, inode->i_mode,  
  20.                    le32_to_cpu(raw_inode->i_block[0]));  
    至此,path_walk的三层循环,都分析完了,nd->dentry最终指向了/usr/local/hello.c这个文件节点的dentry结构,其中的d_inode指向了该节点的inode结构。
本PDF电子书包含上下两册,共1576页,带目录,高清非扫描版本。 作者: 毛德操 胡希明 丛书名: Linux内核源代码情景分析 出版社:浙江大学出版社 目录 第1章 预备知识 1.1 Linux内核简介. 1.2 Intel X86 CPU系列的寻址方式 1.3 i386的页式内存管理机制 1.4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户堆栈的扩展 2.6 物理页面的使用和周转 2.7 物理页面的分配 2.8 页面的定期换出 2.9 页面的换入 2.10 内核缓冲区的管理 2.11 外部设备存储空间的地址映射 2.12 系统调用brk() 2.13 系统调用mmap() 第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3.2 中断向量表IDT的初始化 3.3 中断请求队列的初始化 3.4 中断的响应和服务 3.5 软中断与Bottom Half 3.6 页面异常的进入和返回 3.7 时钟中断 3.8 系统调用 3.9 系统调用号与跳转表 第4章 进程与进程调度 4.1 进程四要素 4.2 进程三部曲:创建、执行与消亡 4.3 系统调用fork()、vfork()与clone() 4.4 系统调用execve() 4.5 系统调用exit()与wait4() 4.6 进程的调度与切换 4.7 强制性调度 4.8 系统调用nanosleep()和pause() 4.9 内核中的互斥操作 第5章 文件系统 5.1 概述 5.2 从路径名目标节点 5.3 访问权限与文件安全性 5.4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5.6 文件的写与读 5.7 其他文件操作 5.8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用socket() 7.2函数sys—socket()——创建插口 7.3函数sys—bind()——指定插口地址 7.4函数sys—listen()——设定server插口 7.5函数sys—accept()——接受连接请求 7.6函数sys—connect()——请求连接 7.7报文的接收与发送 7.8插口的关闭 7.9其他 第8章设备驱动 8.1概述 8.2系统调用mknod() 8.3可安装模块 8.4PCI总线 8.5块设备的驱动 8.6字符设备驱动概述 8.7终端设备与汉字信息处理 8.8控制台的驱动 8.9通用串行外部总线USB 8.10系统调用select()以及异步输入/输出 8.11设备文件系统devfs 第9章多处理器SMP系统结构 9.1概述 9.2SMP结构中的互斥问题 9.3高速缓存与内存的一致性 9.4SMP结构中的中断机制 9.5SMP结构中的进程调度 9.6SMP系统的引导 第10章系统引导和初始化 10.1系统引导过程概述 10.2系统初始化(第一阶段) 10.3系统初始化(第二阶段) 10.4系统初始化(第三阶段) 10.5系统的关闭和重引导
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值