Jump stacks before unlocking semaphores
[akaros.git] / kern / drivers / dev / srv.c
1 /* Copyright (c) 2014 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * #s (srv) - a chan sharing service.  This was originally based off the Inferno
6  * #s, but it's been completely rewritten to act like what I remember the plan9
7  * one to be like.
8  *
9  *
10  * I tried a style where we hang reference counted objects off c->aux, specific
11  * to each chan.  Instead of looking up via qid.path, we just look at the c->aux
12  * for our struct.  I originally tried having those be reference counted
13  * structs, but that fails for a bunch of reasons.  Without them being reference
14  * counted, we're really just using c->aux as if it was qid.path.
15  *
16  * We can't hang an external reference to an item off c->aux, and have that item
17  * change as we gen (but we can use it as a weak ref, uncounted ref).  The main
18  * thing is that devclone makes a 'half-chan' with a copy of c->aux.  This chan
19  * may or may not be closed later.  If we transfer refs via a gen, we first
20  * assumed we had a ref in the first place (devclone doesn't incref our srv),
21  * and then we might not close.  This ends up decreffing top_dir too much, and
22  * giving it's refs to some other file in the walk. */
23
24 #include <vfs.h>
25 #include <kfs.h>
26 #include <slab.h>
27 #include <kmalloc.h>
28 #include <kref.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <assert.h>
32 #include <error.h>
33 #include <cpio.h>
34 #include <pmap.h>
35 #include <smp.h>
36 #include <ip.h>
37 #include <sys/queue.h>
38
39 struct dev srvdevtab;
40
41 static char *devname(void)
42 {
43         return srvdevtab.name;
44 }
45
46 #define Qtopdir                 1
47 #define Qsrvfile                2
48
49 struct srvfile {
50         TAILQ_ENTRY(srvfile) link;
51         char *name;
52         struct chan *chan;
53         struct kref ref;                        /* +1 for existing on create, -1 on remove */
54         char *user;
55         uint32_t perm;
56         atomic_t opens;                         /* used for exclusive open checks */
57 };
58
59 struct srvfile *top_dir;
60 TAILQ_HEAD(srvfilelist, srvfile) srvfiles = TAILQ_HEAD_INITIALIZER(srvfiles);
61 /* the lock protects the list and its members.  we don't incref from a list ref
62  * without the lock. (if you're on the list, we can grab a ref). */
63 spinlock_t srvlock = SPINLOCK_INITIALIZER;
64
65 atomic_t nr_srvs = 0;                   /* debugging - concerned about leaking mem */
66
67 /* Given a pointer (internal ref), we attempt to get a kref */
68 static bool grab_ref(struct srvfile *srv)
69 {
70         bool ret = FALSE;
71         struct srvfile *srv_i;
72         spin_lock(&srvlock);
73         TAILQ_FOREACH(srv_i, &srvfiles, link) {
74                 if (srv_i == srv) {
75                         ret = kref_get_not_zero(&srv_i->ref, 1);
76                         break;
77                 }
78         }
79         spin_unlock(&srvlock);
80         return ret;
81 }
82
83 static void srv_release(struct kref *kref)
84 {
85         struct srvfile *srv = container_of(kref, struct srvfile, ref);
86         kfree(srv->user);
87         kfree(srv->name);
88         if (srv->chan)
89                 cclose(srv->chan);
90         kfree(srv);
91         atomic_dec(&nr_srvs);
92 }
93
94 static int srvgen(struct chan *c, char *name, struct dirtab *tab,
95                                   int ntab, int s, struct dir *dp)
96 {
97         struct srvfile *prev, *next;
98         struct qid q;
99
100         if (s == DEVDOTDOT) {
101                 /* changing whatever c->aux was to be topdir */
102                 mkqid(&q, Qtopdir, 0, QTDIR);
103                 devdir(c, q, devname(), 0, eve, 0555, dp);
104                 return 1;
105         }
106         spin_lock(&srvlock);
107         TAILQ_FOREACH(next, &srvfiles, link) {
108                 /* come in with s == 0 on the first run */
109                 if (s-- == 0)
110                         break;
111         }
112         if (!next) {
113                 spin_unlock(&srvlock);
114                 return -1;
115         }
116         /* update c to point to our new srvfile.  this keeps the chan and its srv in
117          * sync with what we're genning. */
118         c->aux = next;  /* uncounted ref */
119         mkqid(&q, Qsrvfile, 0, QTFILE);
120         /* once we release the lock, next could disappear, including next->name */
121         strlcpy(get_cur_genbuf(), next->name, GENBUF_SZ);
122         devdir(c, q, get_cur_genbuf(), 1 /* length */ , next->user, next->perm, dp);
123         spin_unlock(&srvlock);
124         return 1;
125 }
126
127 static void __srvinit(void)
128 {
129         top_dir = kzmalloc(sizeof(struct srvfile), MEM_WAIT);
130         /* kstrdup, just in case we free this later */
131         kstrdup(&top_dir->name, "srv");
132         kstrdup(&top_dir->user, current ? current->user : "eve");
133         top_dir->perm = DMDIR | 0770;
134         /* +1 for existing, should never decref this */
135         kref_init(&top_dir->ref, fake_release, 1);
136         atomic_set(&top_dir->opens, 0);
137 }
138
139 static void srvinit(void)
140 {
141         run_once(__srvinit());
142 }
143
144 static struct chan *srvattach(char *spec)
145 {
146         /* the inferno attach was pretty complicated, but
147          * we're not sure that complexity is needed. */
148         struct chan *c = devattach(devname(), spec);
149         mkqid(&c->qid, Qtopdir, 0, QTDIR);
150         /* c->aux is an uncounted ref */
151         c->aux = top_dir;
152         return c;
153 }
154
155 static struct walkqid *srvwalk(struct chan *c, struct chan *nc, char **name,
156                                                            int nname)
157 {
158         return devwalk(c, nc, name, nname, 0, 0, srvgen);
159 }
160
161 static int srvstat(struct chan *c, uint8_t * db, int n)
162 {
163         return devstat(c, db, n, 0, 0, srvgen);
164 }
165
166 char*
167 srvname(struct chan *c)
168 {
169         struct srvfile *srv_i;
170         char *s;
171
172         spin_lock(&srvlock);
173         TAILQ_FOREACH(srv_i, &srvfiles, link) {
174                 if(srv_i->chan == c){
175                         int len = 3 + strlen(srv_i->name) + 1;
176                         s = kzmalloc(len, 0);
177                         snprintf(s, len, "#s/%s", srv_i->name);
178                         spin_unlock(&srvlock);
179                         return s;
180                 }
181         }
182         spin_unlock(&srvlock);
183         return NULL;
184 }
185
186 static struct chan *srvopen(struct chan *c, int omode)
187 {
188         ERRSTACK(1);
189         struct srvfile *srv;
190         openmode(omode);        /* used as an error checker in plan9, does little now */
191         if (c->qid.type & QTDIR) {
192                 if (omode & O_WRITE)
193                         error(EISDIR, ERROR_FIXME);
194                 c->mode = openmode(omode);
195                 c->flag |= COPEN;
196                 c->offset = 0;
197                 return c;
198         }
199         srv = c->aux;
200         if (!grab_ref(srv))
201                 error(EFAIL, "Unable to open srv file, concurrent removal");
202         if (waserror()) {
203                 kref_put(&srv->ref);
204                 nexterror();
205         }
206         devpermcheck(srv->user, srv->perm, omode);
207         /* No remove on close support yet */
208 #if 0
209         if (omode & ORCLOSE) {
210                 if (strcmp(srv->user, up->env->user) != 0)
211                         error(EPERM, ERROR_FIXME);
212                 else
213                         srv->flags |= SORCLOSE;
214         }
215 #endif
216         if ((srv->perm & DMEXCL) && atomic_read(&srv->opens))
217                 error(EBUSY, ERROR_FIXME);
218         /* srv->chan is write-once, so we don't need to sync. */
219         if (!srv->chan)
220                 error(EFAIL, "srv file has no chan yet");
221         /* this is more than just the ref - 1, since there will be refs in flight
222          * as gens work their way through the list */
223         atomic_inc(&srv->opens);
224         /* the magic of srv: open c, get c->srv->chan back */
225         cclose(c);
226         c = srv->chan;
227         chan_incref(c);
228         poperror();
229         kref_put(&srv->ref);
230         return c;
231 }
232
233 static void srvcreate(struct chan *c, char *name, int omode, uint32_t perm)
234 {
235         struct srvfile *srv;
236         srv = kzmalloc(sizeof(struct srvfile), MEM_WAIT);
237         kstrdup(&srv->name, name);
238         kstrdup(&srv->user, current ? current->user : "eve");
239         srv->perm = 0770;       /* TODO need some security thoughts */
240         atomic_set(&srv->opens, 1);     /* we return it opened */
241         mkqid(&c->qid, Qsrvfile, 0, QTFILE);
242         c->aux = srv;
243         c->mode = openmode(omode);
244         /* one ref for being on the list */
245         kref_init(&srv->ref, srv_release, 1);
246         spin_lock(&srvlock);
247         TAILQ_INSERT_TAIL(&srvfiles, srv, link);
248         spin_unlock(&srvlock);
249         atomic_inc(&nr_srvs);
250 }
251
252 static int srvwstat(struct chan *c, uint8_t * dp, int n)
253 {
254         error(ENOSYS, ERROR_FIXME);
255         return -1;
256 }
257
258 static void srvclose(struct chan *c)
259 {
260         struct srvfile *srv = c->aux;
261         if (!grab_ref(srv))
262                 return;
263         atomic_dec(&srv->opens);
264         kref_put(&srv->ref);
265 }
266
267 static void srvremove(struct chan *c)
268 {
269         struct srvfile *srv_i, *temp;
270
271         spin_lock(&srvlock);
272         TAILQ_FOREACH_SAFE(srv_i, &srvfiles, link, temp) {
273                 if (srv_i == c->aux) {
274                         TAILQ_REMOVE(&srvfiles, srv_i, link);
275                         break;
276                 }
277         }
278         spin_unlock(&srvlock);
279         if (srv_i)
280                 kref_put(&srv_i->ref);  /* dropping ref from the list */
281 }
282
283 /* N.B. srvopen gives the chan back. The only 'reading' we do
284  * in srv is of the top level directory.
285  */
286 static long srvread(struct chan *c, void *va, long count, int64_t offset)
287 {
288         return devdirread(c, va, count, 0, 0, srvgen);
289 }
290
291 static long srvwrite(struct chan *c, void *va, long count, int64_t offset)
292 {
293         ERRSTACK(2);
294         struct srvfile *srv;
295         struct chan *new_chan;
296         char *kbuf = 0;
297         int fd;
298
299         if (c->qid.type & QTDIR)
300                 error(EPERM, ERROR_FIXME);
301         srv = c->aux;
302         if (!grab_ref(srv))
303                 error(EFAIL, "Unable to write srv file, concurrent removal");
304         if (waserror()) {
305                 kref_put(&srv->ref);
306                 nexterror();
307         }
308         if (srv->chan)
309                 error(EFAIL, "srv file already has a stored chan!");
310         if (waserror()) {
311                 kfree(kbuf);
312                 nexterror();
313         }
314         kbuf = kmalloc(count + 1, MEM_WAIT);
315         strlcpy(kbuf, va, count + 1);
316         fd = strtoul(kbuf, 0, 10);
317         /* the magic of srv: srv stores the chan corresponding to the fd.  -1 for
318          * mode, so we just get the chan with no checks (RDWR would work too). */
319         new_chan = fdtochan(&current->open_files, fd, -1, FALSE, TRUE);
320         /* fdtochan already increffed for us */
321         if (!__sync_bool_compare_and_swap(&srv->chan, 0, new_chan)) {
322                 cclose(new_chan);
323                 error(EFAIL, "srv file already has a stored chan!");
324         }
325         poperror();
326         kfree(kbuf);
327         poperror();
328         kref_put(&srv->ref);
329         return count;
330 }
331
332 struct dev srvdevtab __devtab = {
333         .name = "srv",
334
335         .reset = devreset,
336         .init = srvinit,
337         .shutdown = devshutdown,
338         .attach = srvattach,
339         .walk = srvwalk,
340         .stat = srvstat,
341         .open = srvopen,
342         .create = srvcreate,
343         .close = srvclose,
344         .read = srvread,
345         .bread = devbread,
346         .write = srvwrite,
347         .bwrite = devbwrite,
348         .remove = srvremove,
349         .wstat = srvwstat,
350         .power = devpower,
351         .chaninfo = devchaninfo,
352 };