Linux内核源代码情景分析-从路径名到目标节点
来源:互联网 发布:淘宝等级查询网站 编辑:程序博客网 时间:2024/06/04 18:19
- int __user_walk(const char *name, unsigned flags, struct nameidata *nd)
- {
- char *tmp;
- int err;
- tmp = getname(name);//在系统空间分配一个页面,并从用户空间把文件名复制到这个页面
- err = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- err = 0;
- if (path_init(tmp, flags, nd))
- err = path_walk(tmp, nd);
- putname(tmp);
- }
- return err;
- }
第二个参数flags可以为以下的标志:
- #define LOOKUP_FOLLOW (1) //如果找到的目标只是"符号连接"到其它文件或者目录的一个目录项,则要顺着连接链一直找到终点
- #define LOOKUP_DIRECTORY (2) //表示要寻找的目标必须是个目录
- #define LOOKUP_CONTINUE (4)
- #define LOOKUP_POSITIVE (8)
- #define LOOKUP_PARENT (16) //找到父节点
- #define LOOKUP_NOALT (32)
- struct nameidata {
- struct dentry *dentry;
- struct vfsmount *mnt;
- struct qstr last;
- unsigned int flags;
- int last_type;
- };
path_init,代码如下:
- int path_init(const char *name, unsigned int flags, struct nameidata *nd)
- {
- nd->last_type = LAST_ROOT; /* if there are only slashes... */
- nd->flags = flags;
- if (*name=='/')
- return walk_init_root(name,nd);//如果路径名是以"/"开头的绝对路径,那就要通过这个函数从根目录开始查找
- read_lock(¤t->fs->lock);
- nd->mnt = mntget(current->fs->pwdmnt);//如果路径名不以"/"开头,那就当前目录开始
- nd->dentry = dget(current->fs->pwd);
- read_unlock(¤t->fs->lock);
- return 1;
- }
- static inline int
- walk_init_root(const char *name, struct nameidata *nd)
- {
- read_lock(¤t->fs->lock);
- if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- nd->mnt = mntget(current->fs->altrootmnt);
- nd->dentry = dget(current->fs->altroot);
- read_unlock(¤t->fs->lock);
- if (__emul_lookup_dentry(name,nd))
- return 0;
- read_lock(¤t->fs->lock);
- }
- nd->mnt = mntget(current->fs->rootmnt);
- nd->dentry = dget(current->fs->root);
- read_unlock(¤t->fs->lock);
- return 1;
- }
- int path_walk(const char * name, struct nameidata *nd)//name为/usr/local/hello.c
- {
- struct dentry *dentry;
- struct inode *inode;
- int err;
- unsigned int lookup_flags = nd->flags;
- while (*name=='/')//跳过/usr/local/hello.c最开始的'/'
- name++;
- if (!*name)//如果只有'/',那么直接退出
- goto return_base;
- inode = nd->dentry->d_inode;//根节点的indode结构
- if (current->link_count)
- lookup_flags = LOOKUP_FOLLOW;//如果找到的目标只是"符号连接"到其它文件或者目录的一个目录项,则要顺着连接链一直找到终点
- /* At this point we know we have a real path component. */
- for(;;) {//第一次循环
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- err = permission(inode, MAY_EXEC);
- dentry = ERR_PTR(err);
- if (err)
- break;
- this.name = name;//已经指向了usr的首字符'u'
- c = *(const unsigned char *)name;
- hash = init_name_hash();
- do {
- name++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *)name;
- } while (c && (c != '/'));//如果字符c为空或者遇到了'/'则退出循环,本例中c指向的usr后面的'/'
- this.len = name - (const char *) this.name;//usr的长度
- this.hash = end_name_hash(hash);
- /* remove trailing slashes? */
- if (!c)//如果字符c为空,那么说明是最后一个节点,且最后一个节点是文件
- goto last_component;
- while (*++name == '/');//跳过'/'
- if (!*name)//如果'/'后面为空,那么说明这也是最后一个节点,且最后一个节点是目录
- goto last_with_slashes;
- /*
- * "." and ".." are special - ".." especially so because it has
- * to be able to know about the current root directory and
- * parent relationships.
- */
- if (this.name[0] == '.') switch (this.len) {//执行到这里,this代表中间节点,中间节点一定是目录
- default:
- break;
- case 2:
- if (this.name[1] != '.')//如果当前节点是..,那么要表示上一级目录
- break;
- follow_dotdot(nd);
- inode = nd->dentry->d_inode;
- /* fallthrough */
- case 1://如果当前的节点是 . ,表示当前目录
- continue;
- }
- /*
- * See if the low-level filesystem might want
- * to use its own hash..
- */
- if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {//如果有d_hash这个函数
- err = nd->dentry->d_op->d_hash(nd->dentry, &this);//使用这个函数,重新计算hash值
- if (err < 0)
- break;
- }
- /* This does the actual lookups.. */
- dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//在内存中寻找该节点业已建立的dentry结构
- if (!dentry) {//如果没有找到
- dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//那么就要建立该节点的dentry结构
- err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- break;
- }
- /* Check mountpoints.. */
- while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))//检查是否是挂载点
- ;
- err = -ENOENT;
- inode = dentry->d_inode;
- if (!inode)
- goto out_dput;
- err = -ENOTDIR;
- if (!inode->i_op)
- goto out_dput;
- if (inode->i_op->follow_link) {//看看这个指针是否为NULL,这个指针是在ext2_read_inode中设置的
- err = do_follow_link(dentry, nd);
- dput(dentry);
- if (err)
- goto return_err;
- err = -ENOENT;
- inode = nd->dentry->d_inode;
- if (!inode)
- break;
- err = -ENOTDIR;
- if (!inode->i_op)
- break;
- } else {
- dput(nd->dentry);
- nd->dentry = dentry;//如果没有,直接附给nd->dentry
- }
- err = -ENOTDIR;
- if (!inode->i_op->lookup)//iop指针也是ext2_read_inode中设置的为ext2_dir_inode_operations,因为当前/usr为目录节点,所以一定要有ext2_lookup这个指针
- break;
- continue;
- /* here ends the main loop */
- last_with_slashes:
- ......
- last_component:
- ......
- }
- struct qstr {
- const unsigned char * name;
- unsigned int len;
- unsigned int hash;
- };
cached_lookup,在内存中寻找该节点业已建立的dentry结构,代码如下:
- static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
- {
- struct dentry * dentry = d_lookup(parent, name);
- if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
- if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
- dput(dentry);
- dentry = NULL;
- }
- }
- return dentry;
- }
- 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;
- struct list_head *head = d_hash(parent,hash);
- struct list_head *tmp;
- spin_lock(&dcache_lock);
- tmp = head->next;
- for (;;) {
- struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
- if (tmp == head)
- break;
- tmp = tmp->next;
- if (dentry->d_name.hash != hash)//比较hash值
- continue;
- if (dentry->d_parent != parent)//比较父节点的dentry结构是否一样
- continue;
- if (parent->d_op && parent->d_op->d_compare) {
- if (parent->d_op->d_compare(parent, &dentry->d_name, name))
- continue;
- } else {
- if (dentry->d_name.len != len)//比较长度
- continue;
- if (memcmp(dentry->d_name.name, str, len))//比较名字
- continue;
- }
- __dget_locked(dentry);
- dentry->d_flags |= DCACHE_REFERENCED;
- spin_unlock(&dcache_lock);
- return dentry;//如果找到则返回节点的dentry结构
- }
- spin_unlock(&dcache_lock);
- return NULL;//如果没有找到,返回NULL
- }
- static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
- {
- hash += (unsigned long) parent / L1_CACHE_BYTES;
- hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
- return dentry_hashtable + (hash & D_HASHMASK);
- }
如果没有找到,那么要建立该节点的dentry结构,real_lookup代码如下:
- static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
- {
- struct dentry * result;
- struct inode *dir = parent->d_inode;
- down(&dir->i_sem);
- /*
- * First re-do the cached lookup just in case it was created
- * while we waited for the directory semaphore..
- *
- * FIXME! This could use version numbering or similar to
- * avoid unnecessary cache lookups.
- */
- result = d_lookup(parent, name);//再一次在内存中寻找该节点业已建立的dentry结构
- if (!result) {//如果还是没有找到
- struct dentry * dentry = d_alloc(parent, name);//分配该节点的dentry结构
- result = ERR_PTR(-ENOMEM);
- if (dentry) {
- lock_kernel();
- result = dir->i_op->lookup(dir, dentry);//分配该节点的inode结构,并挂在dentry结构上
- unlock_kernel();
- if (result)
- dput(dentry);
- else
- result = dentry;
- }
- up(&dir->i_sem);
- return result;
- }
- /*
- * Uhhuh! Nasty case: the cache was re-populated while
- * we waited on the semaphore. Need to revalidate.
- */
- up(&dir->i_sem);
- if (result->d_op && result->d_op->d_revalidate) {
- if (!result->d_op->d_revalidate(result, flags) && !d_invalidate(result)) {
- dput(result);
- result = ERR_PTR(-ENOENT);
- }
- }
- return result;
- }
- struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
- {
- char * str;
- struct dentry *dentry;
- dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); //分配了dentry结构
- if (!dentry)
- return NULL;
- if (name->len > DNAME_INLINE_LEN-1) {
- str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
- if (!str) {
- kmem_cache_free(dentry_cache, dentry);
- return NULL;
- }
- } else
- str = dentry->d_iname;
- memcpy(str, name->name, name->len);
- str[name->len] = 0;
- atomic_set(&dentry->d_count, 1);
- dentry->d_flags = 0;
- dentry->d_inode = NULL;
- dentry->d_parent = NULL;
- dentry->d_sb = NULL;
- dentry->d_name.name = str;//名字
- dentry->d_name.len = name->len;//长度
- dentry->d_name.hash = name->hash;//hash值
- dentry->d_op = NULL;
- dentry->d_fsdata = NULL;
- INIT_LIST_HEAD(&dentry->d_vfsmnt);//见下面关于dentry的说明
- INIT_LIST_HEAD(&dentry->d_hash);
- INIT_LIST_HEAD(&dentry->d_lru);
- INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_LIST_HEAD(&dentry->d_alias);
- if (parent) {
- dentry->d_parent = dget(parent);
- dentry->d_sb = parent->d_sb;
- spin_lock(&dcache_lock);
- list_add(&dentry->d_child, &parent->d_subdirs);
- spin_unlock(&dcache_lock);
- } else
- INIT_LIST_HEAD(&dentry->d_child);
- dentry_stat.nr_dentry++;
- return dentry;
- }
- struct dentry {
- atomic_t d_count;
- unsigned int d_flags;
- struct inode * d_inode; /* Where the name belongs to - NULL is negative */
- struct dentry * d_parent; /* parent directory */
- struct list_head d_vfsmnt;
- struct list_head d_hash; /* lookup hash list */
- struct list_head d_lru; /* d_count = 0 LRU list */
- struct list_head d_child; /* child of parent list */
- struct list_head d_subdirs; /* our children */
- struct list_head d_alias; /* inode alias list */
- struct qstr d_name;
- unsigned long d_time; /* used by d_revalidate */
- struct dentry_operations *d_op;
- struct super_block * d_sb; /* The root of the dentry tree */
- unsigned long d_reftime; /* last time referenced */
- void * d_fsdata; /* fs-specific data */
- unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
- };
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。代码如下:
- static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
- {
- struct inode * inode;
- struct ext2_dir_entry_2 * de;
- struct buffer_head * bh;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);//根据父节点的inode结构中inode->u.ext2_i.i_data找到对应的目录项
- inode = NULL;
- if (bh) {
- unsigned long ino = le32_to_cpu(de->inode);//得到该节点inode结构的节点号
- brelse (bh);
- inode = iget(dir->i_sb, ino);//通过这个节点号寻找该节点的inode结构
- if (!inode)
- return ERR_PTR(-EACCES);
- }
- d_add(dentry, inode);//把该节点的inode结构和dentry连接在一起
- return NULL;
- }
- struct ext2_dir_entry_2 {
- __u32 inode; /* Inode number */
- __u16 rec_len; /* Directory entry length */
- __u8 name_len; /* Name length */
- __u8 file_type;
- char name[EXT2_NAME_LEN]; /* File name */
- };
然后根据de->inode,得到该节点inode结构的节点号,通过这个节点号寻找该节点的inode结构,iget如下:
- static inline struct inode *iget(struct super_block *sb, unsigned long ino)
- {
- return iget4(sb, ino, NULL, NULL);
- }
- struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
- {
- struct list_head * head = inode_hashtable + hash(sb,ino);
- struct inode * inode;
- spin_lock(&inode_lock);
- inode = find_inode(sb, ino, head, find_actor, opaque);//在杂凑表队列中寻找
- if (inode) {//找到了
- __iget(inode);//递增计数
- spin_unlock(&inode_lock);
- wait_on_inode(inode);
- return inode;
- }
- spin_unlock(&inode_lock);
- /*
- * get_new_inode() will do the right thing, re-trying the search
- * in case it had to block at any point.
- */
- return get_new_inode(sb, ino, head, find_actor, opaque);//分配一个新的该节点的inode结构
- }
- static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
- {
- struct list_head *tmp;
- struct inode * inode;
- tmp = head;
- for (;;) {
- tmp = tmp->next;
- inode = NULL;
- if (tmp == head)
- break;
- inode = list_entry(tmp, struct inode, i_hash);
- if (inode->i_ino != ino)//对比节点号
- continue;
- if (inode->i_sb != sb)//和超级块结构
- continue;
- if (find_actor && !find_actor(inode, ino, opaque))
- continue;
- break;
- }
- return inode;
- }
- static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
- {
- struct inode * inode;
- inode = alloc_inode();
- if (inode) {
- struct inode * old;
- spin_lock(&inode_lock);
- /* We released the lock, so.. */
- old = find_inode(sb, ino, head, find_actor, opaque);//再一次在杂凑表队列中寻找
- if (!old) {//如果没有找到
- inodes_stat.nr_inodes++;
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_hash, head);//加入到对应的hash表
- inode->i_sb = sb;//超级块结构
- inode->i_dev = sb->s_dev;//设备号
- inode->i_ino = ino;//节点号
- inode->i_flags = 0;
- atomic_set(&inode->i_count, 1);
- inode->i_state = I_LOCK;
- spin_unlock(&inode_lock);
- clean_inode(inode);
- sb->s_op->read_inode(inode);
- /*
- * This is special! We do not need the spinlock
- * when clearing I_LOCK, because we're guaranteed
- * that nobody else tries to do anything about the
- * state of the inode when it is locked, as we
- * just created it (so there can be no old holders
- * that haven't tested I_LOCK).
- */
- inode->i_state &= ~I_LOCK;
- wake_up(&inode->i_wait);
- return inode;
- }
- /*
- * Uhhuh, somebody else created the same inode under
- * us. Use the old inode instead of the one we just
- * allocated.
- */
- __iget(old);//如果找到了inode结构
- spin_unlock(&inode_lock);
- destroy_inode(inode);
- inode = old;//使用找到的inode结构
- wait_on_inode(inode);
- }
- return inode;
- }
- #define alloc_inode() \
- ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
动态的inode结构:
- struct inode {
- struct list_head i_hash;
- struct list_head i_list;
- struct list_head i_dentry;
- struct list_head i_dirty_buffers;
- unsigned long i_ino;
- atomic_t i_count;
- kdev_t i_dev;
- umode_t i_mode;
- nlink_t i_nlink;
- uid_t i_uid;
- gid_t i_gid;
- kdev_t i_rdev;
- loff_t i_size;
- time_t i_atime;
- time_t i_mtime;
- time_t i_ctime;
- unsigned long i_blksize;
- unsigned long i_blocks;
- unsigned long i_version;
- struct semaphore i_sem;
- struct semaphore i_zombie;
- struct inode_operations *i_op;
- struct file_operations *i_fop; /* former ->i_op->default_file_ops */
- struct super_block *i_sb;
- wait_queue_head_t i_wait;
- struct file_lock *i_flock;
- struct address_space *i_mapping;
- struct address_space i_data;
- struct dquot *i_dquot[MAXQUOTAS];
- struct pipe_inode_info *i_pipe;
- struct block_device *i_bdev;
- unsigned long i_dnotify_mask; /* Directory notify events */
- struct dnotify_struct *i_dnotify; /* for directory notifications */
- unsigned long i_state;
- unsigned int i_flags;
- unsigned char i_sock;
- atomic_t i_writecount;
- unsigned int i_attr_flags;
- __u32 i_generation;
- union {
- struct minix_inode_info minix_i;
- struct ext2_inode_info ext2_i;
- struct hpfs_inode_info hpfs_i;
- struct ntfs_inode_info ntfs_i;
- struct msdos_inode_info msdos_i;
- struct umsdos_inode_info umsdos_i;
- struct iso_inode_info isofs_i;
- struct nfs_inode_info nfs_i;
- struct sysv_inode_info sysv_i;
- struct affs_inode_info affs_i;
- struct ufs_inode_info ufs_i;
- struct efs_inode_info efs_i;
- struct romfs_inode_info romfs_i;
- struct shmem_inode_info shmem_i;
- struct coda_inode_info coda_i;
- struct smb_inode_info smbfs_i;
- struct hfs_inode_info hfs_i;
- struct adfs_inode_info adfs_i;
- struct qnx4_inode_info qnx4_i;
- struct bfs_inode_info bfs_i;
- struct udf_inode_info udf_i;
- struct ncp_inode_info ncpfs_i;
- struct proc_inode_info proc_i;
- struct socket socket_i;
- struct usbdev_inode_info usbdev_i;
- void *generic_ip;
- } u;
- }
- struct ext2_inode {
- __u16 i_mode; /* File mode */
- __u16 i_uid; /* Low 16 bits of Owner Uid */
- __u32 i_size; /* Size in bytes */
- __u32 i_atime; /* Access time */
- __u32 i_ctime; /* Creation time */
- __u32 i_mtime; /* Modification time */
- __u32 i_dtime; /* Deletion Time */
- __u16 i_gid; /* Low 16 bits of Group Id */
- __u16 i_links_count; /* Links count */
- __u32 i_blocks; /* Blocks count */
- __u32 i_flags; /* File flags */
- union {
- struct {
- __u32 l_i_reserved1;
- } linux1;
- struct {
- __u32 h_i_translator;
- } hurd1;
- struct {
- __u32 m_i_reserved1;
- } masix1;
- } osd1; /* OS dependent 1 */
- __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
- __u32 i_generation; /* File version (for NFS) */
- __u32 i_file_acl; /* File ACL */
- __u32 i_dir_acl; /* Directory ACL */
- __u32 i_faddr; /* Fragment address */
- union {
- struct {
- __u8 l_i_frag; /* Fragment number */
- __u8 l_i_fsize; /* Fragment size */
- __u16 i_pad1;
- __u16 l_i_uid_high; /* these 2 fields */
- __u16 l_i_gid_high; /* were reserved2[0] */
- __u32 l_i_reserved2;
- } linux2;
- struct {
- __u8 h_i_frag; /* Fragment number */
- __u8 h_i_fsize; /* Fragment size */
- __u16 h_i_mode_high;
- __u16 h_i_uid_high;
- __u16 h_i_gid_high;
- __u32 h_i_author;
- } hurd2;
- struct {
- __u8 m_i_frag; /* Fragment number */
- __u8 m_i_fsize; /* Fragment size */
- __u16 m_pad1;
- __u32 m_i_reserved2[2];
- } masix2;
- } osd2; /* OS dependent 2 */
- }
- void ext2_read_inode (struct inode * inode)
- {
- struct buffer_head * bh;
- struct ext2_inode * raw_inode;
- unsigned long block_group;
- unsigned long group_desc;
- unsigned long desc;
- unsigned long block;
- unsigned long offset;
- struct ext2_group_desc * gdp;
- if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
- inode->i_ino != EXT2_ACL_DATA_INO &&
- inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
- inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
- ext2_error (inode->i_sb, "ext2_read_inode",
- "bad inode number: %lu", inode->i_ino);
- goto bad_inode;
- }
- block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
- if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) {
- ext2_error (inode->i_sb, "ext2_read_inode",
- "group >= groups count");
- goto bad_inode;
- }
- group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
- desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
- bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
- if (!bh) {
- ext2_error (inode->i_sb, "ext2_read_inode",
- "Descriptor not loaded");
- goto bad_inode;
- }
- gdp = (struct ext2_group_desc *) bh->b_data;
- /*
- * Figure out the offset within the block group inode table
- */
- offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
- EXT2_INODE_SIZE(inode->i_sb);
- block = le32_to_cpu(gdp[desc].bg_inode_table) +
- (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
- if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
- ext2_error (inode->i_sb, "ext2_read_inode",
- "unable to read inode block - "
- "inode=%lu, block=%lu", inode->i_ino, block);
- goto bad_inode;
- }
- offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1);
- raw_inode = (struct ext2_inode *) (bh->b_data + offset);//根据节点号,找到硬盘上的ext2_inode结构
- inode->i_mode = le16_to_cpu(raw_inode->i_mode);//mode也来来源于ext2_inode结构
- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
- if(!(test_opt (inode->i_sb, NO_UID32))) {
- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
- }
- inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
- inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime = le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
- inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
- /* We now have enough fields to check if the inode was active or not.
- * This is needed because nfsd might try to access dead inodes
- * the test is that same one that e2fsck uses
- * NeilBrown 1999oct15
- */
- if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.ext2_i.i_dtime)) {
- /* this inode is deleted */
- brelse (bh);
- goto bad_inode;
- }
- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
- inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
- inode->i_version = ++event;
- inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);//联合体的ext2_i被复制
- inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
- inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
- inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
- inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
- if (S_ISDIR(inode->i_mode))
- inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
- else {
- inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high);
- inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
- }
- inode->i_generation = le32_to_cpu(raw_inode->i_generation);
- inode->u.ext2_i.i_block_group = block_group;
- /*
- * NOTE! The in-memory inode i_data array is in little-endian order
- * even on big-endian machines: we do NOT byteswap the block numbers!
- */
- for (block = 0; block < EXT2_N_BLOCKS; block++)
- inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
- if (inode->i_ino == EXT2_ACL_IDX_INO ||
- inode->i_ino == EXT2_ACL_DATA_INO)
- /* Nothing to do */ ;
- else if (S_ISREG(inode->i_mode)) {//根据不同的该节点的inode结构不同状态,设置不同的指针
- inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- inode->i_mapping->a_ops = &ext2_aops;
- } else if (S_ISDIR(inode->i_mode)) {//目前是目录
- inode->i_op = &ext2_dir_inode_operations;
- inode->i_fop = &ext2_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- if (!inode->i_blocks)
- inode->i_op = &ext2_fast_symlink_inode_operations;
- else {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &ext2_aops;
- }
- } else
- init_special_inode(inode, inode->i_mode,
- le32_to_cpu(raw_inode->i_block[0]));
- brelse (bh);
- inode->i_attr_flags = 0;
- if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
- inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
- inode->i_flags |= S_SYNC;
- }
- if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
- inode->i_attr_flags |= ATTR_FLAG_APPEND;
- inode->i_flags |= S_APPEND;
- }
- if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
- inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
- inode->i_flags |= S_IMMUTABLE;
- }
- if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
- inode->i_attr_flags |= ATTR_FLAG_NOATIME;
- inode->i_flags |= S_NOATIME;
- }
- return;
- bad_inode:
- make_bad_inode(inode);
- return;
- }
- struct inode_operations ext2_dir_inode_operations = {
- create: ext2_create,
- lookup: ext2_lookup,
- link: ext2_link,
- unlink: ext2_unlink,
- symlink: ext2_symlink,
- mkdir: ext2_mkdir,
- rmdir: ext2_rmdir,
- mknod: ext2_mknod,
- rename: ext2_rename,
- };
iget获取到该节点的inode结构后,就返回ext2_lookup,继续执行d_add(dentry, inode),把该节点的inode结构和dentry连接在一起。
- static __inline__ void d_add(struct dentry * entry, struct inode * inode)
- {
- d_instantiate(entry, inode);//该节点的inode结构和dentry连接在一起
- d_rehash(entry);//把dentry结构放入杂凑表的某一个队里中
- }
- void d_instantiate(struct dentry *entry, struct inode * inode)
- {
- spin_lock(&dcache_lock);
- if (inode)
- list_add(&entry->d_alias, &inode->i_dentry);//可能一个inode结构对应多个entry结构
- entry->d_inode = inode;//链接在一起了
- spin_unlock(&dcache_lock);
- }
- void d_rehash(struct dentry * entry)
- {
- struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
- spin_lock(&dcache_lock);
- list_add(&entry->d_hash, list);
- spin_unlock(&dcache_lock);
- }
- list_add(&inode->i_hash, head);
real_lookup返回该节点的dentry结构。然后检查是否是挂在点,如果不是nd->dentry被赋值为dentry。由于是目录节点,所有lookup指针不能为NULL。
第一轮循环,执行到这里,continue开始第二轮循环。
- if (!inode->i_op->lookup)
- break;
- continue;
第二轮循环,如下:
- int path_walk(const char * name, struct nameidata *nd)
- {
- struct dentry *dentry;
- struct inode *inode;
- int err;
- unsigned int lookup_flags = nd->flags;
- while (*name=='/')
- name++;
- if (!*name)
- goto return_base;
- inode = nd->dentry->d_inode;
- if (current->link_count)
- lookup_flags = LOOKUP_FOLLOW;
- /* At this point we know we have a real path component. */
- for(;;) {
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- err = permission(inode, MAY_EXEC);
- dentry = ERR_PTR(err);
- if (err)
- break;
- this.name = name;//指向local的第一个字符'l'
- c = *(const unsigned char *)name;
- hash = init_name_hash();
- do {
- name++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *)name;
- } while (c && (c != '/'));
- this.len = name - (const char *) this.name;//local的长度
- this.hash = end_name_hash(hash);//hash值
- /* remove trailing slashes? */
- if (!c)
- goto last_component;
- while (*++name == '/');
- if (!*name)
- goto last_with_slashes;
- /*
- * "." and ".." are special - ".." especially so because it has
- * to be able to know about the current root directory and
- * parent relationships.
- */
- if (this.name[0] == '.') switch (this.len) {
- default:
- break;
- case 2:
- if (this.name[1] != '.')
- break;
- follow_dotdot(nd);
- inode = nd->dentry->d_inode;
- /* fallthrough */
- case 1:
- continue;
- }
- /*
- * See if the low-level filesystem might want
- * to use its own hash..
- */
- if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
- err = nd->dentry->d_op->d_hash(nd->dentry, &this);
- if (err < 0)
- break;
- }
- /* This does the actual lookups.. */
- dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
- if (!dentry) {
- dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
- err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- break;
- }
- /* Check mountpoints.. */
- while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
- ;
- err = -ENOENT;
- inode = dentry->d_inode;
- if (!inode)
- goto out_dput;
- err = -ENOTDIR;
- if (!inode->i_op)
- goto out_dput;
- if (inode->i_op->follow_link) {
- err = do_follow_link(dentry, nd);
- dput(dentry);
- if (err)
- goto return_err;
- err = -ENOENT;
- inode = nd->dentry->d_inode;
- if (!inode)
- break;
- err = -ENOTDIR;
- if (!inode->i_op)
- break;
- } else {
- dput(nd->dentry);
- nd->dentry = dentry;
- }
- err = -ENOTDIR;
- if (!inode->i_op->lookup)
- break;
- continue;
- /* here ends the main loop */
- last_with_slashes:
- ......
- last_component:
- ......
- }
第二轮循环,也是执行到这里,continue开始第三轮循环:
- if (!inode->i_op->lookup)//由于/usr/local/hello.c,local仍然是目录节点
- break;
- continue;
- int path_walk(const char * name, struct nameidata *nd)
- {
- struct dentry *dentry;
- struct inode *inode;
- int err;
- unsigned int lookup_flags = nd->flags;
- while (*name=='/')
- name++;
- if (!*name)
- goto return_base;
- inode = nd->dentry->d_inode;
- if (current->link_count)
- lookup_flags = LOOKUP_FOLLOW;
- /* At this point we know we have a real path component. */
- for(;;) {
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- err = permission(inode, MAY_EXEC);
- dentry = ERR_PTR(err);
- if (err)
- break;
- this.name = name;//指向了hello.c的第一个字符'h'
- c = *(const unsigned char *)name;
- hash = init_name_hash();
- do {
- name++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *)name;
- } while (c && (c != '/'));
- this.len = name - (const char *) this.name;//hello.c的长度
- this.hash = end_name_hash(hash);
- /* remove trailing slashes? */
- if (!c)//c为NULL了
- goto last_component;
- while (*++name == '/');
- if (!*name)
- goto last_with_slashes;
- .....
- last_with_slashes:
- lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;//如果最后一个节点是目录,那么要加上这两个标志位
- last_component:
- if (lookup_flags & LOOKUP_PARENT)//这个标志位表示是要寻找父节点
- goto lookup_parent;
- if (this.name[0] == '.') switch (this.len) {//如果最后一个节点是目录,且是dot或者dotdot
- default:
- break;
- case 2:
- if (this.name[1] != '.')
- break;
- follow_dotdot(nd);
- inode = nd->dentry->d_inode;
- /* fallthrough */
- case 1:
- goto return_base;
- }
- if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
- err = nd->dentry->d_op->d_hash(nd->dentry, &this);
- if (err < 0)
- break;
- }
- dentry = cached_lookup(nd->dentry, &this, 0);
- if (!dentry) {
- dentry = real_lookup(nd->dentry, &this, 0);//本次寻找的节点是文件
- err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- break;
- }
- while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))//是否是挂载点
- ;
- inode = dentry->d_inode;
- if ((lookup_flags & LOOKUP_FOLLOW)//和第一次和第二次循环不同,必须LOOKUP_FOLLOW标志位置1
- && inode && inode->i_op && inode->i_op->follow_link) {
- err = do_follow_link(dentry, nd);
- dput(dentry);
- if (err)
- goto return_err;
- inode = nd->dentry->d_inode;
- } else {
- dput(nd->dentry);
- nd->dentry = dentry;//赋值给nd->dentry
- }
- err = -ENOENT;
- if (!inode)
- goto no_inode;
- if (lookup_flags & LOOKUP_DIRECTORY) {//如果最后一个节点是目录,也就是这个标志为置1的时候,还要检查指针是否为NULL
- err = -ENOTDIR;
- if (!inode->i_op || !inode->i_op->lookup)
- break;
- }
- goto return_base;
- no_inode:
- err = -ENOENT;
- if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
- break;
- goto return_base;
- lookup_parent: ////nd->dentry是父节点的dentry结构
- nd->last = this;//nd->last是最后一个节点的名字
- nd->last_type = LAST_NORM;//最后一个节点的类型
- if (this.name[0] != '.')
- goto return_base;
- if (this.len == 1)
- nd->last_type = LAST_DOT;
- else if (this.len == 2 && this.name[1] == '.')
- nd->last_type = LAST_DOTDOT;
- return_base:
- return 0;
- out_dput:
- dput(dentry);
- break;
- }
- path_release(nd);
- return_err:
- return err;
- }
- if (inode->i_ino == EXT2_ACL_IDX_INO ||
- inode->i_ino == EXT2_ACL_DATA_INO)
- /* Nothing to do */ ;
- else if (S_ISREG(inode->i_mode)) {//hello.c是文件,所以执行这段代码
- inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- inode->i_mapping->a_ops = &ext2_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ext2_dir_inode_operations;
- inode->i_fop = &ext2_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- if (!inode->i_blocks)
- inode->i_op = &ext2_fast_symlink_inode_operations;
- else {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &ext2_aops;
- }
- } else
- init_special_inode(inode, inode->i_mode,
- le32_to_cpu(raw_inode->i_block[0]));
- Linux内核源代码情景分析-从路径名到目标节点
- Linux内核源代码情景分析-从路径名到目标节点
- linux内核源代码情景分析
- 【文件管理】从路径名到目标节点
- Linux内核源代码情景分析-内存管理
- Linux内核源代码情景分析-中断上半部
- Linux内核源代码情景分析-异常
- Linux内核源代码情景分析-系统调用
- Linux内核源代码情景分析-fork()
- Linux内核源代码情景分析-wait()、schedule()
- Linux内核源代码情景分析-execve()
- Linux内核源代码情景分析-exit()
- Linux内核源代码情景分析-强制性调度
- Linux内核源代码情景分析-虚拟文件系统
- Linux内核源代码情景分析-信号
- Linux内核源代码情景分析-共享内存
- Linux内核源代码情景分析-交换分区
- Linux内核源代码情景分析-insmod
- 22
- innerHTML和innerText
- 51单片机--定时器测量脉宽
- 2017ACM/ICPC亚洲区沈阳站_Wandering Robots(hash)_马尔科夫链_随机游走
- 《武则天》书评
- Linux内核源代码情景分析-从路径名到目标节点
- 剑指offer
- redis之string(3)
- VirtualBox 安装 debian 或 kali 安装增强功能失败的解决方案
- 判断丑数
- classpath*:与classpath:的区别
- Hibernate中各种查询方法的总结
- 驱动框架,驱动模型
- idea Spring-boot三种启动方式