proc相关操作

本文介绍了proc_file_operations结构体,重点关注read、write和info三个操作的钩子函数。详细阐述了read_proc_t、write_proc_t和get_info_t的参数及用途。此外,还讲解了在Linux内核中如何使用proc_mkdir和create_proc_entry函数创建proc目录和文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、数据结构

/proc下每个文件对应下面一个数据结构
struct proc_dir_entry {
    unsigned int low_ino;
    unsigned short namelen;
    const char *name;
    mode_t mode;
    nlink_t nlink;
    uid_t uid;
    gid_t gid;
    loff_t size;
    const struct inode_operations *proc_iops;
    /*
     * NULL ->proc_fops means \"PDE is going away RSN\" or
     * \"PDE is just created\". In either case, e.g. ->read_proc won\'t be
     * called because it\'s too late or too early, respectively.
     *
     * If you\'re allocating ->proc_fops dynamically, save a pointer
     * somewhere.
     */
    const struct file_operations *proc_fops;
    get_info_t *get_info;        //
    struct module *owner;
    struct proc_dir_entry *next, *parent, *subdir;
    void *data;
    read_proc_t *read_proc;        //
    write_proc_t *write_proc;    //
    atomic_t count;     /* use count */
    int pde_users;  /* number of callers into module in progress */
    spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
    struct completion *pde_unload_completion;
    shadow_proc_t *shadow_proc;    //
};

这个结构比较重要的就是3个钩子函数,分别用于 read write info操作

1、read操作:
typedef int(read_proc_t)(char *page,char **start,off_t off, int count, int *eof, void *data);
page:指示用来写入数据的缓冲区;
off和count:与read函数对应的参数相同;
start和eof:用于读取大于1个page数据时实现。

2、write操作:
typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);
filp 参数实际上是一个打开文件结构(可以忽略这个参数)。
buffer 参数是用户空间要写入的数据。缓冲区地址实际上是一个用户空间的缓冲区,不能直接读取它。
len 参数定义了在 buffer 中有多少数据要被写入。
data 参数是一个指向私有数据的指针。

3、info操作

typedef int (get_info_t)(char *, char **, off_t, int);


 

二、proc API

创建目录
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)

name: 文件夹的名字
parent: 确定文件所在目录,如果置NULL,则位置为/proc下。

创建文件
方法一:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent)
这是最直接,包装最少的创建方法。
name :是要创建的 proc 文件名。

mode : 是该文件权限值,例如 S_IRUGO,可传入0表示采用系统默认值。
parent :指定该文件的上层 proc 目录项,如果为 NULL,表示创建在 /proc 根目录下。
create_proc_entry() 完成的任务主要包括:检测 mode 值,分配 proc_dir_entry 结构,注册 proc_dir_entry。
 
create_proc_entry还有很多衍生 API
struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base,
    read_proc_t *read_proc, void * data)
{
    struct proc_dir_entry *res=create_proc_entry(name,mode,base);
    if (res) {
        res->read_proc=read_proc;
        res->data=data;
    }
    return res;
}

struct proc_dir_entry *create_proc_info_entry(const char *name,
    mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
{
    struct proc_dir_entry *res=create_proc_entry(name,mode,base);
    if (res) res->get_info=get_info;
    return res;
}

方法二:
static inline struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void * data)
{
    struct proc_dir_entry *res=create_proc_entry(name,mode,base);
    if (res) {
        res->read_proc=read_proc;
        res->data=data;
    }
    return res;
}

如果要创建一个只读的 proc 文件,可以采用 create_proc_read_entry() 这个接口。这个接口其实就是给 proc_dir_entry 多赋了两个值,其中 read_proc 是一个函数指针, data 是 read_proc 调用时传给它一个参数。关于 read_proc 函数,接下来会另行分析。

方法三:
struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops)
        如果要创建一个 proc 文件,并且不用 proc_fs 默认提供的 file_operations 的话,可以使用 proc_create() 这个函数,通过最后一个参数来指定要创建的 proc 文件的 file_operations。
        每个 proc 文件也都会用到 file_operations,在调用 create_proc_entry() 创建 proc 文件时,其中一步是调用 proc_register(),proc_register() 会为 proc_dir_entry 提供一个默认的 file_operations,而 proc_create() 与 create_proc_entry() 唯一差别就是在调用 proc_register() 前先设置好 proc_dir_entry 的 file_operations,这样在 proc_register() 时就不会设置使用 proc_fs 默认的 file_operations 了。
proc_fs 默认的 file_operations 定义如下:
static const struct file_operations proc_file_operations = {
    .llseek        = proc_file_lseek,
    .read        = proc_file_read,
    .write        = proc_file_write,
};
proc_create() 一般在创建使用 seq_file 接口的 proc 文件时会使用。


读 proc 文件
proc 文件的读需要自己提供一个 read_proc_t 类型的函数放在 proc_dir_entry 结构中供 proc_file_read() 函数调用。下面是 read_proc_t 类型函数的定义:
typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);
这个函数的定义很复杂,不过当 proc 文件返回的数据量总是小于一个 PAGE_SIZE 时可以简化使用。关于这个函数以及它的那一大串参数我觉得再怎么解释都解释不全,所以还是留给自己去看 proc_file_read() 的代码就明白了。

写 proc 文件
proc 文件的写很简单。如果是使用 proc_fs 默认提供的 file_operations 的话,要自己实现一个 write_proc_t 类型的函数放在 proc_dir_entry 结构中供 proc_file_write() 函数调用。write_proc_t 类型函数的定义如下:
typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);
下面是 proc_file_write() 的实现:
static ssize_t proc_file_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    struct inode *inode = file->f_path.dentry->d_inode;
    struct proc_dir_entry * dp;
 
    dp = PDE(inode);

    f (!dp->write_proc)
        return -EIO;

    /* FIXME: does this routine need ppos? probably... */
    return dp->write_proc(file, buffer, count, dp->data);
}
可见 proc 文件的写忽略了使用偏移量。

如果是使用自己提供的 file_operations 的话,那还是要自己实现一个 write 函数赋给 file_operations 的 .write 指针

删除一个 proc 项
要删除一个 proc 文件或目录就调用 void remove_proc_entry(const char *name, struct proc_dir_entry *parent)


删除文件或目录
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)

name: 文件夹或文件的名字
parent: 确定文件所在目录,如果置NULL,则位置为/proc下。

注意事项
proc 项创建时要避免已经存在同名的 proc 项,否则注册时内核会报错(但还是会成功返回那个 proc 项),在删除时有时会删不掉(尤其是 proc 目录)。
删除一个 proc 目录会把这个目录所有的 proc 文件都删除。


##################################################################################

常用proc文件大集合:

一、 /proc/devices        显示所有已分配的主设备号
-bash-3.2# cat /proc/devices
Character devices:
  1 mem
  2 pty
  3 ttyp
  5 /dev/tty
....略

二、/proc/sys/kernel/printk    显示和修改控制台的日志级别
-bash-3.2# cat /proc/sys/kernel/printk
6       4       1       7

四个整数分别是:
    当前日志级别
    未明确指定日志级别时默认消息级别
    最小允许的日志级别
    引导时的默认日志级别

若让所有控制消息显示在控制台,则
echo \"0 0 0 0\" > /proc/sys/kernel/printk


三、/proc/iomem     显示mem地址分布

-bash-3.2# cat /proc/iomem
80000000-9fffffff : PCI1 host bridge
  a2000800-a2000807 : pata_85xx_cf.0
  a200080e-a200080e : pata_85xx_cf.0
  9ff90000-9ff9ffff : 0000:00:0c.1
    9ff90000-9ff9ffff : e1000
  9ffa0000-9ffbffff : 0000:00:0c.1
    9ffa0000-9ffbffff : e1000
。。。略


四、/proc/ioports 显示IO资源分布
-bash-3.2# cat /proc/ioports
00000000-00ffffff : PCI1 host bridge
  00ffff80-00ffffbf : 0000:00:0c.1
    00ffff80-00ffffbf : e1000
  00ffffc0-00ffffff : 0000:00:0c.0
    00ffffc0-00ffffff : e1000

五、/proc/interrupts  显示外部中断信息
-bash-3.2# cat /proc/interrupts
           CPU0
 41:         35   CPM2 SIU  Level     cpm_uart
 77:        132   OpenPIC   Level     enet_tx
 78:     487854   OpenPIC   Level     enet_rx
 82:          0   OpenPIC   Level     enet_error
 91:       1417   OpenPIC   Level     i2c-mpc
 94:         35   OpenPIC   Level     cpm2_cascade
BAD:          0

六、/proc/uptime    显示系统运行时间

the uptime of the system(seconds),
and the amount of time spent in idle process(seconds).   

-bash-3.2# cat /proc/uptime
5603.90 5587.39

七、/proc/net/dev    显示网络设备收发包统计信息

-bash-3.2# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:    6924      29    0    0    0     0          0         0     6924      29    0    0    0     0       0          0
  eth0:22376982  352073    0    0    0     0          0         0 493743767 19521668    0    0   26     0       0          0
  eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth2:68372765 1016385    0    0    0     0          0       263   668734    5119    0    0    0     0       0          0
  eth3:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
 bond0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
dummy0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

八、/proc/kallsyms  显示当前内核的符号表


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值