OpenVZ Forum


Home » Mailing lists » Devel » [RFC][PATCH 0/16] Enable cloning of pid namespace
[RFC][PATCH 08/16] Define/use pid->upid_list list. [message #18617 is a reply to message #18609] Thu, 24 May 2007 01:11 Go to previous messageGo to previous message
Sukadev Bhattiprolu is currently offline  Sukadev Bhattiprolu
Messages: 413
Registered: August 2006
Senior Member
Subject: Define/use pid->upid_list list.

From: Sukadev Bhattiprolu <sukadev@us.ibm.com>


With multiple pid namespaces, a process would be known by several pid_t
values, one in each pid namespace. To represent this, we introduce a
'struct upid' which associates a single pid_t value with a single pid
namespace.

We then replace the pid->nr field in 'struct pid' with a list of struct upid'
entries (referred to as the pid->upid_list list). This list represents the
multiple pid_t values of the process, one in each namespace.

The struct upid also replaces 'struct pid' in the pid_hash table to enable us
to find processes given a pid_t from any namespace (i.e we find 'struct upid'
for a given pid_t and from the 'struct upid', we find the 'struct pid' of the
process)

We finally reimplement find_pid() and pid_to_nr() to use pid->upid_list
and remove unused fields from 'struct pid'.

Changelog:
	2.6.21-mm2-pidns3:
	- 'struct upid' used to be called 'struct pid_nr' and a list of these
	   were hanging off of 'struct pid'. So, we renamed 'struct pid_nr'
	   and now hold them in a statically sized array in 'struct pid' since
	   the number of 'struct upid's for a process is known at process-
	   creation time.
	  
	2.6.21-rc3-mm2:

	- [Eric Biederman] Combine all logical changes into one patch
	- [Eric Biederman] Implement __pid_nr(pid_ns, pid) for use in procfs.
	  (now called pid_to_nr_in_ns()).
	- [Serge Hallyn]: Remove (!pid_nr) check in free_pid_nr()

Signed-off-by: Cedric Le Goater <clg@fr.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@us.ibm.com>
---
 fs/proc/array.c               |   30 ++++--
 fs/proc/base.c                |    9 +-
 include/linux/init_task.h     |   13 ++
 include/linux/pid.h           |   35 +++++--
 include/linux/pid_namespace.h |   12 ++
 kernel/fork.c                 |    2 
 kernel/pid.c                  |  187 +++++++++++++++++++++++++++++++++++-------
 7 files changed, 232 insertions(+), 56 deletions(-)

Index: lx26-21-mm2/include/linux/pid.h
===================================================================
--- lx26-21-mm2.orig/include/linux/pid.h	2007-05-22 17:06:48.000000000 -0700
+++ lx26-21-mm2/include/linux/pid.h	2007-05-22 17:06:54.000000000 -0700
@@ -16,6 +16,25 @@ enum pid_type
 	PIDTYPE_MAX
 };
 
+struct pid_namespace;
+
+/*
+ * A struct upid holds a process identifier (or pid->nr) for a given
+ * pid namespace.
+ *
+ * A list of 'struct upid' entries is stored in the struct pid. This list
+ * is used to get the process identifier associated with the pid
+ * namespace it is being seen from.
+ */
+struct upid
+{
+	/* Try to keep pid_chain in the same cacheline as nr for find_pid */
+	struct hlist_node pid_chain; 	/* link hash collisions on pid_hash */
+	int nr;	 			/* user space pid number */
+	struct pid_namespace *pid_ns; 	/* pid namespace in which nr is valid */
+	struct pid *pid; 		/* back to task's unique kernel pid */
+};
+
 /*
  * What is struct pid?
  *
@@ -48,11 +67,10 @@ enum pid_type
 struct pid
 {
 	atomic_t count;
-	/* Try to keep pid_chain in the same cacheline as nr for find_pid */
-	int nr;
-	struct hlist_node pid_chain;
 	/* lists of tasks that use this pid */
 	struct hlist_head tasks[PIDTYPE_MAX];
+	int num_upids;
+	struct upid *upid_list;
 	struct rcu_head rcu;
 };
 
@@ -100,16 +118,11 @@ extern struct pid *FASTCALL(find_pid(int
 extern struct pid *find_get_pid(int nr);
 extern struct pid *find_ge_pid(int nr);
 
-extern struct pid *alloc_pid(enum copy_process_type);
+extern struct pid *dup_struct_pid(enum copy_process_type);
 extern void FASTCALL(free_pid(struct pid *pid));
 
-static inline pid_t pid_to_nr(struct pid *pid)
-{
-	pid_t nr = 0;
-	if (pid)
-		nr = pid->nr;
-	return nr;
-}
+extern pid_t pid_to_nr_in_ns(struct pid_namespace *ns, struct pid *pid);
+extern pid_t pid_to_nr(struct pid *pid);
 
 #define do_each_pid_task(pid, type, task)				\
 	do {								\
Index: lx26-21-mm2/include/linux/init_task.h
===================================================================
--- lx26-21-mm2.orig/include/linux/init_task.h	2007-05-22 17:06:48.000000000 -0700
+++ lx26-21-mm2/include/linux/init_task.h	2007-05-22 17:06:54.000000000 -0700
@@ -89,16 +89,23 @@ extern struct nsproxy init_nsproxy;
 
 extern struct group_info init_groups;
 
-#define INIT_STRUCT_PID {						\
-	.count 		= ATOMIC_INIT(1),				\
-	.nr		= 0, 						\
+#define INIT_STRUCT_UPID {						\
+	.nr		= 0,						\
 	/* Don't put this struct pid in pid_hash */			\
 	.pid_chain	= { .next = NULL, .pprev = NULL },		\
+	.pid_ns		= &init_pid_ns,					\
+	.pid		= &init_struct_pid,				\
+}
+
+#define INIT_STRUCT_PID {						\
+	.count 		= ATOMIC_INIT(1),				\
 	.tasks		= {						\
 		{ .first = &init_task.pids[PIDTYPE_PID].node },		\
 		{ .first = &init_task.pids[PIDTYPE_PGID].node },	\
 		{ .first = &init_task.pids[PIDTYPE_SID].node },		\
 	},								\
+	.num_upids	= 1,						\
+	.upid_list 	= &init_struct_upid,				\
 	.rcu		= RCU_HEAD_INIT,				\
 }
 
Index: lx26-21-mm2/kernel/pid.c
===================================================================
--- lx26-21-mm2.orig/kernel/pid.c	2007-05-22 17:06:48.000000000 -0700
+++ lx26-21-mm2/kernel/pid.c	2007-05-22 17:06:54.000000000 -0700
@@ -33,6 +33,7 @@
 static struct hlist_head *pid_hash;
 static int pidhash_shift;
 static struct kmem_cache *pid_cachep;
+struct upid init_struct_upid = INIT_STRUCT_UPID;
 struct pid init_struct_pid = INIT_STRUCT_PID;
 
 int pid_max = PID_MAX_DEFAULT;
@@ -195,13 +196,104 @@ static int next_pidmap(struct pid_namesp
 	return -1;
 }
 
+static void clear_upid(struct upid *upid)
+{
+	/* We can be called with write_lock_irq(&tasklist_lock) held */
+	unsigned long flags;
+
+	free_pidmap(upid->pid_ns, upid->nr);
+
+	spin_lock_irqsave(&pidmap_lock, flags);
+	hlist_del_rcu(&upid->pid_chain);
+	spin_unlock_irqrestore(&pidmap_lock, flags);
+
+	put_pid_ns(upid->pid_ns);
+}
+
+static int init_upid(struct upid *upid, struct pid *pid,
+		struct pid_namespace *pid_ns)
+{
+	int nr;
+
+	nr = alloc_pidmap(pid_ns);
+	if (nr < 0)
+		return nr;
+
+	upid->pid_ns = pid_ns;
+	get_pid_ns(pid_ns);
+	upid->nr = nr;
+
+	/*
+	 * The struct pid and list of struct upid_list represent a process
+	 * with multiple pid_t values, one in each pid namespace. The list
+	 * of pid_t values of a process, represented by pid->upid_list list,
+	 * never changes during the life of the process. As such, struct
+	 * pid and its upid_list list maybe viewed as a single object i.e
+	 * they are created/destroyed together.  So we do not need a
+	 * reference to struct pid here.
+	 */
+	upid->pid = pid;
+
+	INIT_HLIST_NODE(&upid->pid_chain);
+	spin_lock_irq(&pidmap_lock);
+	hlist_add_head_rcu(&upid->pid_chain, &pid_hash[pid_hashfn(nr)]);
+	spin_unlock_irq(&pidmap_lock);
+
+	return 0;
+}
+
+/*
+ * Return the pid_t by which the process @pid is known in the pid
+ * namespace @ns.
+ *
+ * Return 0 if:
+ * 	- @pid is NULL (eg: procfs calls this for task_pgrp(init_task)
+ * 	  which is NULL).
+ *
+ * 	- process does not have pid_t in the namespace @ns (eg: parent
+ * 	  process of a child reaper does not exist in the child namespace.
+ * 	  A getppid() call by the child reaper results in 0).
+ */
+pid_t pid_to_nr_in_ns(struct pid_namespace *ns, struct pid *pid)
+{
+	int i;
+	struct upid *upid;
+
+	if (!pid)
+		return 0;
+
+	upid = &pid->upid_list[0];
+	for (i = 0; i < pid->num_upids; i++, upid++) {
+		if (upid->pid_ns == ns)
+			return upid->nr;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pid_to_nr_in_ns);
+
+/*
+ * Return the pid_t by which the process @pid is known in the active
+ * pid namespace of the caller.
+ *
+ * pid_to_nr() cannot be static inline if task_active_pid_ns() is
+ * inline as it would cause a circular dependency between pid.h
+ * and pid_namespace.h.
+ */
+pid_t pid_to_nr(struct pid *pid)
+{
+	return pid_to_nr_in_ns(task_active_pid_ns(current), pid);
+}
+EXPORT_SYMBOL_GPL(pid_to_nr);
+
 fastcall void put_pid(struct pid *pid)
 {
 	if (!pid)
 		return;
+
 	if ((atomic_read(&pid->count) == 1) ||
-	     atomic_dec_and_test(&pid->count))
+	     atomic_dec_and_test(&pid->count)) {
 		kmem_cache_free(pid_cachep, pid);
+	}
 }
 EXPORT_SYMBOL_GPL(put_pid);
 
@@ -213,66 +305,95 @@ static void delayed_put_pid(struct rcu_h
 
 fastcall void free_pid(struct pid *pid)
 {
-	/* We can be called with write_lock_irq(&tasklist_lock) held */
-	unsigned long flags;
+	int i;
+	struct upid *upid = &pid->upid_list[0];
 
 	/* check this here to keep copy_process() cleaner */
 	if (unlikely(pid == &init_struct_pid))
 		return;
 
-	spin_lock_irqsave(&pidmap_lock, flags);
-	hlist_del_rcu(&pid->pid_chain);
-	spin_unlock_irqrestore(&pidmap_lock, flags);
+	/* clear any upids that we actually initialized */
+	for (i = 0; i < pid->num_upids; i++, upid++) {
+		if (upid->pid_ns)
+			clear_upid(upid);
+		else
+			break;
+	}
 
-	free_pidmap(&init_pid_ns, pid->nr);
 	call_rcu(&pid->rcu, delayed_put_pid);
 }
 
-struct pid *alloc_pid(enum copy_process_type copy_src)
+static struct pid *alloc_struct_pid(int num_upids)
 {
 	struct pid *pid;
 	enum pid_type type;
-	int nr = -1;
-
-	/* check this here to keep copy_process() cleaner */
-	if (unlikely(copy_src == COPY_IDLE_PROCESS))
-		return &init_struct_pid;
+	struct upid *upid_list;
+	void *pid_end;
 
+	/* for now we only support one pid namespace */
+	BUG_ON(num_upids != 1);
 	pid = kmem_cache_alloc(pid_cachep, GFP_KERNEL);
 	if (!pid)
-		goto out;
+		return NULL;
 
-	nr = alloc_pidmap(task_active_pid_ns(current));
-	if (nr < 0)
-		goto out_free;
+	pid_end = (void *)pid + sizeof(struct pid);
+	pid->upid_list = (struct upid *)pid_end;
 
 	atomic_set(&pid->count, 1);
-	pid->nr = nr;
+	pid->num_upids = num_upids;
+
 	for (type = 0; type < PIDTYPE_MAX; ++type)
 		INIT_HLIST_HEAD(&pid->tasks[type]);
 
-	spin_lock_irq(&am
...

 
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: [PATCH 0/13] Pid namespaces (OpenVZ view)
Next Topic: [PATCH 05/10] Containers(V10): Add container_clone() interface
Goto Forum:
  


Current Time: Sun Sep 07 01:37:44 GMT 2025

Total time taken to generate the page: 0.11219 seconds