kernel与用户层接口之sysfs属性接口

  1. 字符设备文件,以这个虚拟设备上的 read/write/ioctl 等接口与用户交互;但 read/write 一般只能做一件事情, ioctl 可以根据 cmd 参数做多个功能,但其缺点是很明显的: ioctl 接口无法直接在 Shell 脚本中使用,为了使用 ioctl 的功能,还必须编写配套的 C语言的虚拟设备操作程序, ioctl 的二进制数据接口也是造成大小端问题 (big endian与little endian)、32位/64位不可移植问题的根源;
  2.  proc 接口,接受用户的 read/write/ioctl 操作;同样的,一个 proc 项通常使用其 read/write/ioctl 接口,它所存在的问题与上面的虚拟字符设备的的问题相似;
  3. sysfs 属性接口

优点: 比起古老的 proc 文件系统,它是基于内核的数据结构,因此组织结构上更加严密。它的设计使内核的信息更易获取,而且更加清晰。

内核空间与用户空间的映射关系如下表所示:


内核空间(internel) 用户空间(externel)
内核对象
(kernel objects)
目录
(directories)
对象属性
(object attributes)
普通文件
(regular files)
对象关系
(object relationshiops)
符号链接
(symbolic links)



1.1  Linux 统一设备模型所添加的高级sys接口:

 使用 <include/linux/device.h> 头文件提供的这四个宏

#define BUS_ATTR(_name, _mode, _show, _store)   \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

#define CLASS_ATTR(_name, _mode, _show, _store)                 \
struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)

#define DRIVER_ATTR(_name, _mode, _show, _store)        \
struct driver_attribute driver_attr_##_name =           \
        __ATTR(_name, _mode, _show, _store)

#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

从头文件中还可以找到 show/store 函数的原型,注意到它和虚拟字符设备或 proc 项的 read/write 的作用很类似,但有一点不同是 show/store 函数上的 buf/count 参数是在 sysfs 层已作了用户区/内核区的内存复制,虚拟字符设备上常见的 __user 属性在这里并不需要,因而也不需要多一次 copy_from_user/copy_to_user, 在 show/store 函数参数上的 buf/count 参数已经是内核区的地址,可以直接操作。

1.2 使用 sysfs 所提供的底层sys接口:
定义来自 <include/linux/sysfs.h> 
#define __ATTR(_name,_mode,_show,_store) { \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
        .show   = _show,                                        \
	.store  = _store,                                       \
}

#define __ATTR_RO(_name) { \
        .attr   = { .name = __stringify(_name), .mode = 0444 }, \
        .show   = _name##_show,                                 \
}

上面的总线/类别/驱动/设备四个接口都是以这里的__ATTR实现的.
 
 
1.3 对一个 kobject 动态添加上文本属性或二进制属性方法函数:
int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
int __must_check sysfs_create_bin_file(struct kobject *kobj,struct bin_attribute *attr); 


 
 
1.4 参考内核提供的  samples/kobject/kobject-example.c 
/*
 * Sample kobject implementation
 *
 * Copyright (C) 2004-2007 Greg Kroah-Hartman <[email protected]>
 * Copyright (C) 2007 Novell Inc.
 *
 * Released under the GPL version 2 only.
 *
 */
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>

/*
 * This module shows how to create a simple subdirectory in sysfs called
 * /sys/kernel/kobject-example  In that directory, 3 files are created:
 * "foo", "baz", and "bar".  If an integer is written to these files, it can be
 * later read out of it.
 */

static int foo;
static int baz;
static int bar;

/*
 * The "foo" file where a static variable is read from and written to.
 */
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
                        char *buf)
{
        return sprintf(buf, "%d\n", foo);
}

static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
                         const char *buf, size_t count)
{
        sscanf(buf, "%du", &foo);
        return count;
}

static struct kobj_attribute foo_attribute =
        __ATTR(foo, 0666, foo_show, foo_store);
/*
 * More complex function where we determine which variable is being accessed by
 * looking at the attribute for the "baz" and "bar" files.
 */
static ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr,
                      char *buf)
{
        int var;

        if (strcmp(attr->attr.name, "baz") == 0)
                var = baz;
        else
                var = bar;
        return sprintf(buf, "%d\n", var);
}

static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
                       const char *buf, size_t count)
{
        int var;

        sscanf(buf, "%du", &var);
        if (strcmp(attr->attr.name, "baz") == 0)
                baz = var;
        else
                bar = var;
        return count;
}

static struct kobj_attribute baz_attribute =
        __ATTR(baz, 0666, b_show, b_store);
static struct kobj_attribute bar_attribute =
        __ATTR(bar, 0666, b_show, b_store);


/*
 * Create a group of attributes so that we can create and destroy them all
 * at once.
 */
static struct attribute *attrs[] = {
        &foo_attribute.attr,
        &baz_attribute.attr,
        &bar_attribute.attr,
        NULL,   /* need to NULL terminate the list of attributes */
};
/*
 * An unnamed attribute group will put all of the attributes directly in
 * the kobject directory.  If we specify a name, a subdirectory will be
 * created for the attributes with the directory being the name of the
 * attribute group.
 */
static struct attribute_group attr_group = {
        .attrs = attrs,
};

static struct kobject *example_kobj;

static int __init example_init(void)
{
        int retval;

        /*
         * Create a simple kobject with the name of "kobject_example",
         * located under /sys/kernel/
         *
         * As this is a simple directory, no uevent will be sent to
         * userspace.  That is why this function should not be used for
         * any type of dynamic kobjects, where the name and number are
         * not known ahead of time.
         */
        example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
        if (!example_kobj)
                return -ENOMEM;

        /* Create the files associated with this kobject */
        retval = sysfs_create_group(example_kobj, &attr_group);
        if (retval)
                kobject_put(example_kobj);

        return retval;
}

static void __exit example_exit(void)
{
        kobject_put(example_kobj);
}

module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Kroah-Hartman <[email protected]>");



你可能感兴趣的:(kernel与用户层接口之sysfs属性接口)