/* * 一、说明 * sysfs与设备、驱动相关。系统将驱动的层级结构通过sysfs以 * 文件系统的形式展现给用户。在驱动方面涉及到的概念有kobject, * kset,bus,device_driver,device,class等等;而在文件系统方面 * 涉及到的概念有inode,dentry,super_block,vfsmount等虚拟文件 * 系统方面的内容。既然sysfs也是一种文件系统,就必须提供虚拟 * 文件系统相关的数据结构。 * 各方面内容:用户-访问文件系统->VFS-访问实际文件系统->sysfs * --映射到->driver体系 */ /* * 二、sysfs文件系统的加载 */ //sysfs的mount// /* * 调用过程 * start_kernel(/init/main.c)->vfs_caches_init(/fs/dcache.c)-> * mnt_init(/fs/namespace.c)->sysfs_init * 在start_kernel中两个函数是文件系统初始化相关的: * vfs_caches_init_early(),vfs_caches_init(totalram_pages) */ /* * /fs/sysfs/mount.c * 几个全局变量 */ /* * 静态,本文件内函数用,vfsmount代表一个加载的文件系统 * 这是sysfs的源头,sysfs_mnt 可找到其根dentry,进而可找到inode,超级块等结构 * 生成这个结构的过程就是生成inode dentry super_block并使其相关联的过程。 */ static struct vfsmount *sysfs_mnt; //sysfs的sysfs_dirent缓存cache struct kmem_cache *sysfs_dir_cachep; //sysfs的super_block默认操作 static const struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .evict_inode = sysfs_evict_inode, }; /* * sysfs的根sysfs_dirent结构,此结构是联系kobject层级体系和vfs层级体系的桥梁 * 而sysfs_root对应的就是vfs中的根,即/sys/目录 */ struct sysfs_dirent sysfs_root = { .s_name = "", .s_count = ATOMIC_INIT(1), .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, .s_ino = 1, }; /* * sysfs的type,用来注册sysfs文件系统的全局变量,静态的,本文件内函数使用维护 */ static struct file_system_type sysfs_fs_type = { .name = "sysfs", .mount = sysfs_mount, .kill_sb = sysfs_kill_sb, } //初始化sysfs/// 目标:生成static struct vfsmount *sysfs_mnt// int __init sysfs_init(void) { int err = -ENOMEM; //cache缓存申请 sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", sizeof(struct sysfs_dirent), 0, 0, NULL); if (!sysfs_dir_cachep) goto out; /* * 备用存储设备初始化(bdi),用来存储数据的设备 */ err = sysfs_inode_init(); if (err) goto out_err; /* * 注册文件系统,就是将sysfs_fs_type对应的文件系统加入到内核全局变量 * file_system中,它定义在:/fs/filesystems.c文件中,是个静态的,只本文件 * 相关函数维护和访问 * static struct file_system_type *file_systems; * * 传入的参数是静态全局变量sysfs_fs_type */ err = register_filesystem(&sysfs_fs_type); if (!err) { /* * /include/linux/fs.h中定义: * #define kern_mount(type) kern_mount_data(type, NULL) * 本函数最终目的是将文件系统的 vfsmount结构 sysfs_mnt存储起来 * 核心就是取到这个结构的值,以备后用 * * 传入的参数是静态全局变量sysfs_fs_type */ sysfs_mnt = kern_mount(&sysfs_fs_type); if (IS_ERR(sysfs_mnt)) { printk(KERN_ERR "sysfs: could not mount!\n"); err = PTR_ERR(sysfs_mnt); sysfs_mnt = NULL; unregister_filesystem(&sysfs_fs_type); goto out_err; } } else goto out_err; out: return err; out_err: kmem_cache_destroy(sysfs_dir_cachep); sysfs_dir_cachep = NULL; goto out; } /mount vfsmount生成 /* * /fs/namespace.c中定义: * 调用vfs_kern_mount进一步处理 * * 传入的参数是静态全局变量sysfs_fs_type,data=NULL */ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { struct vfsmount *mnt; mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); if (!IS_ERR(mnt)) { real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL; } return mnt; } /* * vfsmount与mount结构:前者是后者的一个成员,都有dentry结构 vfsmount.dentry * mount.mnt_mountpoint都指向子文件系统(sysfs)的根dentry * * /fs/namespace.c中定义 *参数: * type=sysfs_fs_type * flags=MS_KERNMOUNT * name= type->name=sysfs_fs_type->name="sysfs" * data=NULL * * 本函数是取得struct vfsmount结构。但需要加载sysfs以取得sysfs的根dentry. * 将根dentry与要返回的vfsmount联系起来。 * 申请了一个mount,它体内有一个内嵌的vfsmount(不是指针型的),回头将它返回 * 也就是说返回的vfsmount是mount的一个成员结构,通过vfsmount就能找到mount */ struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct mount *mnt; struct dentry *root; if (!type) return ERR_PTR(-ENODEV); //申请一个struct mount结构 mnt = alloc_vfsmnt(name); if (!mnt) return ERR_PTR(-ENOMEM); if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; //得到本文件系统的根dentry root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { free_vfsmnt(mnt); return ERR_CAST(root); } mnt->mnt.mnt_root = root; mnt->mnt.mnt_sb = root->d_sb; mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; br_write_lock(&vfsmount_lock); //mount结构通过mnt_instance连接到超级块的s_mounts字段 list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); br_write_unlock(&vfsmount_lock); return &mnt->mnt; } /* * /fs/super.c中定义 * 参数: * type=sysfs_fs_type * flags=MS_KERNMOUNT * name= type->name=sysfs_fs_type->name="sysfs" * data=NULL * * 函数功能: * 根据type加载文件系统并返回它的root dentry */ struct dentry * mount_fs(struct file_system_type *type, int flags, const char *name, void *data) { struct dentry *root; struct super_block *sb; char *secdata = NULL; int error = -ENOMEM; if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { secdata = alloc_secdata(); if (!secdata) goto out; error = security_sb_copy_data(data, secdata); if (error) goto out_free_secdata; } /* * 调用type的mount函数,. * 即sysfs_fs_type->mount=sysfs_mount()[/fs/sysfs/mount.c] * 整个过程像是这样:对VFS来说,它只要知道文件系统相关信息,并存储起来 * 且vfs调用自己定义好的接口来实现mount(其它操作也一样),具体功能 * 由具体的文件系统自己定义,只要接口保持一致就行。 * 对sysfs来说,它提供具体相关结构的生成,还得靠自己的函数。这些结构 * 包括dentry..super_block..mount..vfsmount等,只是把这些信息放在了 * 文件系统类型sysfs_fs_type中,等待VFS体系来调用罢了。说白了自己让别人 * 管自己,最后还是自己劳动。 */ root = type->mount(type, flags, name, data); if (IS_ERR(root)) { error = PTR_ERR(root); goto out_free_secdata; } sb = root->d_sb; BUG_ON(!sb); WARN_ON(!sb->s_bdi); WARN_ON(sb->s_bdi == &default_backing_dev_info); sb->s_flags |= MS_BORN; error = security_sb_kern_mount(sb, flags, secdata); if (error) goto out_sb; ...... up_write(&sb->s_umount); free_secdata(secdata); return root; out_sb: dput(root); deactivate_locked_super(sb); out_free_secdata: free_secdata(secdata); out: return ERR_PTR(error); } /* * /fs/sysfs/mount.c * * fs_type=sysfs_fs_type * flags=MS_KERNMOUNT * dev_name= type->name=sysfs_fs_type->name="sysfs" * data=NULL * * 函数功能: * 加载sysfs文件系统,并返回sysfs的root dentry * sb = sget取得super_block * sysfs_fill_super(sb填充sb,并组织与sb相关的根inode dentry以及与 * 根dirent sysfs_root关联起来 * 最后将根dentry返回 */ static struct dentry *sysfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct sysfs_super_info *info; enum kobj_ns_type type; struct super_block *sb; int error; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); //命名空间相关 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) info->ns[type] = kobj_ns_grab_current(type); //查询取得,或新创建一个super_block sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); if (IS_ERR(sb) || sb->s_fs_info != info) free_sysfs_super_info(info); if (IS_ERR(sb)) return ERR_CAST(sb); if (!sb->s_root) { //新创建的sb,s_root肯定为空,则需要填充super_block error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); } //超级块生成 /* * 在/fs/super.c中定义: * fs_type=sysfs_fs_type * sysfs_test_super * sysfs_set_super * flags=MS_KERNMOUNT * data=NULL * * 函数功能: * 在type的super_blocks列表中查找或新创建一个属于type的super_block */ struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), int flags, void *data) { struct super_block *s = NULL; struct hlist_node *node; struct super_block *old; int err; retry: spin_lock(&sb_lock); if (test) { hlist_for_each_entry(old, node, &type->fs_supers, s_instances) { //test不断失败,直到循环结束,old是迭代指针,列表是type->fs_supers if (!test(old, data)) continue; if (!grab_super(old)) goto retry; if (s) { up_write(&s->s_umount); destroy_super(s); s = NULL; } down_write(&old->s_umount); if (unlikely(!(old->s_flags & MS_BORN))) { deactivate_locked_super(old); goto retry; } return old; } } //新建的话,s肯定是null if (!s) { spin_unlock(&sb_lock); //申请一个空super_block s = alloc_super(type, flags); if (!s) return ERR_PTR(-ENOMEM); goto retry; } //设置好s的数据 err = set(s, data); if (err) { spin_unlock(&sb_lock); up_write(&s->s_umount); destroy_super(s); return ERR_PTR(err); } //设置type,名称,并添加到全系统全局变量super_blocks中去 s->s_type = type; strlcpy(s->s_id, type->name, sizeof(s->s_id)); list_add_tail(&s->s_list, &super_blocks); hlist_add_head(&s->s_instances, &type->fs_supers); spin_unlock(&sb_lock); get_filesystem(type); //内存管理 register_shrinker(&s->s_shrink); return s; } /* * 定义在:/fs/sysfs/mount.c * super_block=申请的那个超级块 * data=NULL * silent=flags & MS_SILENT ? 1 : 0 * * 函数功能: * 给sysfs的super_block填充内容; 根据super_block和sysfs_root这个根dirent * 生成根dentry root的inode。最终将 super_block sysfs_root root dentry * inode 关联起来,就是将VFS需要的那几项组织起来。虽然返回super_block, * 但与super_block相关的内容都处理好了。 */ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct dentry *root; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = SYSFS_MAGIC; sb->s_op = &sysfs_ops; sb->s_time_gran = 1; /* get root inode, initialize and unlock it */ mutex_lock(&sysfs_mutex); //生成根dentry root的inode inode = sysfs_get_inode(sb, &sysfs_root); mutex_unlock(&sysfs_mutex); if (!inode) { pr_debug("sysfs: could not get root inode\n"); return -ENOMEM; } //根据根inode生成根 dentry root = d_make_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); return -ENOMEM; } root->d_fsdata = &sysfs_root; sb->s_root = root; sb->s_d_op = &sysfs_dentry_ops; return 0; } ///由全局变量sysfs_dirent sysfs_root生成inode/// /* * /fs/sysfs/inode.c * 参数: * sb=sysfs的那个super_block * sysfs_dirent=sysfs_root * * 函数功能: * 由sysfs_dirent生成一个inode * 再看看sysfs_root的定义(/fs/sysfs/mount.c) * struct sysfs_dirent sysfs_root = { * .s_name = "", * .s_count = ATOMIC_INIT(1), * .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), * .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, * .s_ino = 1, * }; */ struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) { struct inode *inode; //由一个加载的文件系统获得一个inode,由上可知传进去的s_ino=1 inode = iget_locked(sb, sd->s_ino); if (inode && (inode->i_state & I_NEW)) sysfs_init_inode(sd, inode); //初始化这个inode return inode; } /* * 静态全局变量,inode hash列表,inode_hashtable[hash]是一个相同hash值=hash的列表 */ static struct hlist_head *inode_hashtable __read_mostly; /* * /fs/inode.c: * 参数: * sb=sysfs的超级块 * ino=sysfs_root.s_ino=1 * * 函数功能: * 从一个加载的文件系统中申请一个inode出来 * 用到静态全局变量inode_hashtable */ struct inode *iget_locked(struct super_block *sb, unsigned long ino) { struct hlist_head *head = inode_hashtable + hash(sb, ino); struct inode *inode; //@@@@第一次锁申请 spin_lock(&inode_hash_lock); //1号inode还没生成,当然找不到了 inode = find_inode_fast(sb, head, ino); //@@@@第一次锁释放 spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); return inode; } //生成1号inode,申请inode空间并初始化 inode = alloc_inode(sb); if (inode) { struct inode *old; //@@@@第二次锁申请 spin_lock(&inode_hash_lock); /* * 因为在两次加锁中间可能有别人申请了本号码的inode, * 所以再查找一次 */ old = find_inode_fast(sb, head, ino); if (!old) { //如果没找到,就用我们刚才申请的的inode inode->i_ino = ino; spin_lock(&inode->i_lock); //设置状态 inode->i_state = I_NEW; hlist_add_head(&inode->i_hash, head); spin_unlock(&inode->i_lock); inode_sb_list_add(inode); spin_unlock(&inode_hash_lock); /* Return the locked inode with I_NEW set, the * caller is responsible for filling in the contents */ return inode; } /* * Uhhuh, somebody else created the same inode under * us. Use the old inode instead of the one we just * allocated. * 执行到这里说明有别人在两锁中间申请了本号码的inode * 则把我们申请的释放掉,然后用别人的那个(old) */ spin_unlock(&inode_hash_lock); destroy_inode(inode); inode = old; wait_on_inode(inode); } return inode; } /* * 在fs/sysfs/inode.c中: */ static const struct address_space_operations sysfs_aops = { .readpage = simple_readpage, .write_begin = simple_write_begin, .write_end = simple_write_end, }; static struct backing_dev_info sysfs_backing_dev_info = { .name = "sysfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; static const struct inode_operations sysfs_inode_operations ={ .permission = sysfs_permission, .setattr = sysfs_setattr, .getattr = sysfs_getattr, .setxattr = sysfs_setxattr, }; /* * 在fs/sysfs/inode.c中: * 参数 * sd=sysfs_root * inode=与sysfs_root对应的1号inode * 功能:初始化inode * 再看看sysfs_root的定义(/fs/sysfs/mount.c) * struct sysfs_dirent sysfs_root = { * .s_name = "", * .s_count = ATOMIC_INIT(1), * .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), * .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, * .s_ino = 1, * }; */ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { struct bin_attribute *bin_attr; /* * i_private字段存储inode与文件系统相关的信息,在sysfs中存储的是sysfs_dirent结构 */ inode->i_private = sysfs_get(sd); inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; set_default_inode_attr(inode, sd->s_mode); sysfs_refresh_inode(sd, inode); /* initialize inode according to type */ switch (sysfs_type(sd)) { case SYSFS_DIR: /* * sysfs_root的s_flags是SYSFS_DIR,所以i_op和i_fop指向相应位置 */ inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; break; case SYSFS_KOBJ_ATTR: inode->i_size = PAGE_SIZE; inode->i_fop = &sysfs_file_operations; break; case SYSFS_KOBJ_BIN_ATTR: bin_attr = sd->s_bin_attr.bin_attr; inode->i_size = bin_attr->size; inode->i_fop = &bin_fops; break; case SYSFS_KOBJ_LINK: inode->i_op = &sysfs_symlink_inode_operations; break; default: BUG(); } unlock_new_inode(inode); } /由sysfs_root dirent对应的inode生成dentry/// /* * /fs/dcache.c: * 参数:sysfs_root dirent对应的inode * 功能:生成对应的dentry */ struct dentry *d_make_root(struct inode *root_inode) { struct dentry *res = NULL; if (root_inode) { //name变量="/" static const struct qstr name = QSTR_INIT("/", 1); //在sb中申请出一个dentry res = __d_alloc(root_inode->i_sb, &name); if (res) //用inode信息初始化,使之与root_inode关联 d_instantiate(res, root_inode); else iput(root_inode); } return res; } /* * /fs/dcache.c: * 从文件系统申请一个dentry */ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) { struct dentry *dentry; char *dname; //内存申请 dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; //名称串内存申请 dentry->d_iname[DNAME_INLINE_LEN-1] = 0; if (name->len > DNAME_INLINE_LEN-1) { dname = kmalloc(name->len + 1, GFP_KERNEL); if (!dname) { kmem_cache_free(dentry_cache, dentry); return NULL; } } else { dname = dentry->d_iname; } //名字复制 dentry->d_name.len = name->len; dentry->d_name.hash = name->hash; memcpy(dname, name->name, name->len); dname[name->len] = 0; /* Make sure we always see the terminating NUL character */ smp_wmb(); //名字指针赋值 dentry->d_name.name = dname; //下面是各种初始化 dentry->d_count = 1; dentry->d_flags = 0; spin_lock_init(&dentry->d_lock); seqcount_init(&dentry->d_seq); dentry->d_inode = NULL; dentry->d_parent = dentry; dentry->d_sb = sb; dentry->d_op = NULL; dentry->d_fsdata = NULL; INIT_HLIST_BL_NODE(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); INIT_LIST_HEAD(&dentry->d_subdirs); INIT_HLIST_NODE(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); d_set_d_op(dentry, dentry->d_sb->s_d_op); this_cpu_inc(nr_dentry); return dentry; } /* * 最终生成了使vfsmount sysfs_mnt=mount.mnt这个全局变量得到赋值后 * 以后要找sysfs便可从sysfs_mnt找。因为它是静态的,所以它的值是由 * 模块内函数维护的。VFS对一个文件系统要求的inode_root,dentry_root, * super_block等都可以从这个变量找到。 * 具体的inode和dentry是在sysfs_lookup时才生成的,没有事先生成。先 * 操作dirent的层次,最后返回基于dirent的dentry * * */ /* * 三、设备驱动模块kobject等 */ /* * 关系: * kset: * 向下:指向子节点链表 kset->list * 自己:kobj对应,因此kobject不是个指针,所以本kobj能定位到自己的kset * 向上: kobj->parent,kobj->kset(父级kset) * kobject: * 向上: kobject->parent * 横向: entry链入兄弟链表,进入父kset的list字段 * sysfs_dirent: * 向上: parent, * 向下: s_dir.children(只能是目录) * 横向: s_rb * * * kobject->sd 指向对应的sysfs_dirent结构 * sysfs_dirent->s_ino指向对应的inode号 * inode->i_private存储其对应的sysfs_dirent结构 * dentry->d_fsdata指向对应的sysfs_dirent结构 * inode->i_dentry指向对应dentry列表 * dentry->d_inode指向对应的inode * * kset{kobject} * ^ 7 * |/ * v * kobject---->sysfs_dirent<------>inode * ^1 * | * v n * sysfs_dirent<------dentry */ /* * kset 是管理kobject的集合,自身体内含有一个kobject,是kset所包含 * 子kobject集合的父亲。kset还可以包含其它的kset(kset->kobj->kset?) */ struct kset {//在sysfs目录结构中,kset是个目录 struct list_head list;//子层kobject链表 spinlock_t list_lock; struct kobject kobj;//本层kobject,代表sysfs目录结构中的自己 const struct kset_uevent_ops *uevent_ops; }; struct kobject { const char *name;//设备名 struct list_head entry;//链入kset(兄弟链) struct kobject *parent;//父对象 struct kset *kset;//本对象所属的kset(父集链) struct kobj_type *ktype;//对象类型描述符 /* * dentry,inode相关字段,组成sysfs文件系统层级关系 * 每个sysfs节点有一个sysfs_dirent结构 */ struct sysfs_dirent *sd; struct kref kref;//引用计数 unsigned int state_initialized:1; unsigned int state_in_sysfs:1;//说明本节点在sysfs中有对应 unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; }; /* * kobject与vfs关联 * inode->i_private存储其对应的sysfs_dirent结构 * sysfs_dirent.s_ino对应inode节点号 * 向上有parent,向下(只能是目录)有s_dir.children * 横向兄弟有s_rb * 这样就形成了一个层级结构 */ struct sysfs_dirent { atomic_t s_count; atomic_t s_active; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif struct sysfs_dirent *s_parent;//父节点 const char *s_name; //兄弟节点,链入父节点的s_dir.children字段 struct rb_node s_rb; union { struct completion *completion; struct sysfs_dirent *removed_list; } u; const void *s_ns; /* namespace tag */ unsigned int s_hash; /* ns + name hash */ union { struct sysfs_elem_dir s_dir;//目录级联用 struct sysfs_elem_symlink s_symlink; struct sysfs_elem_attr s_attr; struct sysfs_elem_bin_attr s_bin_attr; }; /* * s_flags表明在sysfs中的类型 * SYSFS_DIR,SYSFS_KOBJ_ATTR, SYSFS_KOBJ_BIN_ATTR,SYSFS_KOBJ_LINK */ unsigned short s_flags; umode_t s_mode; unsigned int s_ino;//对应的inode节点id号 struct sysfs_inode_attrs *s_iattr; }; /* * sysfs_dirent与dentry的关联,dentry的层次与kobject相同 * kobject形成设备、驱动层次,而dentry负责在stsfs中将这个 * 层次以文件的形式展示出来 * 在v3.6.2/fs/sysfs/inode.c中 * sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) * 根据sysfs_dirent生成inode */ dentry->d_fsdata是void指针,指向sysfs_dirent struct kobj_type { void (*release)(struct kobject *kobj);//资源释放 const struct sysfs_ops *sysfs_ops;//操作 struct attribute **default_attrs;//默认属性 const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); const void *(*namespace)(struct kobject *kobj); }; struct sysfs_ops { //用户读取数据 ssize_t (*show)(struct kobject *, struct attribute *,char *); //用户写入数据 ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); const void *(*namespace)(struct kobject *, const struct attribute *); }; //在http://lxr.linux.no/linux+v3.6.2/include/linux/kobject.h中: extern const struct sysfs_ops kobj_sysfs_ops; //在http://lxr.linux.no/linux+v3.6.2/lib/kobject.c中: const struct sysfs_ops kobj_sysfs_ops = { .show = kobj_attr_show, .store = kobj_attr_store, }; struct attribute { const char *name;//sysfs目录中的文件名 umode_t mode; #ifdef CONFIG_DEBUG_LOCK_ALLOC bool ignore_lockdep:1; struct lock_class_key *key; struct lock_class_key skey; #endif }; /* * 每个bus_type对应/sys/bus下一个子目录,如/sys/bus/pci * 每个子目录下有两个目录devices,drivers; 前者表示总线上所有设备; * 后者表示与该总线相"关联"的所有驱动程序。另外就是几个处理函数。 * * 一些结构: * bus_type ->device *dev_root; * device ->device*parent指向父设备 ->kobj ->type设备类型 ->bus总线 ->device_driver *driver申请本结构的驱动程序 ->class设备的class * device_driver ->bus_type *bus指向bus * class ->dev_kobj代表class链入层级关系 */ struct bus_type {//系统总线结构 const char *name;//名称 const char *dev_name;//设备名 struct device *dev_root;//默认根设备 struct bus_attribute *bus_attrs;//默认总线属性 struct device_attribute *dev_attrs;//总线上默认设备属性 struct driver_attribute *drv_attrs;//总线上默认设备驱动属性 int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct iommu_ops *iommu_ops; struct subsys_private *p;//驱动抽象中:bus私有数据 }; /* * http://lxr.linux.no/linux+v3.6.2/drivers/base/base.h中: * subsys_private,driver_private,device_private */ struct subsys_private { struct kset subsys;//回指定义本subsys的kset struct kset *devices_kset;//device目录 struct list_head interfaces; struct mutex mutex; struct kset *drivers_kset;//driver目录? struct klist klist_devices;//用来遍历devices_kset struct klist klist_drivers;//用来遍历drivers_kset //本bus有事件的话,就会通知本链上函数 struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus;//本结构所相关的bus_type struct kset glue_dirs; struct class *class;//本结构相关的class }; struct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; }; struct device_private { struct klist klist_children; struct klist_node knode_parent; struct klist_node knode_driver; struct klist_node knode_bus; struct list_head deferred_probe; void *driver_data; struct device *device; }; /* * kset代表一个目录,它体内的kobject与sysfs关联 * 子kobject代表sysfs中的一个文件 * subsys_private与bus对应,subsys_private体内有两个子kset代表两个子目录 * devices与drivers。 * device_private与device结构对应,而device体内有kobject,代表一个设备 * driver_private与device_driver对应,driver_private有kobject代表一个驱动 * * 分了3类东西, * 第1类在include/linux/kobject.h中,是kset,kobject,sysfs_dirent(与sysfs关联) * 第2类在include/linux/device.h中, 是bus_type,device,device_driver,class * 第3类在drivers/base/base.h中,是subsys_private,driver_private,device_private * 1在抽象,2是设备,3是驱动 * kset含有kobject: ->kobj 本层 ->list 子层 bus的subsys_private有两个kset ->devices_kset 总线上的设备集合 ->drivers_kset 总线相关的驱动集合 device有个kobject ->kobj 本设备对象的kobject driver_private有个kobject ->kobj 本驱动对象的kobject * */ /* * 二、过程 * * 一些全局变量 * /drivers/base/core.c: struct kset *devices_kset;系统内所有设备,对应/sys/devices/ /drivers/base/bus.c: 这里的两个是静态的,说明只在本文件中有效,也就是只有用本文件中的函数 才能访问。 static struct kset *bus_kset;系统内所有总线,对应/sys/bus/ static struct kset *system_kset;所有子系统,对应/sys/devices/system start_kernel->rest_init-创建进程->kernel_init(pid=1)->do_basic_setup ->driver_init[v3.6.2/drivers/base/init.c]->buses_init 实际上在driver_init时就涉及许多设备驱动相关的初始化 */ void __init driver_init(void) { devtmpfs_init(); devices_init();//设备初始化 buses_init();//这就是总线初始化 classes_init(); firmware_init(); hypervisor_init(); platform_bus_init(); cpu_dev_init(); memory_dev_init(); } /* * /sys/是sysfs的根,下面的函数就是在根下放几个目录:/sys/devices/,/sys/dev/, * /sys/dev/block/和/sys/dev/char/这几个目录都是"设备(device)相关"的。 */ int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); if (!devices_kset) return -ENOMEM; dev_kobj = kobject_create_and_add("dev", NULL); if (!dev_kobj) goto dev_kobj_err; sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); if (!sysfs_dev_block_kobj) goto block_kobj_err; sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); if (!sysfs_dev_char_kobj) goto char_kobj_err; return 0; char_kobj_err: kobject_put(sysfs_dev_block_kobj); block_kobj_err: kobject_put(dev_kobj); dev_kobj_err: kset_unregister(devices_kset); return -ENOMEM; } /* * 与上面函数类似,此函数功能是创添加了/sys/bus/和/sys/devices/system/ */ int __init buses_init(void) { //最后一个参数是parent_kobj,就是父节点的kobject,null就直接挂根上/sys/bus/ bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); if (!bus_kset) return -ENOMEM; //父节点为devices_kset->kobj,所以是在/sys/devices/下挂着 system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); if (!system_kset) return -ENOMEM; return 0; } /* * 顺便提下subsys_system_register函数,在/drivers/base/bus.c中有一句: * EXPORT_SYMBOL_GPL(subsys_system_register);说明它是被其它模块调用的 * 一个subsys跟一个总线相关。所以此函数调用bus_register来注册一种类型 * 的总线bus_type * int subsys_system_register(struct bus_type *subsys, * const struct attribute_group **groups) * 子系统没理解好,子系统注册时用的就是bus_type,一个bus就是 * 一个子系统,一个子系统又可包含更广泛的概念?看代码好像是注册一个 * subsystem就是注册一个bus,因为调用了bus_register */ 添加dir/// /* * 添加kobject对应就是在sysfs添加一个目录,即/sys/xxx/,用函数: * 在v3.6.2/lib/kobject.c: * kset_create_and_add->kset_register->kobject_add_internal * 在kset_create_and_add里会创建一个kset并将它与父级kobject链起来。然后 * 再调用kset_register将本kobject加入sysfs并发送通知事件。 */ static int kobject_add_internal(struct kobject *kobj) { int error = 0; struct kobject *parent; if (!kobj)return -ENOENT; if (!kobj->name || !kobj->name[0]) { return -EINVAL; } //父级kobject引用++,父kobj可能不存在 parent = kobject_get(kobj->parent); //若kset存在且父节点没取到,再从kset里取一次 if (kobj->kset) { if (!parent) parent = kobject_get(&kobj->kset->kobj); kobj_kset_join(kobj); kobj->parent = parent; } ...... error = create_dir(kobj); if (error) { kobj_kset_leave(kobj); kobject_put(parent); kobj->parent = NULL; ...... } else kobj->state_in_sysfs = 1; return error; } /* * 从create_dir这个函数开始就进入了sysfs流程 */ static int create_dir(struct kobject *kobj) { int error = 0; error = sysfs_create_dir(kobj); if (!error) { error = populate_dir(kobj); if (error) sysfs_remove_dir(kobj); } return error; } /* * 在v3.6.2/fs/sysfs/dir.c中: * int sysfs_create_dir(struct kobject * kobj) * * sysfs_create_dir - create a directory for an object. * @kobj: object we're creating directory for. * /sys/ 目录是根,对应的dirent是变量sysfs_root,定义在 * /fs/sysfs/mount.c#L35 * struct sysfs_dirent sysfs_root = { * .s_name = "", * .s_count = ATOMIC_INIT(1), * .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), * .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, * .s_ino = 1, * }; * sysfs的级联体系是基于dirent的,设备驱动模型的级联体系是基于kobjet和kset的。 * 在驱动那边kobject和kset的层级被组织好了。 * 当需要"显示"到sysfs时,就调用sysfs_create_dir类似的sysfs函数来创建目录(或文件) * 如果一个kobject父级为空,说明它是最顶端的,即/sys/下的,把它的父级dirent设置 * 为sysfs_root * * * 而dentry的root("/"目录)是VFS的d_make_root(inode)生成的(/fs/dcache.c),而这个 * inode也是根据sysfs_root生成的。 * * 硬件<---设备驱动体系----sysfs体系----VFS体系--->用户: * kobject -- dirent -- dentry(动态生成) * 设备驱动层级: 以kobject为基础,最上层kobject是几个全局变量 * 如devices_set,bus_set,system_set等 * sysfs层级:以dirent为基础,最上层是sysfs_root,全局变量 * VFS层级:以dentry为基础,最上层的是由sysfs_root和vfs函数d_make_root生成的,像 * 其它文件系统一样,存储在super_block里 * * * */ int sysfs_create_dir(struct kobject * kobj) { enum kobj_ns_type type; struct sysfs_dirent *parent_sd, *sd; const void *ns = NULL; int error = 0; BUG_ON(!kobj); //如果父kobj不存在就用根,直接挂到/sys/ if (kobj->parent) parent_sd = kobj->parent->sd; else parent_sd = &sysfs_root; if (!parent_sd) return -ENOENT; if (sysfs_ns_type(parent_sd)) ns = kobj->ktype->namespace(kobj); type = sysfs_read_ns_type(kobj); error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd); if (!error) kobj->sd = sd; return error; } static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, enum kobj_ns_type type, const void *ns, const char *name, struct sysfs_dirent **p_sd) { //S_IFDIR表示目录? umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; int rc; //申请一个dirent sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) return -ENOMEM; sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); sd->s_ns = ns; //本节点是个目录,其kobj记录在s_dir成员中(联合体) sd->s_dir.kobj = kobj; /* link in */ sysfs_addrm_start(&acxt, parent_sd); rc = sysfs_add_one(&acxt, sd);//添加 sysfs_addrm_finish(&acxt); if (rc == 0) *p_sd = sd; else sysfs_put(sd); return rc; } //向父级dirent 添加一个dirent int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { int ret; //添加内部函数 ret = __sysfs_add_one(acxt, sd); if (ret == -EEXIST) { ...... } return ret; } int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { struct sysfs_inode_attrs *ps_iattr; int ret; if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", sysfs_ns_type(acxt->parent_sd)? "required": "invalid", acxt->parent_sd->s_name, sd->s_name); return -EINVAL; } //21位的二元组[ns,name]的hash值(是个UINT) sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); //设置父级dirent sd->s_parent = sysfs_get(acxt->parent_sd); //本dirent的兄弟链接 ret = sysfs_link_sibling(sd); if (ret) return ret; /* Update timestamps on the parent */ ps_iattr = acxt->parent_sd->s_iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; } return 0; } struct sysfs_elem_dir { struct kobject *kobj; unsigned long subdirs;//本目录子目录数 struct rb_root children;//子目录的红黑树 }; //兄弟节点是一个红黑树链接的(rbtree) static int sysfs_link_sibling(struct sysfs_dirent *sd) { //s_dir 是 sysfs_elem_dir 结构 struct rb_node **node = &sd->s_parent->s_dir.children.rb_node; struct rb_node *parent = NULL; //如果将被添加的是一个目录,则父目录的子目录数+=1 if (sysfs_type(sd) == SYSFS_DIR) sd->s_parent->s_dir.subdirs++; //红黑树遍历,找到合适位置 while (*node) { struct sysfs_dirent *pos; int result; pos = to_sysfs_dirent(*node); parent = *node; result = sysfs_sd_compare(sd, pos); if (result < 0) node = &pos->s_rb.rb_left; else if (result > 0) node = &pos->s_rb.rb_right; else return -EEXIST; } /* add new node and rebalance the tree */ rb_link_node(&sd->s_rb, parent, node); rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); return 0; } 添加file /* * 添加kobject就是往某个"目录"下添加一个"文件" * v3.6.2/include/linux/device.h#L117 */ #define bus_register(subsys) \ ({ \ static struct lock_class_key __key; \ __bus_register(subsys, &__key); \ }) /* * 内部函数定义在: * v3.6.2/drivers/base/bus.c#L923 */ int __bus_register(struct bus_type *bus, struct lock_class_key *key) { int retval; struct subsys_private *priv; //申请一个结构 priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); if (!priv) return -ENOMEM; //与bus联系起来 priv->bus = bus; bus->p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //设置bus的名字,如"USB" retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); if (retval) goto out; /* * 前面说过,bus_kset指的是/sys/bus/目录; 一个kobj.kset指的是本 * kobj的父级目录,所以下面这句就是本bus的父目录是/sys/bus/,若为 * USB,则最终形成/sys/bus/usb/ * / priv->subsys.kobj.kset = bus_kset; priv->subsys.kobj.ktype = &bus_ktype; priv->drivers_autoprobe = 1; //此函数上面说过,添加一个kset目录,即添加/sys/bus/usb/ retval = kset_register(&priv->subsys); if (retval) goto out; //为本目录(/sys/bus/usb/)添加一个属性文件 retval = bus_create_file(bus, &bus_attr_uevent); if (retval) goto bus_uevent_fail; //每个总线目录下有个 /devices和/drivers目录 priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj); if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj); if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; } INIT_LIST_HEAD(&priv->interfaces); __mutex_init(&priv->mutex, "subsys mutex", key); klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL); retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; retval = bus_add_attrs(bus); if (retval) goto bus_attrs_fail; pr_debug("bus: '%s': registered\n", bus->name); return 0; bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: kset_unregister(bus->p->drivers_kset); bus_drivers_fail: kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: kset_unregister(&bus->p->subsys); out: kfree(bus->p); bus->p = NULL; return retval; } /* * v3.6.2/drivers/base/bus.c#L127 */ int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) { int error; if (bus_get(bus)) { error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } else error = -EINVAL; return error; } //v3.6.2/fs/sysfs/file.c#L571 int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) { BUG_ON(!kobj || !kobj->sd || !attr); //kobj是usb目录的那个kobj return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); } //v3.6.2/fs/sysfs/file.c#L558 int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type) { //dir_sd指的是usb目录 return sysfs_add_file_mode(dir_sd, attr, type, attr->mode); } int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type, umode_t amode) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; const void *ns; int rc; rc = sysfs_attr_ns(dir_sd->s_dir.kobj, attr, &ns); if (rc) return rc; //目录下文件所用的那个dirent sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; sd->s_ns = ns; sd->s_attr.attr = (void *)attr; sysfs_dirent_init_lockdep(sd); sysfs_addrm_start(&acxt, dir_sd); //这里与前面相同了,就是在dirent结构体系中加入一个元素 rc = sysfs_add_one(&acxt, sd); sysfs_addrm_finish(&acxt); if (rc) sysfs_put(sd); return rc; } //文件系统mount过程 /* * struct path * /include/linux/path.h */ struct path { struct vfsmount *mnt; struct dentry *dentry; }; /* * /fs/namespace.c中的系统调用定义 * SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, * char __user *, type, unsigned long, flags, void __user *, data) * 系统调用mount有5个参数,此函数最后是调用do_mount完成mount任务 */ long do_mount(char *dev_name, char *dir_name, char *type_page, unsigned long flags, void *data_page) { ...... //取得挂载点的path结构信息,应该是根文件系统目录 retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); ...... //如果是新加载的文件系统,执行这里 retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page) } 1916/* 1917 * create a new mount for userspace and request it to be added into the 1918 * namespace's tree 1919 */ 1920static int do_new_mount(struct path *path, char *type, int flags, 1921 int mnt_flags, char *name, void *data) 1922{ 1923 struct vfsmount *mnt; 1924 int err; 1925 1926 if (!type) 1927 return -EINVAL; 1928 1929 /* we need capabilities... */ 1930 if (!capable(CAP_SYS_ADMIN)) 1931 return -EPERM; 1932 //加载type字串指定的文件系统,过程与rootfs类似 1933 mnt = do_kern_mount(type, flags, name, data); 1934 if (IS_ERR(mnt)) 1935 return PTR_ERR(mnt); 1936 //将mnt挂载到path指定的路径上 1937 err = do_add_mount(real_mount(mnt), path, mnt_flags); 1938 if (err) 1939 mntput(mnt); 1940 return err; 1941} /* * 功能: * 将newmnt文件系统加载到path指定的vfs路径上 * 参数: * newmnt:刚才加载的文件系统 * path:newmnt需要加载到的vfs路径 * 说明: * 因为path可能加载了别的文件系统(顶层是rootfs,子层是别的),所以要进入到最 * 内层(最后加载的文件系统)锁住上层mnt * add a mount into a namespace's mount tree */ 1878static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) 1879{ 1880 int err; 1881 1882 mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); 1883 1884 err = lock_mount(path); 1885 if (err) 1886 return err; 1887 1888 err = -EINVAL; 1889 if (unlikely(!check_mnt(real_mount(path->mnt)))) { 1890 /* that's acceptable only for automounts done in private ns */ 1891 if (!(mnt_flags & MNT_SHRINKABLE)) 1892 goto unlock; 1893 /* ... and for those we'd better have mountpoint still alive */ 1894 if (!real_mount(path->mnt)->mnt_ns) 1895 goto unlock; 1896 } 1897 1898 /* Refuse the same filesystem on the same mount point */ 1899 err = -EBUSY; 1900 if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && 1901 path->mnt->mnt_root == path->dentry) 1902 goto unlock; 1903 1904 err = -EINVAL; 1905 if (S_ISLNK(newmnt->mnt.mnt_root->d_inode->i_mode)) 1906 goto unlock; 1907 1908 newmnt->mnt.mnt_flags = mnt_flags; 1909 err = graft_tree(newmnt, path); 1910 1911unlock: 1912 unlock_mount(path); 1913 return err; 1914} //锁住父mount/ /* * 将path指定的最内层mnt锁住,path可能加载了多个文件系统,所以要进入 * 到最内层的 */ 1543static int lock_mount(struct path *path) 1544{ 1545 struct vfsmount *mnt; 1546retry: 1547 mutex_lock(&path->dentry->d_inode->i_mutex); 1548 if (unlikely(cant_mount(path->dentry))) { 1549 mutex_unlock(&path->dentry->d_inode->i_mutex); 1550 return -ENOENT; 1551 } 1552 down_write(&namespace_sem); //查找path对应的第一个子mnt 1553 mnt = lookup_mnt(path); //一直向下一层找,直到下层没有了(llokup_mnt返回0 1554 if (likely(!mnt)) 1555 return 0; /* * 找到了本层的子层mnt,释放命名空间锁本层inode锁 * 释放路径锁。然后迭代:让path指向子层mnt,和dentry * 再retry */ 1556 up_write(&namespace_sem); 1557 mutex_unlock(&path->dentry->d_inode->i_mutex); 1558 path_put(path); 1559 path->mnt = mnt; 1560 path->dentry = dget(mnt->mnt_root); 1561 goto retry; 1562} /* 575 * lookup_mnt - Return the first child mount mounted at path 576 */ 590struct vfsmount *lookup_mnt(struct path *path) 591{ 592 struct mount *child_mnt; 593 594 br_read_lock(&vfsmount_lock); 595 child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); 596 if (child_mnt) { 597 mnt_add_count(child_mnt, 1); 598 br_read_unlock(&vfsmount_lock); 599 return &child_mnt->mnt; 600 } else { 601 br_read_unlock(&vfsmount_lock); 602 return NULL; 603 } 604} /* * 根据dir指示返回mnt的第一个或最后一个子mnt * mount_hashtable[hash(mnt, dentry)]的值是一个链表,存储着相同hash值的mnt * 根据代码大概是,某一个path对应一对mnt dentry,在此path挂载的话,会有mnt1, * dentry1,再在此path挂载的话,会有mnt2,dentry2并且其父是mnt1,dentry1而并不 * 是mnt和dentry。那意味着hash表项中(&p->mnt_parent->mnt == mnt && * p->mnt_mountpoint == dentry)只能成立一次。也就是说同一挂载点的mnt,dentry * 只可能有一个儿子。(这块不明白) */ 553struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, 554 int dir) 555{ 556 struct list_head *head = mount_hashtable + hash(mnt, dentry); 557 struct list_head *tmp = head; 558 struct mount *p, *found = NULL; 559 560 for (;;) { //顺着来还是倒着来 561 tmp = dir ? tmp->next : tmp->prev; 562 p = NULL; 563 if (tmp == head) 564 break; 565 p = list_entry(tmp, struct mount, mnt_hash); //确定一下关系,因为hash有可能冲突 566 if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { 567 found = p; 568 break; 569 } 570 } 571 return found; 572} //嫁接子mount到父mount上// 1570static int graft_tree(struct mount *mnt, struct path *path) 1571{ 1572 if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER) 1573 return -EINVAL; 1574 1575 if (S_ISDIR(path->dentry->d_inode->i_mode) != 1576 S_ISDIR(mnt->mnt.mnt_root->d_inode->i_mode)) 1577 return -ENOTDIR; 1578 1579 if (d_unlinked(path->dentry)) 1580 return -ENOENT; 1581 1582 return attach_recursive_mnt(mnt, path, NULL); 1583} path walk// static int link_path_walk(const char *name, struct nameidata *nd) 1714{ 1715 struct path next; 1716 int err; 1717 1718 while (*name=='/') 1719 name++; 1720 if (!*name) 1721 return 0; 1722 1723 /* At this point we know we have a real path component. */ 1724 for(;;) { 1725 struct qstr this; 1726 long len; 1727 int type; 1728 1729 err = may_lookup(nd); 1730 if (err) 1731 break; 1732 1733 len = hash_name(name, &this.hash); 1734 this.name = name; 1735 this.len = len; 1736 1737 type = LAST_NORM; 1738 if (name[0] == '.') switch (len) { 1739 case 2: 1740 if (name[1] == '.') { 1741 type = LAST_DOTDOT; 1742 nd->flags |= LOOKUP_JUMPED; 1743 } 1744 break; 1745 case 1: 1746 type = LAST_DOT; 1747 } 1748 if (likely(type == LAST_NORM)) { 1749 struct dentry *parent = nd->path.dentry; 1750 nd->flags &= ~LOOKUP_JUMPED; 1751 if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { 1752 err = parent->d_op->d_hash(parent, nd->inode, 1753 &this); 1754 if (err < 0) 1755 break; 1756 } 1757 } 1758 1759 if (!name[len]) 1760 goto last_component; 1761 /* 1762 * If it wasn't NUL, we know it was '/'. Skip that 1763 * slash, and continue until no more slashes. 1764 */ 1765 do { 1766 len++; 1767 } while (unlikely(name[len] == '/')); 1768 if (!name[len]) 1769 goto last_component; 1770 name += len; 1771 1772 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); 1773 if (err < 0) 1774 return err; 1775 1776 if (err) { 1777 err = nested_symlink(&next, nd); 1778 if (err) 1779 return err; 1780 } 1781 if (can_lookup(nd->inode)) 1782 continue; 1783 err = -ENOTDIR; 1784 break; 1785 /* here ends the main loop */ 1786 1787last_component: 1788 nd->last = this; 1789 nd->last_type = type; 1790 return 0; 1791 }//for(;;)循环 1792 terminate_walk(nd); 1793 return err; 1794} 1795 /* * ///opt/soft/abc.txt */ 1713static int link_path_walk(const char *name, struct nameidata *nd) 1714{ 1715 struct path next; 1716 int err; 1717 //去前导'/'=opt/soft/abc.txt,让name指向第一个分量开始处 1718 while (*name=='/') 1719 name++; 1720 if (!*name) 1721 return 0; 1722 1723 /* At this point we know we have a real path component. */ 1724 for(;;) {//按name分量处理 1725 struct qstr this;//当前分量名,长度 1726 long len; 1727 int type; 1728 //inode 访问检查 1729 err = may_lookup(nd); 1730 if (err) 1731 break; 1732 1733 len = hash_name(name, &this.hash);//当前分量hash 1734 this.name = name;//当前分量开始处 1735 this.len = len;//当前分量长度 1736 1737 type = LAST_NORM;//上一个分量正常 1738 if (name[0] == '.') switch (len) { 1739 case 2: 1740 if (name[1] == '.') { 1741 type = LAST_DOTDOT;//上一分量是"点点" 1742 nd->flags |= LOOKUP_JUMPED; 1743 } 1744 break; 1745 case 1: 1746 type = LAST_DOT;//上一分量是"点" 1747 } 1748 if (likely(type == LAST_NORM)) { 1749 struct dentry *parent = nd->path.dentry; 1750 nd->flags &= ~LOOKUP_JUMPED; 1751 if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { 1752 err = parent->d_op->d_hash(parent, nd->inode, 1753 &this); 1754 if (err < 0) 1755 break; 1756 } 1757 } 1758 //*(name+len)==null表示 name即name分量是最后一个:xxx/name'\0' 1759 if (!name[len]) 1760 goto last_component; 1761 /* 1762 * If it wasn't NUL, we know it was '/'. Skip that 1763 * slash, and continue until no more slashes. * 非null表示name后还有分量,那么过滤掉相应的'/' 1764 */ 1765 do { 1766 len++; 1767 } while (unlikely(name[len] == '/')); 1768 if (!name[len]) 1769 goto last_component; //name指向下一个分量,说不定有下一次for循环 1770 name += len; 1771 //得到当前分量相关的dentry等数据结构存入nd,再循环处理下一分量 1772 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); 1773 if (err < 0) 1774 return err; 1775 1776 if (err) {//err>0时,处理符号链接 1777 err = nested_symlink(&next, nd); 1778 if (err) 1779 return err; 1780 } //err==0时,继续for循环,处理下一分量节点 1781 if (can_lookup(nd->inode)) 1782 continue; 1783 err = -ENOTDIR; 1784 break; 1785 /* here ends the main loop */ 1786 1787last_component: /* * 到这里,this指向的是最后一个分量 * 到这里函数才能正确地退出,如果是 * break出去的则表示出错 */ 1788 nd->last = this; 1789 nd->last_type = type; 1790 return 0; 1791 } 1792 terminate_walk(nd); 1793 return err; 1794} /* * 主要是两种处理方法,一种是查cache,一种是慢速找,最终用到路径上倒数第 * 二个节点的dentry(最后一个的父)相关的inode,然后调用inode->lookup根据 * 设置的name找到相关的dentry * * lookup_fast//rcu列表中查找 * __d_lookup_rcu * __d_lookup * lookup_slow * __lookup_hash * lookup_dcache * d_lookup * __d_lookup * lookup_real * dir->i_op->lookup//调用inode的lookup */ 1475static inline int walk_component(struct nameidata *nd, struct path *path, 1476 struct qstr *name, int type, int follow) 1477{ 1478 struct inode *inode; 1479 int err; 1480 /* 1481 * "." and ".." are special - ".." especially so because it has 1482 * to be able to know about the current root directory and 1483 * parent relationships. 1484 */ 1485 if (unlikely(type != LAST_NORM)) 1486 return handle_dots(nd, type);//点/点点的处理 1487 err = lookup_fast(nd, name, path, &inode); 1488 if (unlikely(err)) { 1489 if (err < 0) 1490 goto out_err; 1491 1492 err = lookup_slow(nd, name, path); 1493 if (err < 0) 1494 goto out_err; 1495 1496 inode = path->dentry->d_inode; 1497 } 1498 err = -ENOENT; 1499 if (!inode) 1500 goto out_path_put; 1501 1502 if (should_follow_link(inode, follow)) { 1503 if (nd->flags & LOOKUP_RCU) { 1504 if (unlikely(unlazy_walk(nd, path->dentry))) { 1505 err = -ECHILD; 1506 goto out_err; 1507 } 1508 } 1509 BUG_ON(inode != path->dentry->d_inode); 1510 return 1; 1511 } //path内容存入nd 1512 path_to_nameidata(path, nd); 1513 nd->inode = inode; 1514 return 0; 1515 1516out_path_put: 1517 path_to_nameidata(path, nd); 1518out_err: 1519 terminate_walk(nd); 1520 return err; 1521} 1522 /* * 总结: * 粗略地看了下vfs。具体的fs只需提供相关结构的方法即可,vfs只是一个框架。 * 具体fs满足vfs所需要的接口。比如,vfs查找路径,最终要生成一个dentry, * 而sysfs以硬件和dirent来级联,但用户调用sysfs的lookup时,sysfs需要根据 * 当前的参数生成一个dentry。vfs不管sysfs内部如何实现。 * 遗留问题: * 往同一个目录mount多次,其树状结构是什么样的 * 路径查找中所使用的cache系统原理 */
vfs学习-sysfs
最新推荐文章于 2023-04-12 18:33:42 发布