sysfs - 用于导出内核对象的_文件系统 【ChatGPT】

简介: sysfs - 用于导出内核对象的_文件系统 【ChatGPT】

sysfs - _用于导出内核对象的_文件系统

Patrick Mochel mochel@osdl.org

Mike Murphy mamurph@cs.clemson.edu

修订日期 2011年8月16日

原始日期 2003年1月10日

它是什么

sysfs是一个基于ramfs的基于RAM的文件系统。它提供了一种将内核数据结构、它们的属性以及它们之间的链接导出到用户空间的方法。

sysfs与kobject基础结构密切相关。有关kobject接口的更多信息,请阅读《关于kobjects、ksets和ktypes的一切你从未想过的》。

使用sysfs

如果定义了CONFIG_SYSFS,sysfs将始终被编译进内核。您可以通过以下方式访问它:

mount -t sysfs sysfs /sys

目录创建

对于系统注册的每个kobject,都会在sysfs中为其创建一个目录。该目录被创建为kobject的父目录的子目录,向用户空间表达内部对象层次结构。sysfs中的顶级目录表示对象层次结构的共同祖先;即对象所属的子系统。

sysfs在内部存储指向实现目录的kobject的指针,该指针与与目录关联的kernfs_node对象相关联。在过去,sysfs使用此kobject指针直接对kobject进行引用计数,每当打开或关闭文件时。使用当前的sysfs实现,kobject引用计数仅通过函数sysfs_schedule_callback()直接修改。

属性

属性可以以文件的形式导出为kobjects。sysfs将文件I/O操作转发到为属性定义的方法,提供了一种读取和写入内核属性的方法。

属性应该是ASCII文本文件,最好每个文件只包含一个值。需要注意的是,每个文件只包含一个值可能不够高效,因此可以接受以社会接受的方式表达相同类型的值数组。

混合类型、表达多行数据和对数据进行花式格式化都是不被赞同的。这样做可能会导致您被公开羞辱,并且您的代码可能会在不经通知的情况下被重写。

属性定义很简单:

struct attribute {
char                    *name;
struct module           *owner;
umode_t                 mode;
};
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);

一个简单的属性不包含读取或写入属性值的方法。鼓励子系统为特定对象类型定义自己的属性结构和包装函数来添加和移除属性。

例如,驱动程序模型定义了struct device_attribute,如下所示:

struct device_attribute {
struct attribute    attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
int device_create_file(struct device *, const struct device_attribute *);
void device_remove_file(struct device *, const struct device_attribute *);

它还定义了用于定义设备属性的辅助程序:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

例如,声明:

static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);

等同于:

static struct device_attribute dev_attr_foo = {
        .attr = {
                .name = "foo",
                .mode = S_IWUSR | S_IRUGO,
        },
        .show = show_foo,
        .store = store_foo,
};

请注意,如include/linux/kernel.h中所述,“OTHER_WRITABLE? 通常被认为是一个坏主意。”因此,尝试将sysfs文件设置为对所有人可写将失败,并恢复为“其他”模式。

对于常见情况,sysfs.h提供了方便的宏,以使定义属性更容易,并使代码更简洁和可读。上述情况可以缩短为:

static struct device_attribute dev_attr_foo = __ATTR_RW(foo);

可用于定义包装函数的辅助程序列表包括:

  • __ATTR_RO(name):
    假定默认的name_show和mode为0444
  • __ATTR_WO(name):
    假定只有name_store,并且被限制为0200模式,即仅根用户具有写访问权限。
  • __ATTR_RO_MODE(name, mode):
    用于更严格的只读访问;目前仅用例是EFI系统资源表(参见drivers/firmware/efi/esrt.c)
  • __ATTR_RW(name):
    假定默认的name_show、name_store,并将模式设置为0644。
  • __ATTR_NULL:
    将名称设置为NULL,并用作列表结束指示器(参见:kernel/workqueue.c)

特定于子系统的回调

当子系统定义新的属性类型时,它必须实现一组sysfs操作,以将读取和写入调用转发到属性所有者的show和store方法:

struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};

[子系统应该已经定义了一个struct kobj_type作为此类型的描述符,其中存储了sysfs_ops指针。有关更多信息,请参阅kobject文档。]

当读取或写入文件时,sysfs调用类型的适当方法。然后,方法将通用的struct kobject和struct attribute指针转换为适当的指针类型,并调用相关的方法。

举例说明:

#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct device_attribute *dev_attr = to_dev_attr(attr);
struct device *dev = kobj_to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->show)
                ret = dev_attr->show(dev, dev_attr, buf);
if (ret >= (ssize_t)PAGE_SIZE) {
printk("dev_attr_show: %pS returned bad count\n",
                                dev_attr->show);
        }
return ret;
}

读取/写入属性数据

要读取或写入属性,必须在声明属性时指定show()或store()方法。方法类型应该与为设备属性定义的方法一样简单:

ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);

即,它们应该只接受一个对象、一个属性和一个缓冲区作为参数。

sysfs分配了一个大小为(PAGE_SIZE)的缓冲区,并将其传递给方法。sysfs将为每次读取或写入调用方法一次。这迫使方法实现以下行为:

  • 在read(2)上,show()方法应填充整个缓冲区。请记住,一个属性应该只导出一个值,或者类似值的数组,因此这不应该太昂贵。
    这允许用户空间对整个文件进行部分读取,并随意进行前向寻址。如果用户空间将寻址回零或执行带有偏移量“0”的pread(2),则show()方法将被重新激活,以填充缓冲区。
  • 在write(2)上,sysfs期望在第一次写入时传递整个缓冲区。然后,sysfs将整个缓冲区传递给store()方法。在存储时,在数据后添加了一个终止空字符。这使得诸如sysfs_streq()之类的函数可以安全使用。
    在写入sysfs文件时,用户空间进程应首先读取整个文件,修改其希望更改的值,然后将整个缓冲区写回。
    属性方法实现在读取和写入值时应使用相同的缓冲区。

其他注意事项:

  • 写入会导致show()方法被重新激活,而不管当前文件位置如何。
  • 缓冲区的长度始终为PAGE_SIZE字节。在x86上,这是4096。
  • show()方法应返回打印到缓冲区中的字节数。
  • show()应仅在将要返回给用户空间的值进行格式化时使用sysfs_emit()或sysfs_emit_at()。
  • store()应返回从缓冲区使用的字节数。如果已使用整个缓冲区,只需返回计数参数。
  • show()或store()始终可以返回错误。如果出现错误值,请务必返回错误。
  • 通过sysfs引用计数其嵌入对象的对象将被固定在内存中。但是,对象表示的物理实体(例如设备)可能不存在。如有必要,请确保有一种方法来检查这一点。

设备属性的一个非常简单(并且天真)的实现是:

static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%s\n", dev->name);
}
static ssize_t store_name(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
snprintf(dev->name, sizeof(dev->name), "%.*s",
                (int)min(count, sizeof(dev->name) - 1), buf);
return count;
}
static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);

(请注意,真实的实现不允许用户空间为设备设置名称。)

顶级目录布局

sysfs目录布局公开了内核数据结构的关系。

顶级sysfs目录如下所示:

block/
bus/
class/
dev/
devices/
firmware/
fs/
hypervisor/
kernel/
module/
net/
power/

devices/包含设备树的文件系统表示。它直接映射到内核设备树,这是一个struct device的层次结构。

bus/包含内核中各种总线类型的扁平目录布局。每个总线的目录包含两个子目录:

devices/
drivers/

devices/包含系统中发现的每个设备的符号链接,指向根目录下设备的目录。

drivers/包含为该特定总线类型上的设备加载的每个设备驱动程序的目录(这假设驱动程序不跨多个总线类型)。

fs/包含一些文件系统的目录。当前,每个想要导出属性的文件系统必须在fs/下创建自己的层次结构(请参见./fuse.rst作为示例)。

module/包含所有加载的系统模块的参数值和状态信息,对于内置模块和可加载模块都是如此。

dev/包含两个目录:char/和block/。在这两个目录中,有名为<major>:<minor>的符号链接。这些符号链接指向给定设备的sysfs目录。/sys/dev提供了一种从stat(2)操作的结果快速查找设备的sysfs接口的方法。

有关驱动程序模型特定功能的更多信息,请参阅Documentation/driver-api/driver-model/。

待办事项:完成本节。

当前接口

sysfs当前存在以下接口层。

devices(include/linux/device.h)

结构:

struct device_attribute {
struct attribute    attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};

声明:

DEVICE_ATTR(_name, _mode, _show, _store);

创建/移除:

int device_create_file(struct device *dev, const struct device_attribute * attr);
void device_remove_file(struct device *dev, const struct device_attribute * attr);

总线驱动程序(include/linux/device.h)

结构:

struct bus_attribute {
struct attribute        attr;
ssize_t (*show)(const struct bus_type *, char * buf);
ssize_t (*store)(const struct bus_type *, const char * buf, size_t count);
};

声明:

static BUS_ATTR_RW(name);
static BUS_ATTR_RO(name);
static BUS_ATTR_WO(name);

创建/移除:

int bus_create_file(struct bus_type *, struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);

设备驱动程序(include/linux/device.h)

结构:

struct driver_attribute {
struct attribute        attr;
ssize_t (*show)(struct device_driver *, char * buf);
ssize_t (*store)(struct device_driver *, const char * buf,
size_t count);
};

声明:

DRIVER_ATTR_RO(_name)
DRIVER_ATTR_RW(_name)

创建/移除:

int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);

文档

sysfs目录结构和每个目录中的属性定义了内核与用户空间之间的ABI。与任何ABI一样,重要的是这个ABI是稳定的并且有适当的文档记录。所有新的sysfs属性必须在Documentation/ABI中进行记录。有关更多信息,请参阅Documentation/ABI/README。

相关文章
为内核对象添加引用计数器(krefs)【ChatGPT】
为内核对象添加引用计数器(krefs)【ChatGPT】
100 14
|
存储 缓存 网络协议
/proc文件系统 【ChatGPT】
/proc文件系统 【ChatGPT】
|
安全
FUSE文件系统 【ChatGPT】
FUSE文件系统 【ChatGPT】
|
1月前
|
机器学习/深度学习 数据采集 人工智能
从ChatGPT到文心一言:AI为什么能“懂人话”?——大语言模型的底层逻辑揭秘
从ChatGPT到文心一言:AI为什么能“懂人话”?——大语言模型的底层逻辑揭秘
264 9
|
4月前
|
传感器 存储 人工智能
ChatGPT让AI展现‘智能’魅力,函数调用和RAG如何助力迈向AI Agent?
本文由AI产品专家三桥君探讨了AI从被动响应到主动决策的演进路径,重点分析了函数调用和RAG技术在构建AI Agent中的关键作用。文章梳理了大模型能力的迭代(原生能力与涌现能力),技术演进的三个阶段(提示工程→函数调用→RAG),并提出AI Agent需具备环境感知、推理决策和行动执行的核心要素。AI产品专家三桥君认为,未来AGI需突破跨领域学习、实时更新和安全性挑战,最终实现如"贾维斯"般的智能伙伴。
196 1
ChatGPT让AI展现‘智能’魅力,函数调用和RAG如何助力迈向AI Agent?
|
4月前
|
机器学习/深度学习 人工智能 文字识别
浏览器AI模型插件下载,支持chatgpt、claude、grok、gemini、DeepSeek等顶尖AI模型!
极客侧边栏是一款浏览器插件,集成ChatGPT、Claude、Grok、Gemini等全球顶尖AI模型,支持网页提问、文档分析、图片生成、智能截图、内容总结等功能。无需切换页面,办公写作效率倍增。内置书签云同步与智能整理功能,管理更高效。跨平台使用,安全便捷,是AI时代必备工具!
373 8
|
9月前
|
人工智能 Linux API
Omnitool:开发者桌面革命!开源神器一键整合ChatGPT+Stable Diffusion等主流AI平台,本地运行不联网
Omnitool 是一款开源的 AI 桌面环境,支持本地运行,提供统一交互界面,快速接入 OpenAI、Stable Diffusion、Hugging Face 等主流 AI 平台,具备高度扩展性。
1004 94
Omnitool:开发者桌面革命!开源神器一键整合ChatGPT+Stable Diffusion等主流AI平台,本地运行不联网
|
10月前
|
机器学习/深度学习 人工智能 搜索推荐
哈佛推出全新类ChatGPT癌症诊断AI,登上Nature!准确率高达96%
哈佛大学研究团队开发的新型AI模型CHIEF,在《自然》期刊发表,癌症诊断准确率达96%。CHIEF基于深度学习,能自动识别、分类癌症并预测生存期,具高准确性、多任务能力和泛化性。它结合病理图像与基因组学等数据,显著提升诊断效率和个性化治疗水平,有望改善医疗资源不平等。但数据隐私和临床效果验证仍是挑战。论文见:https://www.nature.com/articles/s41586-024-07894-z
438 101
|
8月前
|
人工智能 编解码 运维
当ChatGPT能写情书、Sora会造电影:我们必须掌握的AI内容识别技能
随着AI技术迅猛发展,AI生成内容在文学、新闻、绘画等领域广泛应用,但其真假难辨、质量参差不齐,可能带来信息误导、知识产权侵犯及安全风险等问题。学会识别AI生成内容至关重要,包括通过逻辑漏洞排查、语言风格分析、生物特征异常检测等手段审核文本、图片和视频。人工审核在面对高隐蔽性内容时仍不可替代,需结合工具与上下文理解共同筑起防护屏障。守护真实信息、规避风险,是每个人在AI时代应尽的责任。
253 7
|
9月前
|
存储 人工智能 API
ChatGPT-on-WeChat:Star32.4k, DeepSeek加持!这款开源神器秒变AI助手,聊天体验直接起飞!
嗨,大家好,我是小华同学。今天为大家介绍一款结合DeepSeek引擎的开源项目——ChatGPT-on-WeChat,由开发者zhayujie打造。它将微信变成智能AI助手,支持文本、图片、语音对话,具备定时提醒、天气查询等扩展功能,完全开源且易于定制。项目地址:https://github.com/zhayujie/chatgpt-on-wechat。关注我们,获取更多优质开源项目和高效学习方法。
999 11

热门文章

最新文章