/*
* 一、说明
* 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
最新推荐文章于 2025-05-31 03:41:52 发布