linux内核之class介绍(一)

class的概念
class是设备的更高层视图,抽象出了底层的实现细节.驱动程序会区分SCSI硬盘和ATA硬盘,但在class层他们都是
硬盘.classes帮助用户空间只需要知道这些是什么设备,而不需要关心他们是怎么连接和工作的.(A class is a higher-level view of a device that abstracts out low-level implementation details. Drivers may see a SCSI disk or an ATA disk, but,at the class level, they are all simply disks. Classes allow user space to work with devices based on what they do, rather than how they are connected or how they work.)

class结构体
include\linux\Device.h

struct class {
	const char		*name;
	struct module		*owner;

	struct class_attribute		*class_attrs;
	struct device_attribute		*dev_attrs;
	struct bin_attribute		*dev_bin_attrs;
	struct kobject			*dev_kobj;

	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
	char *(*devnode)(struct device *dev, mode_t *mode);

	void (*class_release)(struct class *class);
	void (*dev_release)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	const struct kobj_ns_type_operations *ns_type;
	const void *(*namespace)(struct device *dev);

	const struct dev_pm_ops *pm;

	struct subsys_private *p;
};

@name: Name of the class.

	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);

该名字用于设置subsys_private.subsys.kobj的名字,也就是子系统的目录名,如:sys/class/name

@owner: The module owner.
表示该class所属的module

@class_attrs: Default attributes of this class.
表示class默认的属性,在class注册时创建

	error = add_class_attrs(class_get(cls));

@dev_attrs: Default attributes of the devices belong to the class.
@dev_bin_attrs: Default binary attributes of the devices belong to the class.
以上dev_attrs,dev_bin_attrs是设备相关的属性,在设备添加到该class时在设备目录需要创建的属性文件

static int device_add_attrs(struct device *dev)
{
	struct class *class = dev->class;
	const struct device_type *type = dev->type;
	int error;

	if (class) { // 如果定义了class,添加class的设备属性文件dev_attrs,dev_bin_attrs
		error = device_add_attributes(dev, class->dev_attrs);
		if (error)
			return error;
		error = device_add_bin_attributes(dev, class->dev_bin_attrs);
		if (error)
			goto err_remove_class_attrs;
	}
	.............
}

@dev_kobj: The kobject that represents this class and links it into the hierarchy.
dev_kobj是kobject指针,指向sysfs_dev_char_kobj(sys/dev/char),表示属于该class的设备在sys/dev/char目录

	/* set the default /sys/dev directory for devices of this class */
	if (!cls->dev_kobj)
		cls->dev_kobj = sysfs_dev_char_kobj;// sys/dev/char

sysfs_dev_char_kobj在这里创建,代表/sys/dev/char目录:

int __init devices_init(void)
{
	// 创建/sys/devices目录
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	// 创建/sys/dev目录
	dev_kobj = kobject_create_and_add("dev", NULL);
	if (!dev_kobj)
		goto dev_kobj_err;
	// 创建/sys/dev/block目录
	sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
	if (!sysfs_dev_block_kobj)
		goto block_kobj_err;
	// 创建/sys/dev/char目录
	sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
	if (!sysfs_dev_char_kobj)
		goto char_kobj_err;

	return 0;

 char_kobj_err:
	kobject_put(sysfs_dev_block_kobj);
 block_kobj_err:
	kobject_put(dev_kobj);
 dev_kobj_err:
	kset_unregister(devices_kset);
	return -ENOMEM;
}

@dev_uevent: Called when a device is added, removed from this class, or a
few other things that generate uevents to add the environment
variables.
device加入class或从class移除,或者一些其它事件发生时调用uevent来添加环境变量
driver/base/core.c

static int dev_uevent(struct kset *kset, struct kobject *kobj,
		      struct kobj_uevent_env *env)
{
	struct device *dev = to_dev(kobj);
	int retval = 0;

	/* add device node properties if present */
	if (MAJOR(dev->devt)) {
		const char *tmp;
		const char *name;
		mode_t mode = 0;

		add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
		add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
		name = device_get_devnode(dev, &mode, &tmp);
		if (name) {
			add_uevent_var(env, "DEVNAME=%s", name);
			kfree(tmp);
			if (mode)
				add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
		}
	}

	if (dev->type && dev->type->name)
		add_uevent_var(env, "DEVTYPE=%s", dev->type->name);

	if (dev->driver)
		add_uevent_var(env, "DRIVER=%s", dev->driver->name);

	/* have the bus specific function add its stuff */
	if (dev->bus && dev->bus->uevent) {
		retval = dev->bus->uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: bus uevent() returned %d\n",
				 dev_name(dev), __func__, retval);
	}

	/* have the class specific function add its stuff */
	if (dev->class && dev->class->dev_uevent) { // 调用所属class->dev_uevent
		retval = dev->class->dev_uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: class uevent() "
				 "returned %d\n", dev_name(dev),
				 __func__, retval);
	}

	/* have the device type specific function add its stuff */
	if (dev->type && dev->type->uevent) {
		retval = dev->type->uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: dev_type uevent() "
				 "returned %d\n", dev_name(dev),
				 __func__, retval);
	}

	return retval;
}

static const struct kset_uevent_ops device_uevent_ops = {
	.filter =	dev_uevent_filter,
	.name =		dev_uevent_name,
	.uevent =	dev_uevent,
};

int __init devices_init(void)
{
	// 创建/sys/devices目录
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	.......
}

@devnode: Callback to provide the devtmpfs.
用于返回device设备节点的相对路径

@class_release: Called to release this class.
用于释放class

@dev_release: Called to release the device.
用于释放device

@suspend: Used to put the device to sleep mode, usually to a low power
state.
用于让设备进入睡眠模式,通常是低功耗模式

@resume: Used to bring the device from the sleep mode.
让设备退出睡眠模式

@ns_type: Callbacks so sysfs can detemine namespaces.
sysfs用于确定命名空间(namespaces)

@namespace: Namespace of the device belongs to this class.

@pm: The default device power management operations of this class.
电源管理用的函数集合

@p: The private data of the driver core, no one other than the
driver core can touch this.
p指向subsys_private结构体,用于保存归属该class的device和driver链表:

struct subsys_private {
	struct kset subsys; // the struct kset that defines this subsystem
	struct kset *devices_kset; // the list of devices associated

	struct kset *drivers_kset; // the list of drivers associated
	struct klist klist_devices;// the klist to iterate over the @devices_kset
	struct klist klist_drivers;// the klist to iterate over the @drivers_kset
	struct blocking_notifier_head bus_notifier;//the bus notifier list for anything that cares about things on this bus.
	unsigned int drivers_autoprobe:1;
	struct bus_type *bus;//pointer back to the struct bus_type that this structure is associated with.

	struct list_head class_interfaces;// list of class_interfaces associated
	struct kset glue_dirs;//"glue" directory to put in-between the parent device to  avoid namespace conflicts
	struct mutex class_mutex;//mutex to protect the children, devices, and interfaces lists.
	struct class *class; // pointer back to the struct class that this structure is associated with.
};
<think>好的,我现在需要回答用户关于Linux内核CLASS_ATTR宏的定义和用法的问题。首先,用户提供的引用内容似乎与动态内存管理和BPF有关,但问题本身是关于CLASS_ATTR的,可能需要先确认这些引用是否相关。不过看起来引用[1]提到的TLSF算法和动态内存管理的宏可能与CLASS_ATTR无关,而引用[2]提到的bpf-helpers可能也不直接相关。因此,可能需要抛开这些引用,直接查找关于CLASS_ATTR的信息。 首先,我需要回忆Linux内核中设备模型相关的部分,因为CLASS_ATTR可能与设备类(class)的属性有关。Linux设备模型中,类(class)是种将设备分组的方式,每个类可以有属性,这些属性通常在sysfs中暴露。例如,在/sys/class/下的各个类目录中会有属性文件。 接下来,CLASS_ATTR可能是个用于定义类属性的宏,类似于DEVICE_ATTR、DRIVER_ATTR等。这些宏通常用于创建sysfs属性,允许用户空间读取或设置内核中的变量或执行操作。 为了确认,我需要查找Linux内核源码中的相关定义。通常,这些宏会在头文件中定义,比如include/linux/device/class.h。CLASS_ATTR宏可能接受名称、权限和show/store函数作为参数。例如: #define CLASS_ATTR(_name, _mode, _show, _store) \ struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) 或者可能使用更高级的宏,比如__ATTR_RO或__ATTR_RW等。不过,具体定义可能因内核版本而异。 在用法方面,用户需要先定义个类,然后使用CLASS_ATTR创建属性,并通过class_create_file或class_remove_file来添加或删除属性。例如: static struct class *my_class; static ssize_t my_attr_show(struct class *class, struct class_attribute *attr, char *buf) { return sprintf(buf, "Hello\n"); } static ssize_t my_attr_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { // 处理写入操作 return count; } CLASS_ATTR(my_attribute, 0644, my_attr_show, my_attr_store); 然后在模块初始化时: my_class = class_create(THIS_MODULE, "my_class"); if (IS_ERR(my_class)) { ... } int err = class_create_file(my_class, &class_attr_my_attribute); if (err) { ... } 需要注意权限模式,例如0644表示用户可读写,组和其他可读。另外,show和store函数必须符合特定的原型,正确操作缓冲区,并返回适当的字节数。 另外,可能还需要考虑兼容性问题,不同内核版本中的宏定义可能有所变化。例如,较新的内核可能推荐使用CLASS_ATTR_RO和CLASS_ATTR_RW等宏来简化只读或读写属性的定义。 总结来说,CLASS_ATTR用于在设备类中创建sysfs属性,允许通过文件系统进行交互。使用时需要定义对应的show和store函数,并在类创建后注册这些属性。</think>在Linux内核中,`CLASS_ATTR`宏用于为设备类(class)创建sysfs属性,允许通过文件系统暴露设备类的配置或状态信息。其定义和用法如下: --- ### 定义与结构 `CLASS_ATTR`宏定义在头文件`include/linux/device/class.h`中,其核心逻辑基于通用属性宏`__ATTR`,典型定义如下: ```c #define CLASS_ATTR(_name, _mode, _show, _store) \ struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) ``` - **`_name`**: 属性文件名(如`my_attr`对应`/sys/class/my_class/my_attr`)。 - **`_mode`**: 文件权限(如`0644`)。 - **`_show`和`_store`**: 用户读写属性时的回调函数。 --- ### 使用步骤 1. **定义show/store函数** 函数需符合以下原型: ```c // 读取属性 ssize_t show_func(struct class *class, struct class_attribute *attr, char *buf); // 写入属性 ssize_t store_func(struct class *class, struct class_attribute *attr, const char *buf, size_t count); ``` 2. **声明属性** 使用`CLASS_ATTR`宏生成`class_attribute`结构体: ```c static CLASS_ATTR(my_attr, 0644, show_func, store_func); ``` 3. **注册到设备类** 在设备类创建后,通过`class_create_file`添加属性: ```c struct class *my_class = class_create(THIS_MODULE, "my_class"); class_create_file(my_class, &class_attr_my_attr); ``` 4. **注销属性** 在模块卸载时移除属性: ```c class_remove_file(my_class, &class_attr_my_attr); class_destroy(my_class); ``` --- ### 示例代码 ```c #include <linux/device.h> static ssize_t version_show(struct class *cls, struct class_attribute *attr, char *buf) { return sprintf(buf, "1.0.0\n"); } static CLASS_ATTR(version, 0444, version_show, NULL); static int __init my_module_init(void) { struct class *my_class = class_create(THIS_MODULE, "my_class"); if (IS_ERR(my_class)) return PTR_ERR(my_class); if (class_create_file(my_class, &class_attr_version)) { class_destroy(my_class); return -1; } return 0; } static void __exit my_module_exit(void) { class_remove_file(my_class, &class_attr_version); class_destroy(my_class); } module_init(my_module_init); module_exit(my_module_exit); ``` 此示例会在`/sys/class/my_class/version`中创建只读文件,内容为`1.0.0`[^1]。 --- ### 注意事项 1. **内存安全**:`show`函数需避免越界访问缓冲区`buf`。 2. **并发控制**:若属性被多线程访问,需通过锁(如`mutex`)保护共享数据。 3. **内核版本差异**:高版本内核可能提供简化宏(如`CLASS_ATTR_RO`仅需`show`函数)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值