- <PRE class=cpp name="code">/*
- * 一、说明
- * 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-03-23 17:03:02 发布