测试代码:
-
#include<linux/device.h>
-
#include<linux/module.h>
-
#include<linux/kernel.h>
-
#include<linux/stat.h>
-
#include<linux/init.h>
-
#include<linux/string.h>
-
#include<linux/sysfs.h>
-
#include<linux/kobject.h>
-
-
MODULE_LICENSE("Dual BSD/GPL");
-
MODULE_AUTHOR("SM");
-
-
#define BUFFER_SIZE 20
-
#define NAME_MAX 20
-
#define PHONE_MAX 20
-
struct my_kobject
-
{
-
char name[NAME_MAX];
-
char phone[PHONE_MAX];
-
int age;
-
struct kobject kobj;
-
};
-
-
struct my_kobject test;
-
-
struct attribute attr1 =
-
{
-
.name = "name",
-
.mode = S_IRWXUGO,
-
};
-
-
struct attribute attr2 =
-
{
-
.name = "phone",
-
.mode = S_IRWXUGO,
-
};
-
-
struct attribute attr3 =
-
{
-
.name = "age",
-
.mode = S_IRWXUGO,
-
};
-
-
static struct attribute * attribute_test[] =
-
{
-
&attr1,
-
&attr2,
-
&attr3,
-
NULL,
-
};
-
-
-
ssize_t test_show(struct kobject *obj,struct attribute *attr,char *buf)
-
{
-
struct my_kobject *my_kobj = container_of(obj,struct my_kobject,kobj);
-
int count = 0;
-
-
printk("test_show \n");
-
-
if(strcmp(attr->name, "name") == 0)
-
{
-
count = sprintf(buf, "name : %s\n", my_kobj->name);
-
}
-
else if(strcmp(attr->name, "phone") == 0)
-
{
-
count = sprintf(buf, "phone : %s\n", my_kobj->phone);
-
}
-
else if(strcmp(attr->name, "age") == 0)
-
{
-
count = sprintf(buf, "age : %d\n", my_kobj->age);
-
}
-
else
-
{
-
count = sprintf(buf, "show error\n");
-
}
-
-
return count;
-
}
-
-
ssize_t test_store(struct kobject *kobj,struct attribute *attr,const char *buf,
-
size_t count)
-
{
-
struct my_kobject *my_kobj = container_of(kobj,struct my_kobject,kobj);
-
printk("test_store \n");
-
-
if(strcmp(attr->name, "name") == 0)
-
{
-
strcpy(my_kobj->name,buf);
-
}
-
else if(strcmp(attr->name, "phone") == 0)
-
{
-
strcpy(my_kobj->phone,buf);
-
}
-
else if(strcmp(attr->name, "age") == 0)
-
{
-
my_kobj->age = simple_strtol(buf,NULL,10);
-
}
-
else
-
{
-
printk(KERN_NOTICE"store error\n");
-
}
-
-
return count;
-
}
-
-
struct sysfs_ops test_ops =
-
{
-
.show = test_show,
-
.store = test_store,
-
};
-
-
-
-
void test_release(struct kobject *obj)
-
{
-
printk("release test \n");
-
}
-
-
-
#if 1
-
struct kobj_type ktype =
-
{
-
.release = test_release,
-
.sysfs_ops = &test_ops,
-
.default_attrs = attribute_test,
-
};
-
#endif
-
-
int __init sysfs_init(void)
-
{
-
if(kobject_init_and_add(&test.kobj,&ktype,NULL,"test"))
-
printk("test fail\n");
-
-
printk("register success\n");
-
-
return 0;
-
}
-
-
-
-
void __exit sysfs_exit(void)
-
{
-
kobject_del(&test.kobj);
-
printk("unregister success\n");
-
}
-
-
module_init(sysfs_init);
-
module_exit(sysfs_exit);
/sys/test
├── age
├── name
├── phone
mode的值
-
#define S_IRWXU 00700
-
#define S_IRUSR 00400
-
#define S_IWUSR 00200
-
#define S_IXUSR 00100
-
-
#define S_IRWXG 00070
-
#define S_IRGRP 00040
-
#define S_IWGRP 00020
-
#define S_IXGRP 00010
-
-
#define S_IRWXO 00007
-
#define S_IROTH 00004
-
#define S_IWOTH 00002
-
#define S_IXOTH 00001
-
-
#endif
-
-
#ifdef __KERNEL__
-
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
-
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
-
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
-
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
-
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
1,设备模型 kobject 的操作流程以及重点难点
1)初始化,添加
kobject_init_and_add():
-
/**
-
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
-
* @kobj: pointer to the kobject to initialize
-
* @ktype: pointer to the ktype for this kobject.
-
* @parent: pointer to the parent of this kobject.
-
* @fmt: the name of the kobject.
-
*
-
* This function combines the call to kobject_init() and
-
* kobject_add(). The same type of error handling after a call to
-
* kobject_add() and kobject lifetime rules are the same here.
-
*/
-
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
-
struct kobject *parent, const char *fmt, ...)
-
{
-
va_list args;
-
int retval;
-
-
kobject_init(kobj, ktype);
-
-
va_start(args, fmt);
-
retval = kobject_add_varg(kobj, parent, fmt, args);
-
va_end(args);
-
-
return retval;
-
}
-
EXPORT_SYMBOL_GPL(kobject_init_and_add);
当前函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test")
kobj : test.kobj
ktype : ktype
parent : NULL
fmt : "test"
@a1@ kobject_init
: 初始化一个内核对象的各个参数
-
/**
-
* kobject_init - initialize a kobject structure
-
* @kobj: pointer to the kobject to initialize
-
* @ktype: pointer to the ktype for this kobject.
-
*
-
* This function will properly initialize a kobject such that it can then
-
* be passed to the kobject_add() call.
-
*
-
* After this function is called, the kobject MUST be cleaned up by a call
-
* to kobject_put(), not by a call to kfree directly to ensure that all of
-
* the memory is cleaned up properly.
-
*/
-
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
-
{
-
char *err_str;
-
-
if (!kobj) {
-
err_str = "invalid kobject pointer!";
-
goto error;
-
}
-
if (!ktype) {
-
err_str = "must have a ktype to be initialized properly!\n";
-
goto error;
-
}
-
if (kobj->state_initialized) {
-
/* do not error out as sometimes we can recover */
-
printk(KERN_ERR "kobject (%p): tried to init an initialized "
-
"object, something is seriously wrong.\n", kobj);
-
dump_stack();
-
}
-
-
kobject_init_internal(kobj);
-
kobj->ktype = ktype;
-
return;
-
-
error:
-
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
-
dump_stack();
-
}
-
EXPORT_SYMBOL(kobject_init);
kobject_init(kobj, ktype);
kobj : test.kobj
ktype : ktype
@b1@ 首先要确定对象的存在,以及对象类型的存在,否则无法释放对象,
无法对这个对象的各个属性进行读写
@b2@ 初始化该对象
-
static void kobject_init_internal(struct kobject *kobj)
-
{
-
if (!kobj)
-
return;
-
kref_init(&kobj->kref);
-
INIT_LIST_HEAD(&kobj->entry);
-
kobj->state_in_sysfs = 0;
-
kobj->state_add_uevent_sent = 0;
-
kobj->state_remove_uevent_sent = 0;
-
kobj->state_initialized = 1;
-
}
kobject_init_internal(kobj);
kobj : test.kobj
首先初始化 kobj->kref,实际上kobj->kref就是一个原子变量(atomic_t),表示对象引用计数;
然后初始化 kobj->entry,即对象的链表(清空链表)(用于连接到所在的 kset 中去的单元 );
最后设置对象的其他成员。
@b DONE@
@a2@ va_start和va_end是处理可变参数的固定语法
@a3@ kobject_add_varg
:通过环境变量把该对象添加到合适的位置上去
-
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
-
const char *fmt, va_list vargs)
-
{
-
int retval;
-
-
retval = kobject_set_name_vargs(kobj, fmt, vargs);
-
if (retval) {
-
printk(KERN_ERR "kobject: can not set name properly!\n");
-
return retval;
-
}
-
kobj->parent = parent;
-
return kobject_add_internal(kobj);
-
}
kobject_add_varg(kobj, parent, fmt, args);
kobj : test.kobj
parent : NULL
fmt : "test"
@b1@ 设置该对象的名字
-
/**
-
* kobject_set_name_vargs - Set the name of an kobject
-
* @kobj: struct kobject to set the name of
-
* @fmt: format string used to build the name
-
* @vargs: vargs to format the string.
-
*/
-
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
-
va_list vargs)
-
{
-
const char *old_name = kobj->name;
-
char *s;
-
-
if (kobj->name && !fmt)
-
return 0;
-
-
kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
-
if (!kobj->name)
-
return -ENOMEM;
-
-
/* ewww... some of these buggers have '/' in the name ... */
-
while ((s = strchr(kobj->name, '/')))
-
s[0] = '!';
-
-
kfree(old_name);
-
return 0;
-
}
kobject_set_name_vargs(kobj, fmt, vargs);
kobj : test.kobj
fmt : "test"
@c1@ 如果对象名已被赋值,且 fmt 为 NULL,则退出。
!!!因此,如果对象名没有被赋值,且 fmt 为 NULL,则会产生段错误!!!
即kobject_init_and_add(&test.kobj,&ktype,NULL,NULL);
@c2@ 通过 fmt 参数给 对象名 赋值
-
/* Simplified asprintf. */
-
char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
-
{
-
unsigned int len;
-
char *p;
-
va_list aq;
-
-
va_copy(aq, ap);
-
len = vsnprintf(NULL, 0, fmt, aq);
-
va_end(aq);
-
-
p = kmalloc(len+1, gfp);
-
if (!p)
-
return NULL;
-
-
vsnprintf(p, len+1, fmt, ap);
-
-
return p;
-
}
-
EXPORT_SYMBOL(kvasprintf);
@d1@ 首先测量这个字符串的长度;如 fun("test%d%s",3,"hello"),
则这个字符串的长度为:strlen("test3hello") = 10 个字节;
@d2@ 创建内存空间;
@d3@ 把字符串保存到刚创建的内存空间中
@d DONE@
@c3@ 释放 旧的对象名 所占的内存空间
@c DONE@
@b2@ 把对象加载到合适的位置
-
static int kobject_add_internal(struct kobject *kobj)
-
{
-
int error = 0;
-
struct kobject *parent;
-
-
if (!kobj)
-
return -ENOENT;
-
-
if (!kobj->name || !kobj->name[0]) {
-
WARN(1, "kobject: (%p): attempted to be registered with empty "
-
"name!\n", kobj);
-
return -EINVAL;
-
}
-
-
parent = kobject_get(kobj->parent);
-
-
/* join kset if set, use it as parent if we do not already have one */
-
if (kobj->kset) {
-
if (!parent)
-
parent = kobject_get(&kobj->kset->kobj);
-
kobj_kset_join(kobj);
-
kobj->parent = parent;
-
}
-
-
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
-
kobject_name(kobj), kobj, __func__,
-
parent ? kobject_name(parent) : "",
-
kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
-
-
error = create_dir(kobj);
-
if (error) {
-
kobj_kset_leave(kobj);
-
kobject_put(parent);
-
kobj->parent = NULL;
-
-
/* be noisy on error issues */
-
if (error == -EEXIST)
-
printk(KERN_ERR "%s failed for %s with "
-
"-EEXIST, don't try to register things with "
-
"the same name in the same directory.\n",
-
__func__, kobject_name(kobj));
-
else
-
printk(KERN_ERR "%s failed for %s (%d)\n",
-
__func__, kobject_name(kobj), error);
-
dump_stack();
-
} else
-
kobj->state_in_sysfs = 1;
-
-
return error;
-
}
@c1@ 首先要确定这个对象是存在的(即其是一个分配了内存的变量,
不是一个指针变量),在本例子中如下:
-
struct my_kobject
-
{
-
char name[NAME_MAX];
-
char phone[PHONE_MAX];
-
int age;
-
struct kobject kobj;
-
};
-
struct my_kobject test;
函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test")
kobj : test.kobj
ktype : ktype
parent : NULL
fmt : "test"
定义了一个名为 test 的变量,系统会为这个变量分配内存空间,
而这个变量中的成员 kobj 也就被分配了内存空间了。
@c2@ “!kobj->name”这个对象保存名字的空间是需要被创建了的
“!kobj->name[0]”这个对象名需要已经被赋值了的,不可为空
@c3@ 当前对象的父对象的引用加 1;
在本例子中
parent : NULL
@c4@ 如果对象设置了所归属的集合,
a> 则这个集合的引用加 1;
b> 再把这个对象添加到这个集合的链表尾部
@c5@ 为这个对象创建目录
-
static int create_dir(struct kobject *kobj)
-
{
-
int error = 0;
-
if (kobject_name(kobj)) {
-
error = sysfs_create_dir(kobj);
-
if (!error) {
-
error = populate_dir(kobj);
-
if (error)
-
sysfs_remove_dir(kobj);
-
}
-
}
-
return error;
-
}
@d1@ 获得对象的名字
-
static inline const char *kobject_name(const struct kobject *kobj)
-
{
-
return kobj->name;
-
}
@d2@ 在 sysfs 文件系统中创建目录
-
/**
-
* sysfs_create_dir - create a directory for an object.
-
* @kobj: object we're creating directory for.
-
*/
-
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);
-
-
if (kobj->parent)
-
parent_sd = kobj->parent->sd;
-
else
-
parent_sd = &sysfs_root;
-
-
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;
-
}
函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test")
kobj : test.kobj
ktype : ktype
parent : NULL
fmt : "test"
@e1@ 确定对象已被分配内存空间
@e2@ 获得对象的父对象的目录入口地址。
在本例子中
parent : NULL
因此对象的父对象的目录入口地址为文件系统的根目录
-
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_IRWXU | S_IRUGO | S_IXUGO,
-
.s_ino = 1,
-
};
@e3@ 获得对象的父对象的目录入口地址的命名空间
从而读取对象的命名空间,有3中命名空间
-
/*
-
* Namespace types which are used to tag kobjects and sysfs entries.
-
* Network namespace will likely be the first.
-
*/
-
enum kobj_ns_type {
-
KOBJ_NS_TYPE_NONE = 0,
-
KOBJ_NS_TYPE_NET,
-
KOBJ_NS_TYPES
-
};
@e4@创建目录
-
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)
-
{
-
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
-
struct sysfs_addrm_cxt acxt;
-
struct sysfs_dirent *sd;
-
int rc;
-
-
/* allocate */
-
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
-
if (!sd)
-
return -ENOMEM;
-
-
sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
-
sd->s_ns = ns;
-
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;
-
}
问题:目录是怎么被创建的?
@f1@ sysfs_new_dirent
(name
, mode
,SYSFS_DIR
);
从cache中获取一个slab对象
@f2@
@f3@
@f DONE@
@e DONE@
@d3@ 创建目录成功,添加对象的属性到对象的目录中
问题:属性文件是怎么添加到目录中的?
@d DONE@
@c DONE@
@b DONE@
@a DONE@
2)卸载
阅读(2286) | 评论(0) | 转发(1) |