summaryrefslogtreecommitdiff
path: root/debian/patches/0012-proc-implement-proc_make_task_namespace.patch
blob: a7bd19b271cd5b3a7e0b7285a8f2d4f3cb1a0a3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
From 5aef28222f05dec56cd1212e70766d8bf779df11 Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Tue, 11 Nov 2014 21:23:42 +0100
Subject: [PATCH hurd 12/14] proc: implement `proc_make_task_namespace'

* proc/proc.h (struct proc): Add field `p_task_namespace'.
* proc/mgt.c (S_proc_child): Propagate `p_task_namespace' to child.
(allocate_proc): Initialize `p_task_namespace'.
(namespace_terminate): New function.
(process_has_exited): Reparent children of dead tasks in the namespace
to the root process.  Terminate all tasks if the root process dies.
Reap dead tasks.
(S_mach_notify_new_task): For newly created tasks thats parent is in a
namespace, call S_proc_child and forward the `mach_notify_new_task'
message.
(S_proc_make_task_namespace): New function.
---
 proc/mgt.c  | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 proc/proc.h |   4 +++
 2 files changed, 107 insertions(+), 9 deletions(-)

diff --git a/proc/mgt.c b/proc/mgt.c
index 32408ae..bf400ba 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -220,6 +220,13 @@ S_proc_child (struct proc *parentp,
       childp->end_code = parentp->end_code;
     }
 
+  if (MACH_PORT_VALID (parentp->p_task_namespace))
+    {
+      mach_port_mod_refs (mach_task_self (), parentp->p_task_namespace,
+			  MACH_PORT_RIGHT_SEND, +1);
+      childp->p_task_namespace = parentp->p_task_namespace;
+    }
+
   return 0;
 }
 
@@ -577,6 +584,7 @@ allocate_proc (task_t task)
 
   memset (&p->p_pi + 1, 0, sizeof *p - sizeof p->p_pi);
   p->p_task = task;
+  p->p_task_namespace = MACH_PORT_NULL;
   p->p_msgport = MACH_PORT_NULL;
 
   pthread_cond_init (&p->p_wakeup, NULL);
@@ -721,6 +729,16 @@ new_proc (task_t task)
   return p;
 }
 
+/* Used with prociterate to terminate all tasks in a task
+   namespace.  */
+static void
+namespace_terminate (struct proc *p, void *cookie)
+{
+  mach_port_t *namespacep = cookie;
+  if (p->p_task_namespace == *namespacep)
+    task_terminate (p->p_task);
+}
+
 /* The task associated with process P has died.  Drop most state,
    and then record us as dead.  Our parent will eventually complete the
    deallocation. */
@@ -751,13 +769,39 @@ process_has_exited (struct proc *p)
 
   ids_rele (p->p_id);
 
-  /* Reparent our children to init by attaching the head and tail
-     of our list onto init's.  */
+  /* Reparent our children to init by attaching the head and tail of
+     our list onto init's.  If the process is part of a task
+     namespace, reparent to the process that created the namespace
+     instead.  */
   if (p->p_ochild)
     {
+      struct proc *reparent_to = init_proc;
       struct proc *tp;		/* will point to the last one.  */
       int isdead = 0;
 
+      if (MACH_PORT_VALID (p->p_task_namespace))
+	{
+	  for (tp = p;
+	       MACH_PORT_VALID (tp->p_parent->p_task_namespace);
+	       tp = tp->p_parent)
+	    {
+	      /* Walk up the process hierarchy until we find the
+		 creator of the task namespace.	 */
+	    }
+
+	  if (p == tp)
+	    {
+	      /* The creator of the task namespace died.  Terminate
+		 all tasks.  */
+	      prociterate (namespace_terminate, &p->p_task_namespace);
+
+	      mach_port_deallocate (mach_task_self (), p->p_task_namespace);
+	      p->p_task_namespace = MACH_PORT_NULL;
+	    }
+	  else
+	    reparent_to = tp;
+	}
+
       /* first tell them their parent is changing */
       for (tp = p->p_ochild; tp->p_sib; tp = tp->p_sib)
 	{
@@ -765,7 +809,7 @@ process_has_exited (struct proc *p)
 	    nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
 				    1, tp->p_pgrp->pg_pgid,
 				    !tp->p_pgrp->pg_orphcnt);
-	  tp->p_parent = init_proc;
+	  tp->p_parent = reparent_to;
 	  if (tp->p_dead)
 	    isdead = 1;
 	}
@@ -773,17 +817,17 @@ process_has_exited (struct proc *p)
 	nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
 				1, tp->p_pgrp->pg_pgid,
 				!tp->p_pgrp->pg_orphcnt);
-      tp->p_parent = init_proc;
+      tp->p_parent = reparent_to;
 
       /* And now append the lists. */
-      tp->p_sib = init_proc->p_ochild;
+      tp->p_sib = reparent_to->p_ochild;
       if (tp->p_sib)
 	tp->p_sib->p_prevsib = &tp->p_sib;
-      init_proc->p_ochild = p->p_ochild;
-      p->p_ochild->p_prevsib = &init_proc->p_ochild;
+      reparent_to->p_ochild = p->p_ochild;
+      p->p_ochild->p_prevsib = &reparent_to->p_ochild;
 
       if (isdead)
-	alert_parent (init_proc);
+	alert_parent (reparent_to);
     }
 
   /* If an operation is in progress for this process, cause it
@@ -795,6 +839,23 @@ process_has_exited (struct proc *p)
 
   /* Cancel any outstanding RPCs done on behalf of the dying process.  */
   ports_interrupt_rpcs (p);
+
+  /* No one is going to wait for processes in a task namespace.  */
+  if (MACH_PORT_VALID (p->p_task_namespace))
+    {
+      mach_port_t task;
+      mach_port_deallocate (mach_task_self (), p->p_task_namespace);
+      p->p_waited = 1;
+
+      /* XXX: `complete_exit' will destroy p->p_task if it is valid.
+	 Prevent this so that `do_mach_notify_dead_name' can
+	 deallocate the right.	The proper fix is not to use
+	 mach_port_destroy in the first place.	*/
+      task = p->p_task;
+      p->p_task = MACH_PORT_NULL;
+      complete_exit (p);
+      mach_port_deallocate (mach_task_self (), task);
+    }
 }
 
 void
@@ -1008,9 +1069,42 @@ S_mach_notify_new_task (mach_port_t notify,
       childp = new_proc (task);
     }
 
-  /* XXX do something interesting */
+  if (MACH_PORT_VALID (parentp->p_task_namespace))
+    {
+      error_t err;
+      /* Tasks in a task namespace are not expected to call
+	 proc_child, so we do it on their behalf.  */
+      mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
+      err = S_proc_child (parentp, task);
+      if (! err)
+	/* Relay the notification.  This consumes TASK and PARENT.  */
+	return mach_notify_new_task (childp->p_task_namespace, task, parent);
+    }
 
   mach_port_deallocate (mach_task_self (), task);
   mach_port_deallocate (mach_task_self (), parent);
   return 0;
 }
+
+/* Implement proc_make_task_namespace as described in
+   <hurd/process.defs>.  */
+error_t
+S_proc_make_task_namespace (struct proc *callerp,
+			    mach_port_t notify)
+{
+  if (! callerp)
+    return EOPNOTSUPP;
+
+  if (! MACH_PORT_VALID (notify))
+    return EINVAL;
+
+  if (MACH_PORT_VALID (callerp->p_task_namespace))
+    {
+      mach_port_deallocate (mach_task_self (), notify);
+      return EBUSY;
+    }
+
+  callerp->p_task_namespace = notify;
+
+  return 0;
+}
diff --git a/proc/proc.h b/proc/proc.h
index 6196697..a056d18 100644
--- a/proc/proc.h
+++ b/proc/proc.h
@@ -58,6 +58,10 @@ struct proc
   /* Process group structure */
   struct pgrp *p_pgrp;
 
+  /* Processes may live in a task namespace identified by the
+     notification port registered by proc_make_task_namespace.  */
+  mach_port_t p_task_namespace;	/* send right */
+
   /* Communication */
   mach_port_t p_msgport;	/* send right */
 
-- 
2.1.1