【linux kernel】linux内核伪文件系统—proc分析

linux内核伪文件系统—proc分析

一、proc文件系统简介

首先/proc文件系统是一个接口,linux内核通过它可以获取linux系统上的运行信息。很多用户空间程序都需要依靠/proc文件系统中的内容来完成它们的工作。如下图所示:

在这里插入图片描述
linux内核中运行的每一个用户进程都会对应/proc文件系统中的一个条目。例如:1号进程init。他在/proc对应的条目则为1。可以使用:

ls -l /proc/1

得到init进程相关的条目:
在这里插入图片描述
注意,linux系统中运行的用户进程都有对应的条目。因此,在开发过程中,可以查看对应的条目,从而得到系统中运行进程的相关信息。

  • 如果需要获取到init进程相关联的内存信息,则使用:
cat /proc/1/maps
  • 如果需要获取init进程的状态信息,则使用:
cat /proc/1/status
  • 如果需要获取系统中的处理器信息,则使用cpuinfo条目。

  • 如果需要获取系统内存的统计信息,则使用meminfo条目。

  • 如果需要获取linux内核版本的信息,则使用version条目。

对于/proc文件系统来说,其中给出了许多关于linux内核运行过程中的信息(这里不一一列举啦)。其中有很多的信息条目值得仔细分析和学习。同样的,也有很多软件帮助我们提取/proc文件系统中的条目信息。例如:top、ps命令等。

  • 通过修改/proc/sys目录下条目,可以动态更改内核参数或变量。

linux内核的这个机制,由sysctl接口提供了动态更改某些内核参数和变量的方法,而不需要重新编译linux内核或重新引导系统。其会在/proc/sys目录下生成一棵可修改的sysctl条目树。通过修改该目录下的值就可以动态的更改内核中的某些参数和变量。该机制在实际开发中非常好用。

二、proc文件系统源码分析

本小结将分析以下两个小问题:

(1)linux内核下的/proc文件系统如何创建条目?

(2)linux内核如何初始化/proc文件系统?

(2-1)linux内核下的/proc文件系统如何创建条目

/proc文件系统的源码位于(/fs/proc)目录下,如下图所示:

在这里插入图片描述

Makefile文件可知,其大致的一个编译流程。从其目录的源文件组织结构来看,大致与ls /proc命令下的条目相关联。例如:/proc目录下有个version条目,则在源码目录结构下将有一个对应的version.c源文件。来看一下该文件中的内容:

(/fs/proc/version.c)

static const struct file_operations version_proc_fops = {
	.open		= version_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static int __init proc_version_init(void)
{
	proc_create("version", 0, NULL, &version_proc_fops);
	return 0;
}
fs_initcall(proc_version_init);

fs_initcall宏定义:
(/include/linux/init.h)

#define __define_initcall(fn, id) \
	static initcall_t __initcall_##fn##id __used \
	__attribute__((__section__(".initcall" #id ".init"))) = fn; \
	LTO_REFERENCE_INITCALL(__initcall_##fn##id)

#define fs_initcall(fn)			__define_initcall(fn, 5)

从以上代码片段可见:version.c文件的写法与设备驱动的编写类似:定义一个struct file_operations,并指定对应的callback,然后使用proc_create()创建version条目,最后使用fs_initcall()宏进行初始化。(注:其目录下的许多文件都有类似的程序结构和写法,大同小异)

(2-2)linux内核如何初始化/proc文件系统

/proc是一个文件系统,那么在linux内核源码中,就应该使用struct file_system_type来描述。其定义如下(/fs/proc/root.c):

static struct file_system_type proc_fs_type = {
	.name		= "proc",
	.mount		= proc_mount,
	.kill_sb	= proc_kill_sb,
	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
};

【函数调用链】
​ 在start_kernel()函数中将调用proc_root_init()函数来初始化/proc文件系统。

(/fs/proc/root.c)

void __init proc_root_init(void)
{
	int err;

    //初始化 proc的inode cache
	proc_init_inodecache();
	err = register_filesystem(&proc_fs_type);
	if (err)
		return;

	proc_self_init();
	proc_thread_self_init();
	proc_symlink("mounts", NULL, "self/mounts");

	proc_net_init();

#ifdef CONFIG_SYSVIPC
	proc_mkdir("sysvipc", NULL);
#endif
	proc_mkdir("fs", NULL);
	proc_mkdir("driver", NULL);
	proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
	/* just give it a mountpoint */
	proc_create_mount_point("openprom");
#endif
	proc_tty_init();
	proc_mkdir("bus", NULL);
	proc_sys_init();
}

上述代码第7行,调用register_filesystem()函数向linux 内核注册/proc文件系统。

其次,上面代码中多处还调用proc_mkdir()函数创建对应的/proc下的条目((/fs/proc/generic.c)):

struct proc_dir_entry *proc_mkdir(const char *name,struct proc_dir_entry *parent)
{
	return proc_mkdir_data(name, 0, parent, NULL);
}

最后都将调用到共同的proc_mkdir_data()函数,如下定义(/fs/proc/generic.c):

struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
		struct proc_dir_entry *parent, void *data)
{
	struct proc_dir_entry *ent;

	if (mode == 0)
		mode = S_IRUGO | S_IXUGO;
	//创建proc下的目录节点
	ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
	if (ent) {
		ent->data = data;
		ent->proc_fops = &proc_dir_operations;
		ent->proc_iops = &proc_dir_inode_operations;
		parent->nlink++;
        //将通过__proc_create()创建出的目录节点添加到父节点
		if (proc_register(parent, ent) < 0) {
			kfree(ent);
			parent->nlink--;
			ent = NULL;
		}
	}
	return ent;
}
三、总结

​ 本文没有过多分析proc文件系统背后的实现细节和机制。描述了在开发中,/proc文件系统下关于系统运行的一些信条目信息;从源码角度简单分析了/proc文件系统,描述了linux内核启动过程中是如何初始化/proc文件系统的。


搜索关注【嵌入式小生】wx公众号获取更多精彩内容>>>>
请添加图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值