/procのls一覧表示について


プロック擬似ファイルは実ファイルを持たないファイルシステムであり、このファイルを介してシステム情報およびプロセス情報をを設定確認できる機能を提供している。
[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);
・・・・・
}


最終更新 2010/02/28 22:02:12 - north
(2010/02/28 21:58:23 作成)


検索

アクセス数
3676059
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。