当前位置: 首页 > news >正文

Linux对象管理机制

Linux对象管理机制

在linux内核中,采用对象机制来组织和管理系统单元。kobject表示基本对象单元,kset用来管理一组kobject,ktype用来定义对象行为。
在这里插入图片描述

此图来源于互联网

一、kobject

结构体如下所示,省略了一些暂时不关注的成员

struct kobject {const char		    *name;   /* 每一个kobject对应/sys/下面的一个目录,而name则是目录名 */struct list_head	entry;   /* 用于在kset中将一串kobject链起来 */struct kobject		*parent; /* 父节点,可以理解为父目录 */struct kset		    *kset;   /* 当前kobject属于的kset */struct kobj_type	*ktype;  /* 当前kobject对应的ktype */struct kref		    kref;    /* 引用次数,用来判断当前kobject是否还被使用 */unsigned int state_initialized:1;         /* 如果为1,表示该kobject已经初始化 */unsigned int state_in_sysfs:1;            /* 如果为1,表示该kobject已经添加到sysfs中 */unsigned int state_add_uevent_sent:1;     /* 如果为1,表示该kobject已经发送了add uevent */unsigned int state_remove_uevent_sent:1;  /* 如果为1,表示该kobject已经发送了remove uevent */unsigned int uevent_suppress:1;           /* 如果为1,跳过发送uevent */
};struct kset {struct list_head list; /* 用来链接kset下的kobject成员 */struct kobject kobj;   /* kset本质也是一种特殊的kobject,所以有该成员 */const struct kset_uevent_ops *uevent_ops; /* uevent的处理函数,当属于该set的kobject触发了uevent事件就会调用其中的函数 */
} __randomize_layout;struct kobj_type {void (*release)(struct kobject *kobj); /* 当kref为0时就会被调用 */const struct sysfs_ops *sysfs_ops; /* 定义sfsfs的读写接口 */struct attribute **default_attrs;  /* kobj下的属性文件 */
};struct kset_uevent_ops {int (* const filter)(struct kset *kset, struct kobject *kobj);       /* 决定是否允许该kobject发送uevent */const char *(* const name)(struct kset *kset, struct kobject *kobj); /* 自定义子系统名 */int (* const uevent)(struct kset *kset, struct kobject *kobj,        /* 自定义的uevent环境变量 */struct kobj_uevent_env *env);
};

二、api函数分析

函数有删减,只保留核心逻辑

2.1 注册函数

kobject_init_and_addkobject_init--设置kobject->ktype成员的值kobject_init_internal--初始化kobject结构体中的链表、一些成员、引用次数为1kobject_add_vargkobject_set_name_vargs--设置kobj的namekobject_add_internal--设置父节点相关的信息,创建对应的目录kset_create_and_addkset_create--动态分配一个kset,并为kset->kobj设置name、parent、ktype等,设置uevent_opskset_registerkobject_add_internal--设置父节点相关的信息,创建对应的目录kobject_uevent--设置一个add的uevent事件static int kobject_add_internal(struct kobject *kobj)
{struct kobject *parent;parent = kobject_get(kobj->parent); /* 获取kobject的父kobject,并且父kobject的引用计数加1 */if (kobj->kset) {if (!parent)parent = kobject_get(&kobj->kset->kobj); /* 如果没有父kobject,则将kset作为父 */kobj_kset_join(kobj); /* 将kobject添加到kset的链表里面 */kobj->parent = parent; /*记录最终的父kobject,可能是原父,也可能是kset*/}error = create_dir(kobj); /* 创建kobject的目录以及对应ktype的attribute属性文件 */kobj->state_in_sysfs = 1; /* 设置kobject的state_in_sysfs为1,表示kobject已经添加到sysfs中 */
}

2.2 释放函数

void kobject_del(struct kobject *kobj)功能是将该kobject从kset、parent、sysfs节点中删除

void kobject_del(struct kobject *kobj)
{struct kernfs_node *sd;/* 移除sysfs的目录,引用次数递减 */sd = kobj->sd;sysfs_remove_dir(kobj);sysfs_put(sd);kobj->state_in_sysfs = 0;kobj_kset_leave(kobj); /* 将kobject从kset链表中移除,kset对应的引用次数递减 *//*取消父子节点的绑定,parent引用递减*/kobject_put(kobj->parent);kobj->parent = NULL;
}

void kobject_put(struct kobject *kobj)递减引用计数,当计数为0时调用release函数

void kobject_put(struct kobject *kobj)
{if (kobj) {kref_put(&kobj->kref, kobject_release);}
}

2.3 uevent函数

int kobject_uevent(struct kobject *kobj, enum kobject_action action);的作用是像用户空间发送一个uevent事件

kobject_ueventkobject_uevent_envint kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[])
{/* 找到kobject所属的kset */top_kobj = kobj;while (!top_kobj->kset && top_kobj->parent)top_kobj = top_kobj->parent; if (!top_kobj->kset) {return -EINVAL;}/* 获取到kobject所属的kset的uevent_ops */kset = top_kobj->kset;uevent_ops = kset->uevent_ops; /* 如果uevent_suppress为1,跳过uevent的处理*/if (kobj->uevent_suppress) {return 0;}/* 如果filter返回0则跳过后续的处理 */if (uevent_ops && uevent_ops->filter)if (!uevent_ops->filter(kset, kobj)) {return 0;}/* originating subsystem */if (uevent_ops && uevent_ops->name)subsystem = uevent_ops->name(kset, kobj);elsesubsystem = kobject_name(&kset->kobj);/* 组装环境变量 */env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);devpath = kobject_get_path(kobj, GFP_KERNEL);retval = add_uevent_var(env, "ACTION=%s", action_string);retval = add_uevent_var(env, "DEVPATH=%s", devpath);retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);/* 调用uevent处理函数 */if (uevent_ops && uevent_ops->uevent) {retval = uevent_ops->uevent(kset, kobj, env);}switch (action) {case KOBJ_ADD:kobj->state_add_uevent_sent = 1;    /* 标记已发送add事件 */case KOBJ_REMOVE:kobj->state_remove_uevent_sent = 1; /* 标记已发送remove事件 */case KOBJ_UNBIND:zap_modalias_env(env); /* 解绑时的清理操作 */}#if defined(CONFIG_NET)/* 通过netlink将内核的uevent广播给用户空间,暂不关注 */
#endif#ifdef CONFIG_UEVENT_HELPER/* 这一段是“用户态帮助程序”路径,用于在早期启动阶段(或未启用 netlink/broadcast 时)用用户态程序来处理 uevent,暂不关注 */
#endif
}

三、一个简单的demo

加载该模块后会在/sys/目录下生成如下结构的节点

/sys/kobject_parent/
├── kobj_config
├── kobject_child
│   └── kobj_config
└── kset_demo└── kobject_demo└── kobj_config

在模块insmod和rmmod时,会触发my_uevent_ops相关函数的调用。当echo和cat文件kobj_config时会触发obj_test_sysops相关函数的调用。当rmmod时,会触发obj_test_release函数的调用。

#include<linux/device.h>  
#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/string.h>  
#include <linux/sysfs.h>  
#include <linux/stat.h>  MODULE_LICENSE("Dual BSD/GPL");/*对应于kobject的目录下的一个文件,Name成员就是文件名*/
struct attribute test_attr = {.name = "kobj_config",.mode = S_IRWXUGO,
};static struct attribute *def_attrs[] ={&test_attr,  NULL,  
};  /*当读文件时执行的操作*/
ssize_t kobj_test_show(struct kobject*kobject, struct attribute *attr,char *buf) 
{  printk("have show.\n");printk("attrname:%s.\n", attr->name);  printk("count %d.\n", kobject->kref.refcount);sprintf(buf,"%s\n",attr->name);return strlen(attr->name)+2;  
} /*当写文件时执行的操作*/
ssize_t kobj_test_store(struct kobject*kobject,struct attribute *attr,const char *buf, size_t count) 
{  printk("havestore\n");  printk("write: %s\n",buf);  return count;  
}  //kobject对象的操作  
struct sysfs_ops obj_test_sysops =   
{.show = kobj_test_show,  .store = kobj_test_store,  
};/*release方法释放该kobject对象*/
void obj_test_release(struct kobject*kobject)
{  printk("eric_test: release .\n");  
}/*定义kobject对象的一些属性及对应的操作*/
struct kobj_type ktype =   
{.release = obj_test_release,  .sysfs_ops=&obj_test_sysops,  .default_attrs=def_attrs,  
}; struct kobject kobj_parent;
struct kobject kobj_child;struct kset    *kset_demo;
struct kobject kobj_demo;
static int my_filter(struct kset *kset, struct kobject *kobj)
{pr_info("[uevent_ops] filter called: kobj name = %s\n", kobject_name(kobj));return 1;   // 返回 0 表示不过滤,允许事件
}static const char *my_name(struct kset *kset, struct kobject *kobj)
{pr_info("[uevent_ops] name called for: %s\n", kobject_name(kobj));return "my_kset_event";
}static int my_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
{pr_info("[uevent_ops] uevent called for: %s\n", kobject_name(kobj));add_uevent_var(env, "MY_ENV_VAR=HelloWorld");return 0;
}static const struct kset_uevent_ops my_uevent_ops = {.filter = my_filter,.name   = my_name,.uevent = my_uevent,
};static int kobj_demo_init(void)
{  printk("kboject demo init.\n");kobject_init_and_add(&kobj_parent,&ktype,NULL,"kobject_parent");kobject_init_and_add(&kobj_child,&ktype,&kobj_parent,"kobject_child");kset_demo = kset_create_and_add("kset_demo",&my_uevent_ops,&kobj_parent);kobject_init_and_add(&kobj_demo, &ktype, &kset_demo->kobj, "kobject_demo");kobj_demo.kset = kset_demo;kobject_uevent(&kobj_demo, KOBJ_ADD);return 0;
}  static void kobj_demo_exit(void)
{  printk("kobject demo exit.\n");/* 先释放属于 kset 的 kobject,避免 kset 仍被占用 */kobject_put(&kobj_demo);/* 注销 kset(内部会对 kset->kobj 执行 kobject_del 与 kobject_put) */kset_unregister(kset_demo);/* 先删子节点,再删父节点,且必须在 del 后配对 put 才能真正释放 */kobject_del(&kobj_child); kobject_put(&kobj_child);kobject_del(&kobj_parent);kobject_put(&kobj_parent);
}module_init(kobj_demo_init); 
module_exit(kobj_demo_exit);
http://www.dtcms.com/a/483110.html

相关文章:

  • 网站建设实训考试做电商的步骤
  • 微信小程序uni.request 返回值存在精度丢失问题
  • 做外贸上哪些网站鹤壁集团网站建设
  • 惠城网站建设有哪些网站建设欧美
  • 注册 区块链节点
  • 硅谷甄选(续2)首页
  • 茂名建设公司网站wordpress写书typecho主题
  • 上海网站建设软件下载唐山的做网站的企业
  • 图解网络(科普版)
  • TensorFlow Implementation of Content-Based Filtering|基于内容过滤的TensorFlow实现
  • 【Pr】Adobe Premiere Pro 2025 学习笔记-01工作流实操
  • 手机端网站模板下载开发者助手app
  • 怎样做网站代理拼多多怎么开店
  • php按步骤做网站苏州企业网站建设服务中心
  • 月报 Vol.04:新增 async test 与 async fn main 语法,新增 lexmatch 表达式
  • 04--CSS基础(3)
  • C语言--函数
  • `String`、`StringBuilder` 和 `StringBuffer`区别卓望一面面试题
  • 【11408学习记录】考研英语阅读长难句得分密码:5层拆解2016真题复杂句!
  • 网站建设启示金华网站建设团队
  • 做彩票网站代理犯法吗网站建设实施计划包括
  • 第三十五篇|日本语言学校的可计算结构:神户日语学院数据建模案例
  • 数据安全工具手册——便捷实用的安全工具集-20251014
  • 网站建设网络合同网站打开出现建设中
  • 办公用品网站模板建英文网站
  • 【编号28】中国九大流域范围-shp
  • FITC-SH的化学特性及其在分子标记与表面偶联中的实验应用
  • BITFIELD命令详解
  • 无锡模板网站设计公司无锡网站建设seo
  • ⸢ 柒-Ⅳ⸥⤳ 可信纵深防御建设方案:信任链构建可信策略