• Linux 文件系统:procfs, sysfs, debugfs 用法简介


    1 前言

    内核中有三个常用的伪文件系统:procfs,debugfs和sysfs。

    1. procfs — The proc filesystem is a pseudo-filesystem which provides an interface to kernel data structures.
    2. sysfs — The filesystem for exporting kernel objects.
    3. debugfs — Debugfs exists as a simple way for kernel developers to make information available to user space.

    它们都用于Linux内核和用户空间的数据交换,但是适用的场景有所差异:

    1. procfs 历史最早,最初就是用来跟内核交互的唯一方式,用来获取处理器、内存、设备驱动、进程等各种信息。
    2. sysfs 跟 kobject 框架紧密联系,而 kobject 是为设备驱动模型而存在的,所以 sysfs 是为设备驱动服务的。
    3. debugfs 从名字来看就是为debug而生,所以更加灵活。

    它们仨的挂载方式类似,做个实验:

    1. $ sudo mkdir /tmp/{proc,sys,debug}
    2. $ sudo mount -t proc nondev /tmp/proc/
    3. $ sudo mount -t sys nondev /tmp/sys/
    4. $ sudo mount -t debugfs nondev /tmp/debug/

    不过,默认情况下,它们分别挂载在/proc,/sys/,/sys/kernel/debug/。

    下面简单介绍这三个文件系统的用法。在介绍之前,请记下他们的官方文档:

    1. procfs — Documentation/filesystems/proc.txt
    2. sysfs — Documentation/filesystems/sysfs.txt
    3. debugfs — Documentation/filesystems/debugfs.txt

    2 debugfs
    API说明

    1. struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
    2. struct dentry *debugfs_create_file(const char *name, umode_t mode,
    3. struct dentry *parent, void *data,
    4. const struct file_operations *fops)
    5. 参考实例
    6. drivers/base/power/wakeup.c:
    7. /**
    8. * wakeup_sources_stats_show - Print wakeup sources statistics information.
    9. * @m: seq_file to print the statistics into.
    10. */
    11. static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
    12. {
    13. struct wakeup_source *ws;
    14. seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
    15. "expire_count\tactive_since\ttotal_time\tmax_time\t"
    16. "last_change\tprevent_suspend_time\n");
    17. rcu_read_lock();
    18. list_for_each_entry_rcu(ws, &wakeup_sources, entry)
    19. print_wakeup_source_stats(m, ws);
    20. rcu_read_unlock();
    21. return 0;
    22. }
    23. static int wakeup_sources_stats_open(struct inode *inode, struct file *file)
    24. {
    25. return single_open(file, wakeup_sources_stats_show, NULL);
    26. }
    27. static const struct file_operations wakeup_sources_stats_fops = {
    28. .owner = THIS_MODULE,
    29. .open = wakeup_sources_stats_open,
    30. .read = seq_read,
    31. .llseek = seq_lseek,
    32. .release = single_release,
    33. };
    34. static int __init wakeup_sources_debugfs_init(void)
    35. {
    36. wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
    37. S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);
    38. return 0;
    39. }
    40. 创建完的接口
    41. /sys/kernel/debug/wakup_sources
    42. 给接口添加多级目录
    43. 上述接口直接创建在 debugfs 根目录(/sys/kernel/debug)下,所以 debugfs_create_file的parent参数被设置成了NULL,如果要加一级目录,则可以先用 debugfs_create_dir 创建一级目录,例如,要创建:/sys/kernel/debug/power/wakeup_sources 的话,则需要:
    44. struct dentry *power;
    45. int err = -ENOMEM;
    46. power = debugfs_create_dir("power", NULL);
    47. if (!power)
    48. return err;
    49. wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
    50. S_IRUGO, power, NULL, &wakeup_sources_stats_fops);

    3 procfs

    1. API说明
    2. static inline struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
    3. static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode,
    4. struct proc_dir_entry *parent, const struct file_operations *proc_fops)
    5. 参考实例
    6. 在上面例子的基础上,可以添加如下语句:
    7. static int __init wakeup_sources_debugfs_init(void)
    8. {
    9. proc_create("wakelocks", S_IFREG | S_IRUGO, NULL, &wakeup_sources_stats_fops);
    10. return 0;
    11. }
    12. 创建后的接口
    13. /proc/wakelocks
    14. 给接口添加多级目录
    15. 这样创建的接口用起来跟 /sys/kernel/debug/wakeup_sources 没有任何差异,类似地,如果要加一级目录,例如 /proc/power/wakelocks,则可以:
    16. struct proc_dir_entry *power;
    17. int err = -ENOMEM;
    18. power = proc_mkdir("power", NULL);
    19. if (!power)
    20. return err;
    21. proc_create("wakelocks", S_IFREG | S_IRUGO, power, &wakeup_sources_stats_fops);
    22. proc_mkdir 用法跟 debugfs_create_dir 几无差异。

    4 sysfs

    1. API说明
    2. struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
    3. int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
    4. static inline int sysfs_create_link(struct kobject *kobj, struct kobject *target, const char *name)
    5. int device_create_file(struct device *dev, const struct device_attribute *attr)
    6. 参考实例
    7. /sys/power 下创建一个 wakelocks 节点,用于读/写一个字符串。
    8. static char test_str[11];
    9. static ssize_t show_wakelocks(struct kobject *kobj, struct attribute *attr, char *buf)
    10. {
    11. int ret;
    12. ret = snprintf(buf, 10, "%s\n", test_str);
    13. return ret;
    14. }
    15. static ssize_t store_wakelocks(struct kobject *kobj, struct attribute *attr,
    16. const char *buf, size_t count)
    17. {
    18. int tmp;
    19. ret = sscanf(buf, "%10s", test_str);
    20. if (ret != 1)
    21. return -EINVAL;
    22. return count;
    23. }
    24. define_one_global_rw(wakelocks);
    25. static int __init wakelocks_init(void)
    26. {
    27. int ret;
    28. ret = sysfs_create_file(power_kobj, &wakelocks.attr);
    29. }
    30. 创建后的节点
    31. /sys/power/test_node
    32. 给接口添加多级目录
    33. 咱们上面其实已经把 test_node 创建在 /sys/power 目录下,而非根目录 /sys 下,而参数 power_kobj 为内核已经在 kernel/power/main.c 创建的kobject对象。
    34. struct kobject *power_kobj;
    35. power_kobj = kobject_create_and_add("power", NULL);
    36. if (!power_kobj)
    37. return -ENOMEM;
    38. 在 sysfs 中,有另外一个常见用法,那就是在一个 kobject 对应的目录下创建一个符号(属性文件)指向另外一个 kobject 对应的目录,通常这个是为了方便记忆和访问。这个API是 sysfs_create_link。
    39. 这种创建符号链接方法其实有一个很特殊的实例,那就是在驱动模型里头,有一个 class 的概念,它把挂在不同总线上,但是实现类似功能的设备进行归类,比如说 input 类,backlight 类等。
    40. 如果设备属于一个现存的类,比如 backlight,那么可以用 backlight_device_register 创建,如果是 I2C 设备,会先在I2C下创建 sysfs 访问节点,并创建一个符号链接到 backlight 类所属的目录下。
    41. 当然,如果没有找到设备能挂的直观的类,也可以用 class_create 创建类,设备类通常会有一组默认的设备操作接口,例如 backlight 类有 bl_device_attributes,如果要创建更多的设备特定的节点,可以用 device_create_file 或者 device_add_groups 创建节点或者节点群。

    5 小结

    通过比较发现,上述三个文件系统的 API 用法类似,而其中 debugfs 和 procfs 几乎有相同的参数,用的主要结构体是 struct file_operations,蛮多操作可以用 seq_* 家族的函数来实现。而 sysfs 则用到比较简单一些的 struct global_attr 结构体。对于提供给用户空间的节点,都可以轻松实现读写操作。

    在创建目录方面,debugfs 和 procfs 类似,且比较简单。而 sysfs 要创建一级目录,需要先创建一个 kobject 对象。

    为了简化设备模型依据总线创建的访问节点路径,sysfs 提供了API用于创建更简易的符号链接,可以创建到自己指定的目录下,也可以用设备类(Class)提供的API创建到设备类所属的目录下。

    对于 sysfs,由于 kobject 与 device 的一对一依存关系,也可以直接用 device_create_file 来创建节点。

  • 相关阅读:
    Linux ubuntu 20.04.5 Server桌面设置NetworkManager网络管理
    PDFView4NET 2022.09.02 Crack
    SwiftUI 2.0 课程笔记 Chapter 6
    【C++】C++11 ——— 类的新功能
    vue通过接口下载文件的封装及使用
    Linux软件管理
    Spring Boot、Spring MVC 和 Spring Cloud 深度解析
    AI趋势量化系统(Binance升级版)
    上海亚商投顾:沪指放量涨1.69% 房地产板块掀涨停潮
    Chat GPT 使用教学,文字创作、学习
  • 原文地址:https://blog.csdn.net/m0_62089210/article/details/127400051