sysfs是一个用于导出内核内部对象及其属性和关系的虚拟文件系统,用户可以使用sysfs来确定运行内核中的有用信息,同时也可以用来调整设备和子系统。某些系统代理依赖sysfs中的信息来进行操作。块子系统当前使用它来挂载根分区。如果禁用sysfs,就需要通过其主要和次要设备号在内核引导命令行上指定引导设备。例如: 例如,/dev/hda1的“root=03:01”
在Linux内核中,kernfs提供内核子系统内部伪文件系统所需的功能,源于拆分sysfs使用的部分内部逻辑,它通过将有关硬件设备和相关设备驱动程序的信息从内核的设备模型导出到用户空间,提供一组虚拟文件,从而实现独立且可重用的功能。 其他内核子系统可以更容易,更一致地实现自己的伪文件系统。相关补丁集合并到内核版本3.14中的Linux内核主线,该版本于2014年3月30日发布。kernfs的主要用户之一是cgroups内部使用的伪文件系统,其重新设计继续进入Linux内核的3.15版本。
在cgroup的kconfig文件中:
menuconfig CGROUPS
bool "Control Group support"
select KERNFS // 依赖CONFIG_KERNFS
help
kernfs_node表示kernfs层次的构成部分(building block),每个kernfs节点由单个kernfs_node表示。大多数字段都是kernfs专用的,不应该由kernfs用户直接访问。
初始化的时候创建kernfs_node_cache的cache,只有在函数__kernfs_new_node中使用。
有两个函数会调用:
1)kernfs_new_node
2)创建一个新的kernfs层次,kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags, void *priv)
Linux中,使用kset,kobj嵌入某个实体,用ket、kobj来表示这些实体之间的关系。
下面通过一个实例结合代码看下这些数据结构之间的关系:
sys目录内如如下,存在10个目录:
# ls /sys
block class devices fs module
bus dev firmware kernel power
#
在系统中,通过kobject_create_and_add和kset_create_and_add创建这10个目录的逻辑结构,在这个逻辑层次它们都没有父节点,它们的parent_kobj参数都为空。
fs_kobj = kobject_create_and_add("fs", NULL);
power_kobj = kobject_create_and_add("power", NULL);
kernel_kobj = kobject_create_and_add("kernel", NULL);
dev_kobj = kobject_create_and_add("dev", NULL);
firmware_kobj = kobject_create_and_add("firmware", NULL);
block_depr = kobject_create_and_add("block", NULL);
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
class_kset = kset_create_and_add("class", NULL, NULL);
module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
如果是创建上面某个目录的子目录,如devices目录下的system:
# ls /sys/devices
breakpoint platform software system virtual
则需要在参数parent_obj填入device目录的kobject,如下:
kset_create_and_add (name="system", NULL parent_kobj=0x9f50210c) //0x9f50210c为devices_kset的地址
这两个类型在哪里同kernfs_node有关系呢,下面看下这两种对象的创建过程:
kobject创建:
-----------
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
static int object_add_varg (vargs=...
static int kobject_add_internal(struct kobject *kobj)
static int create_dir(struct kobject *kobj)
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) //sysfs_root_kn
struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
kset创建:
--------
struct kset *kset_create_and_add(const char *name,
int kset_register(struct kset *k)
static int kobject_add_internal(struct kobject *kobj)
从上面可以看出,这两个函数最终都调用到了相同的函数:
kobject_add_internal
在这个函数中最终会调用到:
sysfs_create_dir_ns,创建kernfs_node保存到struct kobject 的sd字段中。
函数如下:
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
{
struct kernfs_node *parent, *kn;
BUG_ON(!kobj);
if (kobj->parent) // 什么样的kobj->parent为空?
parent = kobj->parent->sd;
else
parent = sysfs_root_kn;
if (!parent)
return -ENOENT;
kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);
if (IS_ERR(kn)) {
if (PTR_ERR(kn) == -EEXIST)
sysfs_warn_dup(parent, kobject_name(kobj));
return PTR_ERR(kn);
}
kobj->sd = kn;
return 0;
}
在代码中可以看到:if (kobj->parent),如果为空,在kernfs_node这个逻辑层次的父节点,设置为:sysfs_root_kn。
什么样的节点parent为空呢?在上面看到创建sys目录下的10个子目录这个逻辑层次的kobj时,parent都设置为空。
sysfs_root_kn是什么时候创建的呢?如下,在vfs系统初始化时,创建了sysfs_root.
int __init sysfs_init(void)
{
int err;
sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
NULL);
if (IS_ERR(sysfs_root))
return PTR_ERR(sysfs_root);
sysfs_root_kn = sysfs_root->kn;
err = register_filesystem(&sysfs_fs_type);
if (err) {
kernfs_destroy_root(sysfs_root);
return err;
}
return 0;
}
这时,我们看以看到一个完整的目录层次结构(sys目录下有10个子目录,子目录下又有各个子目录),以及这个目录结构的创建方式。