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