> 文档中心 > linux内核源码分析之proc文件系统(三)

linux内核源码分析之proc文件系统(三)

目录

一、数据结构分析

1、proc数据项的表示proc_dir_entry

2、proc inode

二、proc初始化

三、管理/proc数据项

1. 数据项的创建和注册

2. 查找proc数据项

三、读取和写入信息

四、进程相关的信息

1、创建目录inode

2、处理文件


一、数据结构分析

1、proc数据项的表示proc_dir_entry

proc文件系统中的每个数据项都由proc_dir_entry 的一个实例描述

struct proc_dir_entry {spinlock_t pde_unload_lock;struct completion *pde_unload_completion;const struct inode_operations *proc_iops;union {const struct proc_ops *proc_ops;const struct file_operations *proc_dir_ops;};const struct dentry_operations *proc_dops;proc_write_t write;...}

实例

struct proc_dir_entry proc_root = {.low_ino= PROC_ROOT_INO, .namelen= 5, .mode= S_IFDIR | S_IRUGO | S_IXUGO, .nlink= 2, .refcnt= REFCOUNT_INIT(1),.proc_iops= &proc_root_inode_operations, //对proc根目录几乎不能做什么.proc_dir_ops= &proc_root_operations,//proc目录是特别的,因为其中包含了目录,因而不能对该目录使用通用处理函数.parent= &proc_root,.subdir= RB_ROOT,.name= "/proc",};

2、proc inode

内核提供了一个数据结构,称之为 proc_inode ,支持以面向 inode 的方式来查看 proc 文件系统的 数据项。

//proc的数据与VFS层的inode数据关联起来,struct proc_inode {struct pid *pid;unsigned int fd;union proc_op op;struct proc_dir_entry *pde;//pde是一个指针,指向关联到proc数据项的proc_dir_entry实例struct ctl_table_header *sysctl;struct ctl_table *sysctl_entry;struct hlist_node sysctl_inodes;const struct proc_ns_operations *ns_ops;struct inode vfs_inode;} __randomize_layout;

两个结构体之间的关系

proc_inode中的成员pde是一个指针,指向关联到proc数据项的proc_dir_entry实例

二、proc初始化

初始化,装载文件系统

三、管理/proc数据项

proc 文件系统投入使用之前,必须向其中添加数据项。内核提供了几个辅助例程来添加文件、 创建目录

1. 数据项的创建和注册

内核中有相关的宏定义

#define proc_create_seq_private(name, mode, parent, ops, size, data) ({NULL;})#define proc_create_seq_data(name, mode, parent, ops, data) ({NULL;})#define proc_create_seq(name, mode, parent, ops) ({NULL;})#define proc_create_single(name, mode, parent, show) ({NULL;})#define proc_create_single_data(name, mode, parent, show, data) ({NULL;})#define proc_create(name, mode, parent, proc_ops) ({NULL;})#define proc_create_data(name, mode, parent, proc_ops, data) ({NULL;})

在创建了数据项之后,绑定相关的操作函数 文件相关的 :proc_ops,  proc_file_inode_operations 目录相关的 :proc_dir_operations,proc_dir_inode_operations 连接相关的 :proc_link_inode_operations使用 proc_register 将其注册到 proc 文件系统,5.6.18 内核先绑定相关的操作函数如

struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,struct proc_dir_entry *parent,const struct proc_ops *proc_ops, void *data){struct proc_dir_entry *p;p = proc_create_reg(name, mode, &parent, data);if (!p)return NULL;p->proc_ops = proc_ops;return proc_register(parent, p);}

2. 查找proc数据项

分为进程pid相关的查找,和普通查找

static const struct inode_operations proc_root_inode_operations = {.lookup= proc_root_lookup,.getattr= proc_root_getattr,};static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags){if (!proc_pid_lookup(dentry, flags))//PIDreturn NULL;return proc_lookup(dir, dentry, flags);}

三、读取和写入信息

使用proc_ops, 而不是file_operations

struct proc_ops {int(*proc_open)(struct inode *, struct file *);ssize_t(*proc_read)(struct file *, char __user *, size_t, loff_t *);ssize_t(*proc_write)(struct file *, const char __user *, size_t, loff_t *);loff_t(*proc_lseek)(struct file *, loff_t, int);int(*proc_release)(struct inode *, struct file *);__poll_t (*proc_poll)(struct file *, struct poll_table_struct *);long(*proc_ioctl)(struct file *, unsigned int, unsigned long);#ifdef CONFIG_COMPATlong(*proc_compat_ioctl)(struct file *, unsigned int, unsigned long);#endifint(*proc_mmap)(struct file *, struct vm_area_struct *);unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);};

这里以读取CPU信息为例

extern const struct seq_operations cpuinfo_op;static int cpuinfo_open(struct inode *inode, struct file *file){arch_freq_prepare_all();return seq_open(file, &cpuinfo_op);}//读写相关的操作函数 static const struct proc_ops cpuinfo_proc_ops = {.proc_open= cpuinfo_open,.proc_read= seq_read,.proc_lseek= seq_lseek,.proc_release= seq_release,};//创建cpuinfo文件static int __init proc_cpuinfo_init(void){proc_create("cpuinfo", 0, NULL, &cpuinfo_proc_ops);return 0;}fs_initcall(proc_cpuinfo_init);

四、进程相关的信息

1、创建目录inode

//查看进程信息struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags){struct task_struct *task;unsigned tgid;struct pid_namespace *ns;struct dentry *result = ERR_PTR(-ENOENT);tgid = name_to_int(&dentry->d_name);if (tgid == ~0U)goto out;ns = dentry->d_sb->s_fs_info;rcu_read_lock();task = find_task_by_pid_ns(tgid, ns);if (task)get_task_struct(task);rcu_read_unlock();if (!task)goto out;result = proc_pid_instantiate(dentry, task, NULL);put_task_struct(task);out:return result;}

2、处理文件

因为特定于 PID 的目录,其内容总是同样的,内核源代码中定义了所有文件的静态列表以及其他一些信息,内核定义了静态参数.

static const struct pid_entry tgid_base_stuff[] = {REG("cmdline",    S_IRUGO, proc_pid_cmdline_ops),ONE("stat",S_IRUGO, proc_tgid_stat),ONE("statm",      S_IRUGO, proc_pid_statm),REG("maps",S_IRUGO, proc_pid_maps_operations),...}

参考内核学习连接

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂