/proc/xxx从哪来?

 /proc/<pid>

在/proc目录下,除了/proc/sys、/proc/meminfo、/proc/slabinfo等系统级信息之外,系统中所有的存在的进程都会在这个目录下存在一个目录,而里面则有大量的进程级的信息;这些文件和目录都是什么时候创建的呢?

proc文件系统

proc文件系统是什么时候挂载的呢?

struct pid *alloc_pid(struct pid_namespace *ns)
---
	pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
	...
	tmp = ns;
	pid->level = ns->level;

	for (i = ns->level; i >= 0; i--) {
		int pid_min = 1;
        // 会在每个命名空间都申请一个pid
		nr = idr_alloc_cyclic(&tmp->idr, NULL, pid_min,
				      pid_max, GFP_ATOMIC);
		...
		tmp = tmp->parent;
	}

    // 这个命名空间的1号进程就是child reaper
	if (unlikely(is_child_reaper(pid))) {
		if (pid_ns_prepare_proc(ns))
			goto out_free;
	}
---

当某个pid命名空间的1号进程被创建时,或者更加准确的说,1号pid被申请时,会执行执行一次proc目录的挂载;换句话说,每个pid命名空间都有一个独立视角的proc目录。proc文件系统的卸载是在该namespace的pid都释放了之后,通过kwork进行的,参考free_pid()。

 通过proc文件系统的root目录的file和inode方法,如下:

static const struct file_operations proc_root_operations = {
	.read		 = generic_read_dir,
	.iterate_shared	 = proc_root_readdir,
	.llseek		= generic_file_llseek,
};

/*
 * proc root can do almost nothing..
 */
static const struct inode_operations proc_root_inode_operations = {
	.lookup		= proc_root_lookup,
	.getattr	= proc_root_getattr,
};

我们知道,他们只能对它做两件事,即目录遍历(ls)和目录查询(cd、cat等);

/proc/<pid>哪来的?

先说结论,/proc/<pid>并不是进程创建就有的,而是通过proc_pid_instantiate()在需要的时候创建的;那么什么时候需要?readdir和lookup,参考:

proc_pid_lookup()
---
	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);
---


proc_pid_readdir()
---
	if (pos == TGID_OFFSET - 2) {
		struct inode *inode = d_inode(ns->proc_self);
		if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
			return 0;
		ctx->pos = pos = pos + 1;
	}
	if (pos == TGID_OFFSET - 1) {
		struct inode *inode = d_inode(ns->proc_thread_self);
		if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
			return 0;
		ctx->pos = pos = pos + 1;
	}
	iter.tgid = pos - TGID_OFFSET;
	iter.task = NULL;
	for (iter = next_tgid(ns, iter);
	     iter.task;
	     iter.tgid += 1, iter = next_tgid(ns, iter)) {
		...
		len = snprintf(name, sizeof(name), "%u", iter.tgid);
		ctx->pos = iter.tgid + TGID_OFFSET;
		if (!proc_fill_cache(file, ctx, name, len,
				     proc_pid_instantiate, iter.task, NULL)) {
			put_task_struct(iter.task);
			return 0;
		}
	}
---

当我们去遍历/proc或者查询某个pid的目录时,其相关的inode节点会在那个时候被创建;以此类似,/proc/<pid>/下面的目录和文件也是一样方式;参考函数,proc_pident_lookup()和proc_pident_instantiate()。

/proc/<pid>哪去了?

do_exit()
  -> exit_notify()
    -> release_task()
  -> do_task_dead()

release_task()
  -> proc_flush_task()
    -> proc_flush_task_mnt()
	---
		name.name = buf;
		name.len = snprintf(buf, sizeof(buf), "%u", pid);
		/* no ->d_hash() rejects on procfs */
		dentry = d_hash_and_lookup(mnt->mnt_root, &name);
		if (dentry) {
			d_invalidate(dentry);
			dput(dentry);
		}
	---

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值