linux之configfs简介和编程入门

一、什么是configfs
是一种基于ram的文件系统
configfs is a ram-based filesystem that provides the converse of sysfs's functionality.  Where sysfs is a filesystem-based view of kernel objects, configfs is a filesystem-based manager of kernel objects, or config_items.

二、configfs有什么用处
在用户空间配置内核对象

三、configfs VS ioctl
configfs可直接察看,通过用户态目录文件访问接口,适用于内核对象有众多复杂的配置。

四、configs VS sysfs
configfs可以在用户态创建和删除内核对象。
With sysfs, an object is created in kernel (for example, when a device is discovered) and it is registered with sysfs.  Its attributes then appear in sysfs, allowing userspace to read the attributes via readdir(3)/read(2).  It may allow some attributes to be modified via write(2).  The important point is that the object is created and destroyed in kernel, the kernel controls the lifecycle of the sysfs representation, and sysfs is merely a window on all this.
A configfs config_item is created via an explicit userspace operation: mkdir(2).  It is destroyed via rmdir(2).  The attributes appear at mkdir(2) time, and can be read or modified via read(2) and write(2). As with sysfs, readdir(3) queries the list of items and/or attributes. symlink(2) can be used to group items together.  Unlike sysfs, the lifetime of the representation is completely driven by userspace.  The kernel modules backing the items must respond to this.
Both sysfs and configfs can and should exist together on the same system.  One is not a replacement for the other.

五、什么时候用configfs
当内核需要很多参数需要配置时;当需要动态创建内核对象并且内核对象需要修改配置时;
不想写用户态程序和ioctl时,写shell脚本就可以直接配置configfs。

六、怎么知道系统上是否已经安装了configfs,安装在哪个目录
执行如下命令,可以看到安装目录为/sys/kernel/config
cat /proc/mounts | grep configfs 
configfs /sys/kernel/config configfs rw,relatime 0 0

七、configfs组织结构是怎么样的
顶层结构是struct configfs_subsystem,为configfs子系统结构,接着是struct config_group,是configfs目录和属性的容器,struct config_item是configfs目录,代表可配置的内核对象,struct configfs_attribute是目录下面的属性。

八、如何运用configfs

configfs can be compiled as a module or into the kernel.  You can access it by doing
mount -t configfs none /config

The configfs tree will be empty unless client modules are also loaded. These are modules that register their item types with configfs as subsystems.  Once a client subsystem is loaded, it will appear as a subdirectory (or more than one) under /config.  Like sysfs, the configfs tree is always there, whether mounted on /config or not.

An item is created via mkdir(2).  The item's attributes will also appear at this time.  readdir(3) can determine what the attributes are, read(2) can query their default values, and write(2) can store new values.  Don't mix more than one attribute in one attribute file.

There are two types of configfs attributes:

* Normal attributes, which similar to sysfs attributes, are small ASCII text files, with a maximum size of one page (PAGE_SIZE, 4096 on i386).  Preferably only one value per file should be used, and the same caveats from sysfs apply. Configfs expects write(2) to store the entire buffer at once.  When writing to normal configfs attributes, userspace processes should first read the entire file, modify the portions they wish to change, and then write the entire buffer back.

* Binary attributes, which are somewhat similar to sysfs binary attributes, but with a few slight changes to semantics.  The PAGE_SIZE limitation does not apply, but the whole binary item must fit in single kernel vmalloc'ed buffer. The write(2) calls from user space are buffered, and the attributes' write_bin_attribute method will be invoked on the final close, therefore it is imperative for user-space to check the return code of close(2) in order to verify that the operation finished successfully. To avoid a malicious user OOMing the kernel, there's a per-binary attribute maximum buffer value.

When an item needs to be destroyed, remove it with rmdir(2).  An item cannot be destroyed if any other item has a link to it (via symlink(2)).  Links can be removed via unlink(2).

九、Coding With configfs

Every object in configfs is a config_item.  A config_item reflects an object in the subsystem.  It has attributes that match values on that object.  configfs handles the filesystem representation of that object and its attributes, allowing the subsystem to ignore all but the basic show/store interaction.
Items are created and destroyed inside a config_group.  A group is a collection of items that share the same attributes and operations. Items are created by mkdir(2) and removed by rmdir(2), but configfs handles that.  The group has a set of operations to perform these tasks
A subsystem is the top level of a client module.  During initialization, the client module registers the subsystem with configfs, the subsystem appears as a directory at the top of the configfs filesystem.  A subsystem is also a config_group, and can do everything a config_group can.

十、代码示例(来自内核目录Documentation\filesystems\configfs)
介绍代码之前,先过一下基本的数据结构:
struct configfs_subsystem {
	struct config_group	su_group;
	struct mutex		su_mutex;
};
configfs子系统,config_group是抽象容器,之所以叫容器,是因为容器中可以包括config_item,还可以递归包含config_group。struct mutex是用于子系统访问控制的。
struct config_group {
	struct config_item		cg_item;
	struct list_head		cg_children;
	struct configfs_subsystem 	*cg_subsys;
	struct list_head		default_groups;
	struct list_head		group_entry;
};
config_group作为幕后主使,是不轻易出现在台前的。所以有了94行的struct config_item来表现为一个目录。
struct config_item {
	char			*ci_name;
	char			ci_namebuf[CONFIGFS_ITEM_NAME_LEN];
	struct kref		ci_kref;
	struct list_head	ci_entry;
	struct config_item	*ci_parent;
	struct config_group	*ci_group;
	struct config_item_type	*ci_type;
	struct dentry		*ci_dentry;
}; 
config_item             行为目录名称。
config_item_type 行为目录下属性和属性操作,属性表现为目录下的文本文件。
struct config_item_type {
	struct module				*ct_owner;
	struct configfs_item_operations		*ct_item_ops;
	struct configfs_group_operations	*ct_group_ops;
	struct configfs_attribute		**ct_attrs;
	struct configfs_bin_attribute		**ct_bin_attrs;
};
configfs_item_operations行为属性操作方法,操作对象是configfs_attribute属性。
configfs_group_operations行为目录操作方法,可以在当前目录下创建item或group。
configfs_attribute行为当前目录属性数组。
struct configfs_attribute {
	const char		*ca_name;
	struct module 		*ca_owner;
	umode_t			ca_mode;
	ssize_t (*show)(struct config_item *, char *);
	ssize_t (*store)(struct config_item *, const char *, size_t);
};
属性非常简单,有属性名称、所属模块和访问权限。
示例1:创建一个最简单的configfs目录和可读写的属性
创建目录01-childless,下面有三个属性,其中属性storeme为可写。
# ll /sys/kernel/config/01-childless/
-r–r–r–. 1 root root 4096 Sep 27 05:16 description
-r–r–r–. 1 root root 4096 Sep 27 05:16 showme
-rw-r–r–. 1 root root 4096 Sep 27 05:16 storeme
37/*
38 * 01-childless
39 *
40 * This first example is a childless subsystem.  It cannot create
41 * any config_items.  It just has attributes.
42 *
43 * Note that we are enclosing the configfs_subsystem inside a container.
44 * This is not necessary if a subsystem has no attributes directly
45 * on the subsystem.  See the next example, 02-simple-children, for
46 * such a subsystem.
47 */
48
49struct childless {
50     struct configfs_subsystem subsys;
51     int showme;
52     int storeme;
53};
创建一个结构体包含了configfs子系统,两个属性showme, storeme放在了这里。
虽然注释里说明了为什么把这两个属性放这里,但还是没太理解,既然属性description可以放子系统下,为什么其他两个属性不行呢?有谁知道的告知一下。
子系统定义如下:
138static struct childless childless_subsys = {
139     .subsys = {
140          .su_group = {
141               .cg_item = {
142                    .ci_namebuf = "01-childless",
143                    .ci_type = &childless_type,
144               },
145          },
146     },
147};
142行,定义目录名称。
143行,定义属性和操作。
接着看属性和操作的定义:
114CHILDLESS_ATTR_RO(showme, childless_showme_read);
115CHILDLESS_ATTR(storeme, S_IRUGO | S_IWUSR, childless_storeme_read,
116            childless_storeme_write);
117CHILDLESS_ATTR_RO(description, childless_description_read);
118
119static struct configfs_attribute *childless_attrs[] = {
120     &childless_attr_showme.attr,
121     &childless_attr_storeme.attr,
122     &childless_attr_description.attr,
123     NULL,
124};
125
126CONFIGFS_ATTR_OPS(childless);
127static struct configfs_item_operations childless_item_ops = {
128     .show_attribute          = childless_attr_show,
129     .store_attribute     = childless_attr_store,
130};
131
132static struct config_item_type childless_type = {
133     .ct_item_ops     = &childless_item_ops,
134     .ct_attrs     = childless_attrs,
135     .ct_owner     = THIS_MODULE,
136};

133行,属性操作定义在128行和129行,这两个函数又是由126行宏定义的。126行宏依赖一个函数to_##_item,其中_item是宏的传入参数,这个函数的作用是从struct config_item转换到第49行的结构,然后作为函数show_attribute和store_attribute的传入参数。
134行,关联了属性数组,属性数组在119行定义,第120-122行属性又分别在114-117行定义。
一切准备就绪之后,在模块初始化地方调用子系统注册函数之后,就可以在/sys/kernel/config/下看到创建了子系统了。 
407static int __init configfs_example_init(void)
408{
409     int ret;
410     int i;
411     struct configfs_subsystem *subsys;
412
413     for (i = 0; example_subsys[i]; i++) {
414          subsys = example_subsys[i];
415
416          config_group_init(&subsys->su_group);
417          mutex_init(&subsys->su_mutex);
418          ret = configfs_register_subsystem(subsys);
419          if (ret) {
420               printk(KERN_ERR "Error %d while registering subsystem %s\n",
421                      ret,
422                      subsys->su_group.cg_item.ci_namebuf);
423               goto out_unregister;
424          }
425     }
426
427     return 0;
416-417行,初始化子系统。
418行,注册子系统。
这里做个小结:
1、创建子系统struct configfs_subsystem
2、创建子系统下config_item_type,对应位置configfs_subsystem->config_group->config_item->config_item_type
3、创建config_item_type对应的属性数组和操作,操作主要是show_attribute和store_attribute
4、注册子系统configfs_register_subsystem

示例2:创建一个configfs目录,用户空间可创建目录(新的内核对象)
首先是定义configfs子系统,
304static struct configfs_subsystem simple_children_subsys = {
305     .su_group = {
306          .cg_item = {
307               .ci_namebuf = "02-simple-children",
308               .ci_type = &simple_children_type,
309          },
310     },
311};
接着定义config_item_type, 
289/*
290 * Note that, since no extra work is required on ->drop_item(),
291 * no ->drop_item() is provided.
292 */
293static struct configfs_group_operations simple_children_group_ops = {
294     .make_item     = simple_children_make_item,
295};
296
297static struct config_item_type simple_children_type = {
298     .ct_item_ops     = &simple_children_item_ops,
299     .ct_group_ops     = &simple_children_group_ops,
300     .ct_attrs     = simple_children_attrs,
301     .ct_owner     = THIS_MODULE,
302};
298行,定义了子系统根目录属性操作,跟示例1类似
300行,定义了子系统根目录属性,跟示例1类似
299行,这里新增加了configfs_group_operations,具体定义在293行,继续跟进294行函数simple_children_make_item
232struct simple_children {
233     struct config_group group;
234};
235
236static inline struct simple_children *to_simple_children(struct config_item *item)
237{
238     return item ? container_of(to_config_group(item), struct simple_children, group) : NULL;
239}
240
241static struct config_item *simple_children_make_item(struct config_group *group, const char *name)
242{
243     struct simple_child *simple_child;
244
245     simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
246     if (!simple_child)
247          return ERR_PTR(-ENOMEM);
248
249     config_item_init_type_name(&simple_child->item, name,
250                       &simple_child_type);
251
252     simple_child->storeme = 0;
253
254     return &simple_child->item;
255}
241行,定义了configfs_group_operations->make_item操作,返回值是新创建的struct config_item,传入参数是struct config_group,即是指定config_group下创建config_item项,这就意味着在该子系统(i.e /sys/kernel/config/02-simple-children)下执行命令mkdir,最终会执行到这个函数。
那执行mkdir 之后,会生成一个怎样的新目录呢?
249行,当调用mkdir时,这时就调用config_item_init_type_name初始化这个config_item,接着看250行的simple_child_type到底定义了怎么一个item类型?
171static struct configfs_attribute simple_child_attr_storeme = {
172     .ca_owner = THIS_MODULE,
173     .ca_name = "storeme",
174     .ca_mode = S_IRUGO | S_IWUSR,
175};
176
177static struct configfs_attribute *simple_child_attrs[] = {
178     &simple_child_attr_storeme,
179     NULL,
180};
219static struct configfs_item_operations simple_child_item_ops = {
220     .release          = simple_child_release,
221     .show_attribute          = simple_child_attr_show,
222     .store_attribute     = simple_child_attr_store,
223};
224
225static struct config_item_type simple_child_type = {
226     .ct_item_ops     = &simple_child_item_ops,
227     .ct_attrs     = simple_child_attrs,
228     .ct_owner     = THIS_MODULE,
229};
225行,定义了config_item_type。
227行,先看属性,simple_child_attrs定义在177行,只有一个属性,这个属性定义在171行,仔细看一下这个属性,有可读写的。
所以经过mkdir之后,该目录下就自动生成一个名字为storeme的属性,其对应的操作定义在219行。具体如下:
# cd /sys/kernel/config/02-simple-children/
# ls
description
# mkdir test
# ll
-r–r–r–. 1 root root 4096 Sep 28 21:24 description
drwxr-xr-x. 2 root root    0 Sep 28 21:24 test
# tree
.
|– description
`– test
    `– storeme
1 directory, 2 files
# cat test/storeme 
0
# echo 1 > test/storeme 
# cat test/storeme 
1

示例3:创建group
之前我们讲过,config_group是可以嵌套的,那么现在就来看一下嵌套之后是什么样的:
# cd /sys/kernel/config/03-group-children/
# ls
description 
# mkdir test
# mkdir test/test1
# mkdir test/test2
# mkdir test/test3
# tree
.
|– description
`– test
    |– description
    |– test1
    |   `– storeme
    |– test2
    |   `– storeme
    `– test3
        `– storeme
看出与示例2的区别了吗?
首先看子系统定义
382static struct configfs_subsystem group_children_subsys = {
383     .su_group = {
384          .cg_item = {
385               .ci_namebuf = "03-group-children",
386               .ci_type = &group_children_type,
387          },
388     },
389};
386行,config_item_type与之前的不一样,跟过去看看
371static struct configfs_group_operations group_children_group_ops = {
372     .make_group     = group_children_make_group,
373};
374
375static struct config_item_type group_children_type = {
376     .ct_item_ops     = &group_children_item_ops,
377     .ct_group_ops     = &group_children_group_ops,
378     .ct_attrs     = group_children_attrs,
379     .ct_owner     = THIS_MODULE,
380};
375行,定义新的config_item_type,其根本区别在377行configfs_group_operations
371行,定义了configfs_group_operations,这里定义了make_group函数,在子系统下mkdir就会调用这个函数。
326static struct config_group *group_children_make_group(struct config_group *group, const char *name)
327{
328     struct simple_children *simple_children;
329
330     simple_children = kzalloc(sizeof(struct simple_children),
331                      GFP_KERNEL);
332     if (!simple_children)
333          return ERR_PTR(-ENOMEM);
334
335     config_group_init_type_name(&simple_children->group, name,
336                        &simple_children_type);
337
338     return &simple_children->group;
339}
这份代码非常眼熟,跟示例2中创建config_item太像了,只不过把所有对象由config_item改为config_group类型的。
336行,simple_children_type正是示例2中对应的config_item_type。
所以这里的创建步骤首先是创建一个为config_group的目录,再在这个目录下创建config_item的目录。
到这里为止,简单地了解了一下configfs的实现原理,在某些应用中不失为一种很好的手段。
转载请注原出处:http://blog.csdn.net/liumangxiong
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页