前言

当多个kobject属于同一类的时候,为了方便管理,就引入了Kset。Kset可以认为是一组kobject的集合,是kobject的容器。
比如/sys/bus下就属于同一类kobject。
shell@test:/sys/bus $ ls
clockevents
clocksource
container
coresight
cpu
event_source
hid
i2c
iio
mdio_bus
mmc
platform
scsi
sdio
serio
spi
usb
virtio
workqueue

数据结构

linux内核使用struct kset结构体代表一个kset结构
struct kset {struct list_head list;spinlock_t list_lock;struct kobject kobj;const struct kset_uevent_ops *uevent_ops;
};

list:                  用来将kset下的kobject使用链表管理。

list_lock:         对kset上的list访问操作时,使用spinlock进行互斥保护。
kobj:                kset本身也是一个内核对象,所以需要嵌入kobject进行管理。
uevent_ops:   kset的uevent操作函数集合。当其中的kobject对象的状态发生变化需要通知用户空间的时候,就需要调用uevent_ops中的函数。
struct kset_uevent_ops定义如下:
struct kset_uevent_ops {int (* const filter)(struct kset *kset, struct kobject *kobj);const char *(* const name)(struct kset *kset, struct kobject *kobj);int (* const uevent)(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env);
};

kset操作

  • kset_init(初始化一个kset对象)
/*** kset_init - initialize a kset for use* @k: kset*/
void kset_init(struct kset *k)
{kobject_init_internal(&k->kobj);                       //初始化kobjectINIT_LIST_HEAD(&k->list);                              //初始化链表spin_lock_init(&k->list_lock);                         //初始化自旋锁
}
  • kset_register(初始化然后添加kset)
/*** kset_register - initialize and add a kset.* @k: kset.*/
int kset_register(struct kset *k)
{int err;if (!k)return -EINVAL;kset_init(k);                                           //初始化操作err = kobject_add_internal(&k->kobj);                   //将kset->kobject对象添加到sys下,此过程和添加kobject操作一样。if (err)return err;kobject_uevent(&k->kobj, KOBJ_ADD);                     //通过uevent机制通知用户空间return 0;
}

关于uevent机制,会在后面的uevent文章中详细说明,此处先跳过。

  • kset_create(动态创建一个Kset)
tatic struct kset *kset_create(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int retval;kset = kzalloc(sizeof(*kset), GFP_KERNEL);if (!kset)return NULL;retval = kobject_set_name(&kset->kobj, "%s", name);                                //设置name域if (retval) {kfree(kset);return NULL;}kset->uevent_ops = uevent_ops;                         //设置uevent_opskset->kobj.parent = parent_kobj;                       //设置parent/** The kobject of this kset will have a type of kset_ktype and belong to* no kset itself.  That way we can properly free it when it is* finished being used.*/kset->kobj.ktype = &kset_ktype;                   //设置ktypekset->kobj.kset = NULL;return kset;
}
  • kset_create_and_add(kset_register和kset_create的结合体)
struct kset *kset_create_and_add(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int error;kset = kset_create(name, uevent_ops, parent_kobj);if (!kset)return NULL;error = kset_register(kset);if (error) {kfree(kset);return NULL;}return kset;
}

示例

本例看下/sys/module下节点的创建过程。
kernel/kernel/params.c
------------------------------------
static int __init param_sysfs_init(void)
{module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);if (!module_kset) {printk(KERN_WARNING "%s (%d): error creating kset\n",__FILE__, __LINE__);return -ENOMEM;}module_sysfs_initialized = 1;version_sysfs_builtin();param_sysfs_builtin();return 0;
}

可以看到通过kset_create_and_add创建一个名字为"module"的kset。表现在sys下就是在sys下存在一个module的目录。

root@sp9860g_1h10_3g:/sys/module # ls
ahci_xgene
audio_smsg
bcmdhd
binder
block
bluetooth
brcm_lpm
cfg80211
configfs
coresight_etm4x
cpuidle
dm_bufio
dm_mod
dm_verity
dwc3
dynamic_debug
.....

那module下的这些节点是什么时候创建的?   带着此问题继续看代码。

static void __init param_sysfs_builtin(void)
{const struct kernel_param *kp;unsigned int name_len;char modname[MODULE_NAME_LEN];for (kp = __start___param; kp < __stop___param; kp++) {char *dot;if (kp->perm == 0)continue;dot = strchr(kp->name, '.');if (!dot) {/* This happens for core_param() */strcpy(modname, "kernel");name_len = 0;} else {name_len = dot - kp->name + 1;strlcpy(modname, kp->name, name_len);}kernel_add_sysfs_param(modname, kp, name_len);}
}

对kernel中在.param段的模块参数,通过kernel_add_sysfs_param添加到sys中。而__start___param和__stop___param定义在链接脚本中。

  /* Built-in module parameters. */               \__param : AT(ADDR(__param) - LOAD_OFFSET) {            \VMLINUX_SYMBOL(__start___param) = .;          \*(__param)                     \VMLINUX_SYMBOL(__stop___param) = .;           \}  

而这些模块参数,是通过module_param等相关函数设置的。

#define module_param(name, type, perm)               \module_param_named(name, name, type, perm)

接着上面的分析,看kernel_add_sysfs_param此函数,在此函数中通过locate_module_kobject函数建立起与kset(module_kset)之间的联系。

static struct module_kobject * __init locate_module_kobject(const char *name)
{struct module_kobject *mk;struct kobject *kobj;int err;kobj = kset_find_obj(module_kset, name);                                 //通过name域找下kobj是否存在,存在就返回,不存在创建新的if (kobj) {mk = to_module_kobject(kobj);                  } else {mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);BUG_ON(!mk);mk->mod = THIS_MODULE;mk->kobj.kset = module_kset;err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL,             //设置kset, ktype,  创建新的kobj"%s", name);
#ifdef CONFIG_MODULESif (!err)err = sysfs_create_file(&mk->kobj, &module_uevent.attr);        //创建kobj的属性,
#endifif (err) {kobject_put(&mk->kobj);pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",name, err);return NULL;}/* So that we hold reference in both cases. */kobject_get(&mk->kobj);}return mk;
}

当用户通过insmod插入一个模块的时候,最后调用到init_module系统调用

SYSCALL_DEFINE3(init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
{int err;struct load_info info = { };err = may_init_module();if (err)return err;pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",umod, len, uargs);err = copy_module_from_user(umod, len, &info);if (err)return err;return load_module(&info, uargs, 0);
}

下面是load_module的调用流程,只关心跟本节相关的。

load_module->mod_sysfs_setup->module_param_sysfs_setup->add_sysfs_paramnew->grp.name = "parameters";new->grp.attrs = attrs;new->attrs[num].mattr.show = param_attr_show;new->attrs[num].mattr.store = param_attr_store;

最终会在/sys/module下的任何一个模块,都会有一个名字为"parameters"的目录。比如/sys/module/printk

root@test:/sys/module/printk # ls
parameters
uevent

在parameters下的模块参数有:

root@test:/sys/module/printk/parameters # ls
always_kmsg_dump
console_suspend
cpuid
ignore_loglevel
time

这些属性都是在printk中通过

module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);

相同此种方法创建的。

Linux设备驱动模型-Kset相关推荐

  1. Linux中kobject的作用,Linux设备驱动模型-- 数据结构Kset/KObject

    前言 Kset和kobject是Linux设备驱动模型中的核心数据结构,其主要作用是将系统中的设备抽象出来,以树状结构组织,方便系统统一管理. 而这个统一管理的地方,就是sysfs,先放一张示例图,阐 ...

  2. Linux设备驱动模型三 kset

    Linux设备驱动模型三 kset 1 kset数据结构 kset的定义在前文已有描述,我们再回顾一下: [cpp] view plain copy struct kset { /*与子kobject ...

  3. linux 统一设备模型 pci,Linux设备驱动模型摘抄

    Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄 Linux设备驱动模型摘抄(1) Linux统一设备模型 简介 Li ...

  4. Linux设备驱动模型1——简介和底层架构

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.linux设备驱动模型简介 1.什么是设备驱动模型? (1)类class.总线bus.设备device.驱动d ...

  5. Linux设备驱动模型之platform(平台)总线详解

    /********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...

  6. Linux设备驱动模型二 kobject

    Linux设备驱动模型二 kobject 1 kobject 1.1 kobject数据结构 kobject是sysfs文件系统的基础数据结构,它定义在include/linux/kobjec.h中 ...

  7. Linux设备驱动模型一 sysfs

    Linux设备驱动模型一 sysfs 1 Linux设备模型 Linux 2.5的内核引入了一种新的设备模型,目的是对计算机上的所有设备进行统一的管理. 它包含以下基础结构: 类型 说明 设备Devi ...

  8. 五.linux设备驱动模型

    站在设备驱动这个角度分析,设备驱动模型是如何构建出来,起到什么作用,认识它并在写驱动的时候去利用设备驱动模型 目录 一.linux 设备驱动模型简介 1.1. 什么是设备驱动模型 1.2. 为什么需要 ...

  9. 整理--linux设备驱动模型

    知识整理–linux设备驱动模型 以kobject为底层,组织类class.总线bus.设备device.驱动driver等高级数据结构,同时实现对象引用计数.维护对象链表.对象上锁.对用户空间的表示 ...

  10. LINUX设备驱动模型分析之三 驱动(DRIVER)接口分析

    上一章我们分析了bus-driver-device模型中bus接口部分,本章我们将分析driver接口,在bus-driver-device模型中,driver接口是依附于bus上,而不像device ...

最新文章

  1. 比特币核心(BCE)或许并没有你想象的强大
  2. .Net Telerik Web UI 安装和使用入门
  3. Hadoop学习笔记—1.基本介绍与环境配置
  4. solver.prototxt参数说明(二)
  5. mysql事务,START TRANSACTION, COMMIT和ROLLBACK,SET AUTOCOMMIT语法
  6. Java认证授权框架Spring Security介绍
  7. Struts 2的OGNL表达式
  8. WPF之无法触发KeyDown或者KeyUp键盘事件
  9. Nodejs正则表达式函数之match、test、exec、search、split、replace使用详解
  10. jenkins java常用插件下载,Jenkins简单介绍以及插件入门
  11. 【Low版】HAUT - OJ - Contest1035 - 2017届新生周赛(六)题解
  12. 厦门大学考研:必知20大时间节点
  13. GeekTool使用备忘
  14. java实现微信H5支付和回调的Demo源码
  15. 【转】巧舟的逆转裁判开发手记~
  16. rtspplayer播放器实现
  17. matlab patch 六面体,[MATLAB数学相关] 求正六面体的细分格式
  18. python基础 日常总结——列表(二)
  19. linux系统下操作nandflash指令,Linux驱动之Nand Flash原理及硬件操作
  20. 条件求和:SUMIF、SUMIFS函数

热门文章

  1. 当前网络存在的安全问题
  2. Linux驱动的platform机制
  3. IIS连接oralce数据提示“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本”...
  4. java byte与char互转原理
  5. 游戏娱乐计算机配置方案,计算机配置方案.doc
  6. Java NIO 详解(二)
  7. 开发环境、生产环境、测试环境的基本理解和区别
  8. backbond Model实现
  9. 给Eclipse中hibernate.cfg.xml配置文件加提示
  10. LinkedHashMap与HashMap的使用比较