/procのls一覧表示について
Rev.1を表示中。最新版はこちら。
プロック擬似ファイルは実ファイルを持たないファイルシステムであり、このファイルを介してシステム情報およびプロセス情報をを設定確認できる機能を提供している。
[root@localhost proc]# ls -f . mtrr vmstat loadavg 151 542 .. irq pagetypeinfo self 155 543 crypto cgroups buddyinfo 1 156 592 key-users sys vmallocinfo 2 157 914 keys bus slabinfo 3 159 1276 swaps tty interrupts 4 164 1277 latency_stats driver stat 5 167 1278 kallsyms fs partitions 6 217 1301 dma sysvipc cpuinfo 7 218 1384 timer_stats net devices 8 219 1393 timer_list sysrq-trigger locks 9 267 1404 iomem vmcore kmsg 10 268 1405 ioports kpageflags mounts 11 456 1483 sched_debug kpagecount execdomains 85 459 1521 mdstat kcore cmdline 86 494 1523 scsi schedstat filesystems 88 501 2112 misc modules version 89 504 acpi diskstats meminfo 91 537 fb zoneinfo uptime 92 541
本ファイルシステムは、proc_root_initでprocファイルシステム登録、マウント処理が行われ、マウ
ント処理後、struct proc_dir_entry proc_rootをrootエントリーとして、proc_misc_init等でシス
テムに関するものはprocファイルシステム以下に静的にディレクトリが作成され、プロセスに関する
ものは動的に作成されるようになっている。
lsで/proc下のファイルを表示した場合、file_opretaionのproc_root_inode_operationsの.readdir
のコールバック関数により/proc下のファイル一覧情報が取得される。このfile_opretaionはマウン
ト時にスーパブロック取得において、rootのinodeに設定されるのinodeオペレーションにproc_root
の.proc_fopsをinode->i_fopに設定することで実現している。
struct proc_dir_entry proc_root = { .low_ino = PROC_ROOT_INO, .namelen = 5, .name = "/proc", .mode = S_IFDIR | S_IRUGO | S_IXUGO, .nlink = 2, .count = ATOMIC_INIT(1), .proc_iops = &proc_root_inode_operations, .proc_fops = &proc_root_operations, .parent = &proc_root, }; static const struct file_operations proc_root_operations = { .read = generic_read_dir, .readdir = proc_root_readdir, };
mount時に呼ばれてスーパブロックを取得する。この時rootのinodeにproc_rootの時に.proc_iopsお
よび.proc_fopsが設定される。
int proc_fill_super(struct super_block *s)
{
・・・・・ struct inode * root_inode;
s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; s->s_time_gran = 1; de_get(&proc_root); root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; root_inode->i_uid = 0; root_inode->i_gid = 0; s->s_root = d_alloc_root(root_inode); ・・・・・
struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
struct proc_dir_entry *de){
・・・・・ if (de->proc_iops) ルートのIノードオペレーションにproc_root_inode_operationsを設定 inode->i_op = de->proc_iops; if (de->proc_fops) { ・・・・・ ルートのIノードファイルオペレーションにproc_root_operationsを設定 inode->i_fop = de->proc_fops; ・・・・・これでlsで/proc一覧表示させると、rootのinodeオペレーションとしてproc_root_operations
の.readdir = proc_root_readdirが呼ばれることになる。最初にproc_readdirで/proc下の静的に作
成されているディレクトリーが表示させ、proc_pid_readdirで動的にプロセスIDを表示させる。
static int proc_root_readdir(struct file * filp, void * dirent, filldir_t filldir) { ・・・・・ if (nr < FIRST_PROCESS_ENTRY) { プロセスIDでないものを表示 int error = proc_readdir(filp, dirent, filldir); if (error <= 0) { unlock_kernel(); return error; } filp->f_pos = FIRST_PROCESS_ENTRY; } selfおよびプロセスIDを表示 ret = proc_pid_readdir(filp, dirent, filldir); return ret; }
proc_readdirはproc_readdir_deを呼び出して、"."、".."および静的に作成した/procファイル以下
のディレクトリー一覧が表示し、proc_pid_readdirでselfディレクトリーを表示して後、next_tgid
でプロセスIDを1から順に、その時のスレッドグループIDを取得し、そのプロセスIDを表示するよう
になっている。next_tgidでPIDTYPE_PIDにつながれたプロセスIDから、グループリーダのプロセス
IDを返す。それをプロセスIDを1から順に調べることで、システムの全グループリーダのプロセ
スIDを表示している。このことから一覧で表示されるプロセスIDは表示だけのもので、この段階
ではその実態(inode等)は有していない。
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { ・・・・・ ns = filp->f_dentry->d_sb->s_fs_info; iter.task = NULL; iter.tgid = filp->f_pos - TGID_OFFSET; for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { filp->f_pos = iter.tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { put_task_struct(iter.task); goto out; } } filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; ・・・・・ }
static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) { ・・・・・
iter.task = NULL; pid = find_ge_pid(iter.tgid, ns); if (pid) { iter.tgid = pid_nr_ns(pid, ns); iter.task = pid_task(pid, PIDTYPE_PID); if (!iter.task || !has_group_leader_pid(iter.task)) { iter.tgid += 1; goto retry; } get_task_struct(iter.task); } rcu_read_unlock(); return iter; }
補足
プロセスID以外はファイルシステム作成時、proc_misc_initがコールされ、proc_createでディレ
クトリ名と処理するコールバックを個々に設定することで作成している。
void __init proc_misc_init(void) { static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); } *p, simple_ones[] = { {"loadavg", loadavg_read_proc}, {"uptime", uptime_read_proc}, {"meminfo", meminfo_read_proc}, {"version", version_read_proc}, ・・・・・ {"filesystems", filesystems_read_proc}, {"cmdline", cmdline_read_proc}, {"execdomains", execdomains_read_proc}, {NULL,} }; for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
proc_symlink("mounts", NULL, "self/mounts");
・・・・・ proc_create("stat", 0, NULL, &proc_stat_operations); proc_create("interrupts", 0, NULL, &proc_interrupts_operations); proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); ・・・・・ }