Linux sysfs_create_group属性组创建与bin_attribute

Linux sysfs_create_group属性组创建与bin_attribute
Linux sysfs_create_group属性组创建与bin_attributesysfs_create_group()是驱动程序向sysfs导出属性的标准接口它允许一次注册一组属性而无需逐一调用sysfs_create_file()。其函数原型位于fs/sysfs/group.cint sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);struct attribute_group的核心定义struct attribute_group {const char *name;umode_t (*is_visible)(struct kobject *, struct attribute *, int);umode_t (*is_bin_visible)(struct kobject *, struct bin_attribute *, int);struct attribute **attrs;struct bin_attribute **bin_attrs;};当grp-name为NULL时属性直接创建在kobj对应的sysfs目录下。当name非空时sysfs_create_group()先创建以name命名的子目录然后将所有属性放入该子目录中。实现上sysfs_create_group()首先计算属性数量然后调用internal_create_group()进行实际创建。关键步骤包含(1) 如果grp-name非空通过sysfs_create_dir_ns()创建子目录。(2) 遍历grp-attrs数组对每个attribute调用sysfs_add_file_mode_ns()创建普通属性文件。(3) 遍历grp-bin_attrs数组对每个bin_attribute调用sysfs_add_bin_file_mode_ns()创建二进制属性文件。属性文件在内核态通过struct attribute描述struct attribute {const char *name;umode_t mode;#ifdef CONFIG_DEBUG_LOCK_ALLOCbool ignore_lockdep:1;struct lock_class_key *key;struct lock_class_key skey;#endif};每个attribute对应一个sysfs文件show/store回调通过struct sysfs_ops从kobject的ktype中获取struct sysfs_ops {ssize_t (*show)(struct kobject *, struct attribute *, char *);ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);};当用户空间读取sysfs文件时内核调用sysfs_kf_read()它通过kobj-ktype-sysfs_ops-show()分发到具体实现。bin_attribute提供了对无格式二进制数据的读写能力这在大块数据传输如firmware、寄存器dump场景中远优于基于文本的attributestruct bin_attribute {struct attribute attr;size_t size;void *private;ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,char *, loff_t, size_t);ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,char *, loff_t, size_t);loff_t (*llseek)(struct file *, struct kobject *, struct bin_attribute *,loff_t, int);};bin_attribute突破了普通attribute单页缓冲区的限制。普通attribute的show()回调最多只能返回PAGE_SIZE字节的数据而bin_attribute的read()回调可以处理任意大小的数据块通过偏移和长度参数支持随机访问。典型的硬件寄存器dump实现static ssize_t regs_read(struct file *filp, struct kobject *kobj,struct bin_attribute *bin_attr,char *buf, loff_t off, size_t count){struct my_device *dev container_of(kobj, struct my_device, kobj);size_t regs_size 0x1000;if (off regs_size)return 0;if (off count regs_size)count regs_size - off;/* 从硬件寄存器空间读取 */memcpy_fromio(buf, dev-regs_base off, count);return count;}static BIN_ATTR(regs, 0400, regs_read, NULL, 0x1000);static struct bin_attribute *my_bin_attrs[] {bin_attr_regs,NULL,};static struct attribute_group my_group {.attrs my_attrs,.bin_attrs my_bin_attrs,};is_visible()和is_bin_visible()回调在属性创建前被调用返回值决定了属性文件的访问权限。返回0表示隐藏该属性。这种机制使得同一属性组可以根据设备能力动态调整可见性static umode_t my_is_visible(struct kobject *kobj, struct attribute *attr, int n){struct my_device *dev container_of(kobj, struct my_device, kobj);if (attr dev_attr_feature_x.attr !dev-has_feature_x)return 0;return attr-mode;}sysfs_update_group()用于在运行时更新属性组的权限和可见性它不会创建或删除属性文件只会修改已有文件的权限位。如果要动态添加属性需使用sysfs_add_group()或重新创建组。sysfs_remove_group()是逆向操作按相反顺序移除属性和子目录。需要注意sysfs_create_group()和sysfs_remove_group()必须配对调用否则会导致sysfs节点残留进而引发后续内核对象注册冲突。在设备驱动模型中devm_device_add_group()提供了资源管理版本当设备被注销时自动移除属性组省去了手动清理的麻烦。