Fix bug with duping fds for plan 9 files
[akaros.git] / kern / src / ns / pgrp.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /* TODO: (ID) need a unique ID service.  These will loop around... */
17 static int pgrpid;
18 static int mountid;
19 #define NEXT_ID(x) (__sync_add_and_fetch(&(x), 1))
20
21 void closepgrp(struct pgrp *p)
22 {
23         struct mhead **h, **e, *f, *next;
24
25         wlock(&p->ns);
26         p->pgrpid = -1;
27
28         e = &p->mnthash[MNTHASH];
29         for (h = p->mnthash; h < e; h++) {
30                 for (f = *h; f; f = next) {
31                         wlock(&f->lock);
32                         cclose(f->from);
33                         mountfree(f->mount);
34                         f->mount = NULL;
35                         next = f->hash;
36                         wunlock(&f->lock);
37                         putmhead(f);
38                 }
39         }
40         wunlock(&p->ns);
41         cclose(p->dot);
42         cclose(p->slash);
43         kfree(p);
44 }
45
46 static void freepgrp(struct kref *k)
47 {
48         struct pgrp *p = container_of(k, struct pgrp, ref);
49         closepgrp(p);
50 }
51
52 struct pgrp *newpgrp(void)
53 {
54         struct pgrp *p;
55
56         p = kzmalloc(sizeof(struct pgrp), KMALLOC_WAIT);
57         kref_init(&p->ref, freepgrp, 1);
58         p->pgrpid = NEXT_ID(pgrpid);
59         p->progmode = 0644;
60         qlock_init(&p->debug);
61         qlock_init(&p->nsh);
62         return p;
63 }
64
65 void pgrpinsert(struct mount **order, struct mount *m)
66 {
67         struct mount *f;
68
69         m->order = 0;
70         if (*order == 0) {
71                 *order = m;
72                 return;
73         }
74         for (f = *order; f; f = f->order) {
75                 if (m->mountid < f->mountid) {
76                         m->order = f;
77                         *order = m;
78                         return;
79                 }
80                 order = &f->order;
81         }
82         *order = m;
83 }
84
85 /*
86  * pgrpcpy MUST preserve the mountid allocation order of the parent group
87  */
88 void pgrpcpy(struct pgrp *to, struct pgrp *from)
89 {
90         ERRSTACK(2);
91         int i;
92         struct mount *n, *m, **link, *order;
93         struct mhead *f, **tom, **l, *mh;
94
95         wlock(&from->ns);
96         if (waserror()) {
97                 wunlock(&from->ns);
98                 nexterror();
99         }
100         order = 0;
101         tom = to->mnthash;
102         for (i = 0; i < MNTHASH; i++) {
103                 l = tom++;
104                 for (f = from->mnthash[i]; f; f = f->hash) {
105                         rlock(&f->lock);
106                         if (waserror()) {
107                                 runlock(&f->lock);
108                                 nexterror();
109                         }
110                         mh = newmhead(f->from);
111                         if (!mh)
112                                 error(Enomem);
113                         *l = mh;
114                         l = &mh->hash;
115                         link = &mh->mount;
116                         for (m = f->mount; m; m = m->next) {
117                                 n = newmount(mh, m->to, m->mflag, m->spec);
118                                 m->copy = n;
119                                 pgrpinsert(&order, m);
120                                 *link = n;
121                                 link = &n->next;
122                         }
123                         poperror();
124                         runlock(&f->lock);
125                 }
126         }
127         /*
128          * Allocate mount ids in the same sequence as the parent group
129          */
130         /* should probably protect with a spinlock and be done with it */
131         for (m = order; m; m = m->order) {
132                 m->copy->mountid = NEXT_ID(mountid);
133         }
134
135         to->progmode = from->progmode;
136         to->slash = cclone(from->slash);
137         to->dot = cclone(from->dot);
138         to->nodevs = from->nodevs;
139
140         poperror();
141         wunlock(&from->ns);
142 }
143
144 void closefgrp(struct fgrp *f)
145 {
146         /* TODO: look at this more carefully.  sharing fgrps might be unnecessary,
147          * due to our parallelism style. */
148         /* closefgrp can't be called from proc_destroy, due to races on the fgrp.
149          * current->fgrp is a kref source, and we'd need some form of external sync
150          * to remove it, since multiple kthreads could be accessing current->fgrp.
151          * proc_free is synchronized, for instance.  we could put some sync in the
152          * fgrp, but that would require splitting the deallocation (which we do
153          * manually), and would require not having multiple procs per fgrp (which we
154          * also require).  another option would be to use RCU: clear current->fgrp,
155          * then closefgrp after a grace period. */
156         warn("Don't call closefgrp()");
157
158         if (!f)
159                 return;
160         kref_put(&f->ref);
161 }
162
163 static void freefgrp(struct kref *k)
164 {
165         struct fgrp *f = container_of(k, struct fgrp, ref);
166         struct chan *c;
167         for (int i = 0; i <= f->maxfd; i++)
168                 if ((c = f->fd[i]))
169                         cclose(c);
170
171         kfree(f->fd);
172         kfree(f);
173 }
174
175 struct fgrp *newfgrp(void)
176 {
177         struct fgrp *new;
178         int n;
179
180         new = kzmalloc(sizeof(struct fgrp), 0);
181         kref_init(&new->ref, freefgrp, 1);
182         spinlock_init(&new->lock);
183         n = DELTAFD;
184         new->nfd = n;
185         new->fd = kzmalloc(n * sizeof(struct chan *), 0);
186         return new;
187 }
188
189 struct fgrp *dupfgrp(struct proc *new_proc, struct fgrp *f)
190 {
191         int i;
192         struct chan *c;
193         struct fgrp *new;
194         int n;
195
196         new = kzmalloc(sizeof(struct fgrp), KMALLOC_WAIT);
197         kref_init(&new->ref, freefgrp, 1);
198         spin_lock(&f->lock);
199         if (f->closed) {
200                 spin_unlock(&f->lock);
201                 kfree(new);
202                 error("File group closed");
203         }
204         n = DELTAFD;
205         if (f->maxfd >= n)
206                 n = (f->maxfd + 1 + DELTAFD - 1) / DELTAFD * DELTAFD;
207         new->nfd = n;
208         new->fd = kzmalloc(n * sizeof(struct chan *), 0);
209         if (new->fd == NULL) {
210                 spin_unlock(&f->lock);
211                 kfree(new);
212                 error(Enomem);
213         }
214         new->maxfd = f->maxfd;
215         new->minfd = f->minfd;
216         for (i = 0; i <= f->maxfd; i++) {
217                 if ((c = f->fd[i])) {
218                         kref_get(&c->ref, 1);
219                         claim_fd(&new_proc->open_files, i);
220                         new->fd[i] = c;
221                 }
222         }
223         spin_unlock(&f->lock);
224
225         return new;
226 }
227
228 struct mount *newmount(struct mhead *mh, struct chan *to, int flag, char *spec)
229 {
230         struct mount *m;
231
232         m = kzmalloc(sizeof(struct mount), 0);
233         m->to = to;
234         m->head = mh;
235         kref_get(&to->ref, 1);
236         m->mountid = NEXT_ID(mountid);
237         m->mflag = flag;
238         if (spec != 0)
239                 kstrdup(&m->spec, spec);
240
241         return m;
242 }
243
244 void mountfree(struct mount *m)
245 {
246         struct mount *f;
247
248         while (m) {
249                 f = m->next;
250                 cclose(m->to);
251                 m->mountid = 0;
252                 kfree(m->spec);
253                 kfree(m);
254                 m = f;
255         }
256 }
257
258 #if 0
259 almost certainly not needed.void resrcwait(char *reason)
260 {
261         char *p;
262
263         if (current == 0)
264                 panic("resrcwait");
265
266         p = up->psstate;
267         if (reason) {
268                 up->psstate = reason;
269                 printd("%s\n", reason);
270         }
271
272         udelay_sched(300 * 1000);
273         up->psstate = p;
274 }
275 #endif
276
277 /* TODO: We don't have any alloc / initializer methods for skeyset or signerkey
278  * yet.  When we do, use these releases for their kref_init. */
279 static void __sigs_release(struct kref *kref)
280 {
281         struct skeyset *s = container_of(kref, struct skeyset, ref);
282         int i;
283         for (i = 0; i < s->nkey; i++)
284                 freeskey(s->keys[i]);
285         kfree(s);
286 }
287
288 void closesigs(struct skeyset *s)
289 {
290         if (!s)
291                 return;
292         kref_put(&s->ref);
293 }
294
295 static void __key_release(struct kref *kref)
296 {
297         struct signerkey *key = container_of(kref, struct signerkey, ref);
298         kfree(key->owner);
299         (*key->pkfree) (key->pk);
300         kfree(key);
301 }
302
303 void freeskey(struct signerkey *key)
304 {
305         if (!key)
306                 return;
307         kref_put(&key->ref);
308 }