Linux SysFs文件系统分析3

Linux SysFs文件系统分析3(基于Linux6.6)---sysfs目录创建介绍

一、sysfs目录相关的文件操作接口定义

在 Linux 6.x 内核中,sysfs 提供了一种与用户空间交互的机制,其中包括了创建和删除目录、文件的接口。对于 sysfs 目录操作的接口,内核使用 kobject 和一些辅助函数来实现这些操作。以下是针对 Linux 6.x 内核的 sysfs 目录操作接口的定义和实现概述。

1. kobject_create_and_add:创建 kobject 目录

kobject_create_and_add 是一个常用的接口,用来创建一个新的 kobject 并将其添加到 sysfs 文件系统中。

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
  • name:目录的名称,最终会在 /sys 文件系统中创建一个以此名称命名的目录。
  • parent:父 kobject,指定新创建的 kobject 目录的父目录,通常可以是 kernel_kobj 或其他已有的 kobject

示例代码:

struct kobject *example_kobj;

example_kobj = kobject_create_and_add("example", kernel_kobj);
if (!example_kobj) {
    pr_err("Failed to create kobject\n");
}

这段代码会在 /sys/kernel/example 下创建一个名为 example 的目录。

2. kobject_add:将已创建的 kobject 添加到 sysfs

如果你已经有了一个 kobject 实例,并希望将其添加到 sysfs 文件系统中,可以使用 kobject_add 函数。

int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);
  • kobj:要添加的 kobject
  • parent:父 kobject,决定了新目录的位置。
  • fmt:目录名称的格式化字符串。
示例代码:
int ret;
ret = kobject_add(example_kobj, kernel_kobj, "example");
if (ret) {
    pr_err("Failed to add kobject to sysfs\n");
}

3. sysfs_create_dir:手动创建目录

在某些情况下,你可能希望手动创建一个空的目录。此时可以使用 sysfs_create_dir 来创建目录。

int sysfs_create_dir(struct kobject *kobj);
  • kobj:要创建的目录对应的 kobject

示例代码:

int ret = sysfs_create_dir(example_kobj);
if (ret) {
    pr_err("Failed to create sysfs directory\n");
}

4. sysfs_remove_dir:删除 sysfs 目录

一旦不再需要某个目录时,可以通过 sysfs_remove_dir 来删除该目录及其所有的子文件。

int sysfs_remove_dir(struct kobject *kobj);
  • kobj:要删除的目录对应的 kobject

示例代码:

sysfs_remove_dir(example_kobj);

5. kobject_put:释放 kobject

在删除 kobject 之前,确保释放它的引用。这通常通过 kobject_put 来完成,它会递减 kobject 的引用计数,并在引用计数为零时删除 kobject

void kobject_put(struct kobject *kobj);

示例代码:

kobject_put(example_kobj);

6. kobject_uevent:发送 uevent 通知

sysfs 目录和文件的创建和删除通常伴随有事件通知。kobject_uevent 函数用于发送 uevent 通知,供用户空间的 udev 或其他程序处理。

int kobject_uevent(struct kobject *kobj, enum kobject_action action);
  • kobj:目标 kobject
  • action:事件类型,可以是 KOBJ_ADD, KOBJ_REMOVE, KOBJ_CHANGE 等。

示例代码:

kobject_uevent(example_kobj, KOBJ_ADD);

7. 删除目录和属性

为了确保删除目录和属性时不发生内存泄漏,在释放 kobject 之前,通常要删除所有与该目录相关的文件或属性。这可以通过 sysfs_remove_file 来完成。

int sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
  • kobj:要从中删除文件的目录。
  • attr:指向要删除的 attribute

完整示例代码

以下是一个简单的示例,展示如何创建 sysfs 目录,并为其添加属性文件:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/init.h>

static struct kobject *example_kobj;

static ssize_t example_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
    return sprintf(buf, "Hello, Sysfs!\n");
}

static struct kobj_attribute example_attribute = __ATTR(example_file, 0444, example_show, NULL);

static int __init sysfs_example_init(void)
{
    int retval;

    // 创建 kobject 和 sysfs 目录
    example_kobj = kobject_create_and_add("example", kernel_kobj);
    if (!example_kobj)
        return -ENOMEM;

    // 创建属性文件
    retval = sysfs_create_file(example_kobj, &example_attribute.attr);
    if (retval)
        kobject_put(example_kobj);  // 失败时清理 kobject

    return retval;
}

static void __exit sysfs_example_exit(void)
{
    // 删除属性文件
    sysfs_remove_file(example_kobj, &example_attribute.attr);
    
    // 删除 kobject 及其所有属性
    kobject_put(example_kobj);
}

module_init(sysfs_example_init);
module_exit(sysfs_example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple example of creating sysfs directories and files");

二、SYSFS提供给kernel模块的目录创建接口

针对sysfs的目录相关的操作接口与变量,均在文件dir.c中实现,针对目录操作,主要介绍目录创建这几个接口。

3.1、目录创建

首先介绍目录创建接口,即sysfs_create_dir接口,该接口主要用于创建目录,其处理流程如下所示。

该接口主要完成的功能如下:

1.根据传递的kobject,获取该kobject的父目录对应的sysfs_dirent类型的变量:

    a. 若找到则记为parent_sd;

    b. 若没有找到,则以sysfs_root记为父目录对应的sysfs_dirent(即本次在sysfs文件系统的根目录下创建子目录)。

2.若父目录支持kobject namespace,则调用该kobject的ktype->namespace接口,获取namespace变量以及kobject_ns_type。

(在sysfs中,针对net device,为保证在同一个目录下支持多个相同名称的net device,sysfs文件系统中引入了namespace的概念,作为sysfs 目录/文件的tag。在创建目录及文件并将sysfs_dirent类型的变量插入到红黑树节点时,在判断是否存在相同的文件及目录时,也会根据kobject->name与sysfs_dirent->s_ns进行判断(sysfs目前仅支持net type一种namespace类型,关于sysfs namespace的详细内容,可在Documentation/sysfs-tagging.txt中有详细说明))

3.调用sysfs_new_dirent接口创建sysfs_dirent类型的变量,并设置其相应的namespace相关的成员;

4.调用sysfs_add_one(sysfs_add_one->__sysfs_add_one->sysfs_link_sibling),将该sysfs_dirent类型的变量插入到其父目录sysfs_dirent的子目录的红黑树节点中。至此完成目录的创建。

仅在上述第4步执行完成后,方可标识一个sysfs目录或文件的创建完成,因为在sysfs的readdir接口中,其根据父目录对应sysfs_dirent类型变量的s_dir.children.rb_node节点查找子节点,因此若一个sysfs_dirent变量未插入到一个父节点的s_dir.children.rb_node中,则尚未完成创建操作。

 

sysfs提供了sysfs_create_dir接口后,主要供kobject相关的接口kobject_add_internal使用,该接口实现了根据kobject变量创建对应目录及其属性文件的功能,该接口的处理流程如下。

1.调用kobj_kset_join,将该kobject插入到其所指向的kset的kob子链表中。

2.调用create_dir接口,创建该kobject对应的目录及属性文件。

kobject_add_internal接口主要由kobject_add_varg接口调用,而kobject_add_varg则由kobject_add、kobject_init_and_add。

3.2、举例应用

在 Linux 内核中,sysfs 提供了一种机制,允许内核模块创建目录、文件和属性,用于与用户空间进行交互。通常,内核模块会通过 kobject 和相关的 API 来创建 sysfs 目录和文件。

1. kobject_create_and_add()

创建一个 kobject 并将其与一个目录挂钩,是创建 sysfs 目录的关键步骤。kobject 是一个内核对象,它为 sysfs 中的目录提供了基本的支持。创建的目录会出现在 /sys 文件系统中。

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
  • name:指定目录的名称,最终会在 /sys 下显示。
  • parent:父级 kobject,通常是 kernel_kobj 或其他现有的 kobject,表示创建的目录是哪个父目录的子目录。

示例

struct kobject *example_kobj;

example_kobj = kobject_create_and_add("example", kernel_kobj);
if (!example_kobj) {
    pr_err("Failed to create kobject\n");
}

上述代码将在 /sys/kernel/example 下创建一个名为 example 的目录,kernel_kobj 是父目录。

2. sysfs_create_file()

一旦创建了一个 kobject,就可以为它添加属性文件(文件接口),这些属性文件可以供用户空间读取或写入。通过 sysfs_create_file() 来创建文件。

int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
  • kobj:指向 kobject 的指针,属性文件将被添加到这个 kobject 目录下。
  • attr:一个 struct attribute 结构体,它定义了属性文件的名称和操作。

struct attribute 结构体:

struct attribute {
    const char *name;
    umode_t mode;
};
  • name:文件名。
  • mode:文件的权限,例如:S_IRUGO(只读)、S_IWUSR(可写)等。

sysfs 属性的读取和写入通常通过 kobj_attribute 结构体来定义。

struct kobj_attribute {
    struct attribute attr;
    ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buf);
    ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count);
};
  • show:当用户从文件读取时调用。
  • store:当用户向文件写入时调用。

3. 创建属性文件的完整示例

以下是一个创建 sysfs 目录并为其添加属性文件的完整示例:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/init.h>

static struct kobject *example_kobj;

static ssize_t example_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
    return sprintf(buf, "Hello, Sysfs!\n");
}

static struct kobj_attribute example_attribute = __ATTR(example_file, 0444, example_show, NULL);

static int __init sysfs_example_init(void)
{
    int retval;

    // 创建 kobject 和 sysfs 目录
    example_kobj = kobject_create_and_add("example", kernel_kobj);
    if (!example_kobj)
        return -ENOMEM;

    // 创建属性文件
    retval = sysfs_create_file(example_kobj, &example_attribute.attr);
    if (retval)
        kobject_put(example_kobj);  // 失败时清理 kobject

    return retval;
}

static void __exit sysfs_example_exit(void)
{
    kobject_put(example_kobj);  // 删除 kobject 及其所有属性
}

module_init(sysfs_example_init);
module_exit(sysfs_example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple example of creating sysfs directories and files");

4. 操作说明

  1. 初始化阶段:在 sysfs_example_init 中,首先通过 kobject_create_and_add 创建一个 kobject,它表示 /sys/example 目录。然后,使用 sysfs_create_file() 创建了一个名为 example_file 的只读文件。

  2. 文件读取example_show 函数定义了文件读取时的行为,返回字符串 Hello, Sysfs!\n

  3. 退出阶段:在 sysfs_example_exit 中,通过 kobject_put() 删除 kobject,这会清理目录及其中的所有文件。

5. 总结

  • kobject_create_and_add() 是创建 sysfs 目录的核心接口。
  • sysfs_create_file() 用于创建与该目录关联的属性文件。
  • 属性文件的读取和写入通过 showstore 函数进行定义,允许内核模块与用户空间交互。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值