iT邦幫忙

2024 iThome 鐵人賽

DAY 12
0
自我挑戰組

Linux Kernel 網路巡禮系列 第 12

初探 PROC 檔案系統

  • 分享至 

  • xImage
  •  

今天,我們要接續介紹 proc 檔案系統

proc 檔案系統是一個特殊的虛擬檔案系統,通常會掛載在 /proc 路徑下。透過 proc 檔案系統,我們可以與 kernel 互動,了解各個 process 的資訊,甚至進行某些特殊操作。

proc 檔案結構

當我們查看 /proc 目錄時,可以看到如下所示的內容:

> ls /proc
1 2 3 4 filesystems sys
...

> ls /proc/1
comm mem fd ns ...
...

/proc 資料夾中,每個 process 會有一個以 PID(Process ID)為名稱的資料夾。此外,還有一些特殊的檔案或資料夾對應到某些 kernel 功能。在 /proc/<pid> 資料夾中,包含了該 process 的各式資訊的檔案與資料夾,這些資訊涵蓋執行檔案名稱、工作目錄、記憶體分配狀況等。

Proc 檔案系統的推測

在深入了解 VFS(Virtual File System)系統後,我們可以推測 proc 檔案系統是如何實現的。首先,proc 檔案系統定義了自己的檔案系統驅動。當我們訪問 /proc 資料夾時,proc 檔案系統驅動會存取 kernel 中 task_struct 的列表,藉此知道有哪些 process,並動態生成名稱為 PID 的 dentry。

在對 VFS 系統有了一個完整了解後,我們可以直接猜到 proc 檔案系統是怎麼實現的,首先 proc 檔案系統定義了自己的檔案系統驅動。當我們訪問 proc 資料夾時,proc 檔案系統驅動會存取 kernel 資料結構 task_struct的列表,了解到有哪些process,動態生成名稱為pid 的 dentry。

當我們執行 cat /proc/<pid>/comm 指令讀取 process 1 的執行檔案名稱時,read system call 會執行由 proc 檔案系統定義的特殊 read inode_operation。該 read 函數會讀取該 process 的 task_struct 並將其資訊返回。

Proc 檔案系統程式碼觀察

// proc/base.c
static const struct pid_entry tgid_base_stuff[] = {
	DIR("task",       S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
	DIR("fd",         S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
	DIR("map_files",  S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations),
	DIR("fdinfo",     S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations),
	DIR("ns",	  S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
#ifdef CONFIG_NET
	DIR("net",        S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
#endif
    REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
    ...

從這個程式碼片段可以觀察出,在 /proc/<pid> 目錄下的檔案與資料夾,其實是在程式碼中靜態定義的。例如我們前面提到的 /proc/<pid>/comm,根據程式碼定義,它是一個一般檔案(REG),使用的 file_operationsproc_pid_set_comm_operations

// proc/base.c
static const struct file_operations proc_pid_set_comm_operations = {
	.open		= comm_open,
	.read		= seq_read,
	.write		= comm_write,
	.llseek		= seq_lseek,
	.release	= single_release,
};

上面這段程式碼中,proc_pid_set_comm_operations 定義了該檔案的操作方式,包括 openreadwrite 等。這裡的 read 函數使用的是 seq_read,這是一種由 kernel 提供的特殊用法。當 application 進行 read 操作時,proc 檔案系統會先將要讀取的內容寫到一個虛擬的 seq_file 中,再由 seq_read 輸出。

當檔案被打開時,會呼叫 comm_open 函數,而在 comm_open 中又會呼叫 comm_show

static int comm_open(struct inode *inode, struct file *filp)
{
	return single_open(filp, comm_show, inode);
}

static int comm_show(struct seq_file *m, void *v)
{
	struct inode *inode = m->private;
	struct task_struct *p;

	p = get_proc_task(inode); // 取得目標 process 的 task_struct
	if (!p)
		return -ESRCH;

	proc_task_name(m, p, false); // 從 task_struct 拿到 comm
	seq_putc(m, '\n'); // 寫入 seq_file

	put_task_struct(p);

	return 0;
}

comm_show 函數會從指定的 process 的 task_struct 中取得執行檔案名稱(comm),然後將其寫入 seq_file。當應用程式呼叫 read 時,最終會從 seq_file 中讀取並返回該資訊。

小結

proc 檔案系統 是 Linux kernel 提供的非常重要的工具,在對 VFS 系統有深入的了解後,我們已經可以很容易了解 proc 檔案系統的原理了。


上一篇
番外篇 (3) mknod 與 device driver
下一篇
網路命名空間、proc檔案系統與nsfs檔案系統 (1)
系列文
Linux Kernel 網路巡禮14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言