Rewrite of #s
[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  * I'm trying a style where we hang items off c->aux, specific to each chan.
10  * Instead of looking up via qid.path, we just look at the c->aux for our
11  * struct.  This has been a pain in the ass, and might have issues still.
12  *
13  * basically, whenever we gen a response, the chan will now have the aux for
14  * that response.  though we don't change the chan's qid (devwalk will do that
15  * on a successful run).
16  *
17  * one consequence of the refcnt style is that so long as an FD is open, it'll
18  * hold the chan and the srvfile in memory.  even if the file is removed from
19  * #s, it can still be read and written.  removal only prevents future walks.
20  *
21  * i've seen other devices do the chan->aux thing, but not like this.  those
22  * other ones had aux be for a device instance (like pipe - every attach creates
23  * its own pipe instance). */
24
25 #include <vfs.h>
26 #include <kfs.h>
27 #include <slab.h>
28 #include <kmalloc.h>
29 #include <kref.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <assert.h>
33 #include <error.h>
34 #include <cpio.h>
35 #include <pmap.h>
36 #include <smp.h>
37 #include <ip.h>
38 #include <sys/queue.h>
39
40 #define Qtopdir                 1
41 #define Qsrvfile                2
42
43 struct srvfile {
44         TAILQ_ENTRY(srvfile) link;
45         char *name;
46         struct chan *chan;
47         struct kref ref;                /* +1 for existing on create, -1 on remove */
48         bool on_list;
49         char *user;
50         uint32_t perm;
51         atomic_t opens;                 /* used for exclusive open checks */
52 };
53
54 struct srvfile *top_dir;
55 TAILQ_HEAD(srvfilelist, srvfile) srvfiles = TAILQ_HEAD_INITIALIZER(srvfiles);
56 /* the lock protects the list and its members.  we don't incref from a list ref
57  * without the lock. (if you're on the list, we can grab a ref).  Nor do we
58  * remove or mess with 'on_list' for any member without the lock. */
59 spinlock_t srvlock = SPINLOCK_INITIALIZER;
60
61 atomic_t nr_srvs = 0; /* debugging - concerned about leaking mem */
62
63 static void srv_release(struct kref *kref)
64 {
65         struct srvfile *srv = container_of(kref, struct srvfile, ref);
66         kfree(srv->user);
67         kfree(srv->name);
68         if (srv->chan)
69                 cclose(srv->chan);
70         kfree(srv);
71         atomic_dec(nr_srvs);
72 }
73
74 static int srvgen(struct chan *c, char *name, struct dirtab *tab,
75                   int ntab, int s, struct dir *dp)
76 {
77         struct srvfile *prev, *next;
78         struct qid q;
79
80         if (s == DEVDOTDOT) {
81                 /* changing whatever c->aux was to be topdir */
82                 kref_get(&top_dir->ref, 1);
83                 kref_put(&((struct srvfile*)(c->aux))->ref);
84                 mkqid(&q, Qtopdir, 0, QTDIR);
85                 devdir(c, q, "#s", 0, eve, 0555, dp);
86                 return 1;
87         }
88         /* we're genning the contents of the #s/ directory.  first time through, we
89          * just give the first item.  we have a c->aux from a previous run, though
90          * for s == 0, it's not necessarily the top_dir.
91          *
92          * while we do come in with c->aux, and it is a srvfile, it might be one
93          * that is removed from the list.  since we always add new items to the
94          * tail, if prev is still on the list, we can just return the next one.  but
95          * if we aren't on the list, we'll need to gen from scratch.
96          *
97          * This might be fucked up when we're genning and not starting from s = 0,
98          * and when prev isn't the actual previous one.  devdirread will start from
99          * other 's'es.  If prev is fucked up, we'll have to take out the on_list
100          * optimization. */
101         prev = c->aux;
102         spin_lock(&srvlock);
103         if (s == 0) {
104                 next = TAILQ_FIRST(&srvfiles);
105         } else if (prev->on_list) {
106                 assert(prev != top_dir);
107                 next = TAILQ_NEXT(prev, link);
108         } else {
109                 /* fall back to the usual scan, which is normally O(n) (O(n^2) overall).
110                  * though this only happens when there was some race and prev was
111                  * removed, and next gen it should be O(1). */
112                 TAILQ_FOREACH(next, &srvfiles, link) {
113                         /* come in with s == 0 on the first run */
114                         if (s-- == 0)
115                                 break;
116                 }
117         }
118         if (!next) {
119                 spin_unlock(&srvlock);
120                 return -1;
121         }
122         /* the list lock allows us to grab the ref */
123         kref_get(&next->ref, 1);        /* passing out via c->aux */
124         spin_unlock(&srvlock);
125         /* update c to point to our new srvfile.  this keeps the chan and its srv in
126          * sync with what we're genning.  this does suck a bit, since we'll do a
127          * lot of increfs and decrefs. */
128         kref_put(&prev->ref);
129         c->aux = next;          
130         mkqid(&q, Qsrvfile, 0, QTFILE);
131         devdir(c, q, next->name, 1/* length */, next->user, next->perm, dp);
132         return 1;
133 }
134
135 static void __srvinit(void)
136 {
137         top_dir = kzmalloc(sizeof(struct srvfile), KMALLOC_WAIT);
138         /* kstrdup, just in case we free this later */
139         kstrdup(&top_dir->name, "srv");
140         kstrdup(&top_dir->user, current ? current->user : "eve");
141         top_dir->perm = DMDIR | 0770;
142         /* +1 for existing, should never decref this */
143         kref_init(&top_dir->ref, fake_release, 1);
144         atomic_set(&top_dir->opens, 0);
145 }
146
147 static void srvinit(void)
148 {
149         run_once(__srvinit());
150 }
151
152 static struct chan *srvattach(char *spec)
153 {
154         /* the inferno attach was pretty complicated, but
155          * we're not sure that complexity is needed. */
156         struct chan *c = devattach('s', spec);
157         mkqid(&c->qid, Qtopdir, 0, QTDIR);
158         /* c->aux is a counted ref */
159         kref_get(&top_dir->ref, 1);
160         c->aux = top_dir;
161         return c;
162 }
163
164 static struct walkqid *srvwalk(struct chan *c, struct chan *nc, char **name,
165                                                            int nname)
166 {
167         struct srvfile *srv = c->aux;
168         assert(srv);    /* all srv chans should have an aux. */
169         struct walkqid *wq = devwalk(c, nc, name, nname, 0, 0, srvgen);
170         /* I don't fully understand this, but when wq and wq->clone return, we need
171          * to account for the aux (example, devip, devpipe, etc, though those differ
172          * in that they have one aux for the entire #device).
173          *
174          * i think this is because the callers of our walk track and cclose the
175          * initial chan , regardless of what we did internally.  walk() does this
176          * (via *cp).  though the main one i've run into is cclone().  callers of
177          * cclone() close both the source chan and the cloned chan.
178          *
179          * So even though our gen moved along the steps of the state machine,
180          * tracking each change of the working chan (via inc and decref), the caller
181          * has an extra copy of the original c that it'll close.  
182          *
183          * So i think we should be increffing the original c->aux, and that we
184          * already accounted for wq->clone (when we ran gen, and genned the final
185          * answer).
186          *
187          * Regarding the clone != c check: many other devs do this, and it's
188          * probably correct.  One thing: the c->aux is per chan, and the srv ref
189          * only gets put once per chan close.  If the two chans (clone and c) are
190          * the same, then there is one real chan with a chan refcnt of 2.  We don't
191          * want a refcnt of 2 on the srv, since there is really only one srv ref.
192          *
193          * Oh, and FYI, when we're called from clone, nnames == 0, and some devs
194          * (like the original inferno srv) treat that case differently. */
195         if (wq && wq->clone && (wq->clone != c)) {
196                 assert(wq->clone->aux); /* make sure this ran through gen */
197                 kref_get(&srv->ref, 1);
198         }
199         return wq;
200 }
201
202 static int srvstat(struct chan *c, uint8_t * db, int n)
203 {
204         return devstat(c, db, n, 0, 0, srvgen);
205 }
206
207 static struct chan *srvopen(struct chan *c, int omode)
208 {
209         struct srvfile *srv;
210         openmode(omode);        /* used as an error checker in plan9, does little now */
211         if (c->qid.type & QTDIR) {
212                 if (!IS_RDONLY(omode))
213                         error(Eisdir);
214                 c->mode = openmode(omode);
215                 c->flag |= COPEN;
216                 c->offset = 0;
217                 return c;
218         }
219         /* c->aux is a counted ref.  srv could be removed from the list already. */
220         srv = c->aux;
221         devpermcheck(srv->user, srv->perm, omode);
222         /* No remove on close support yet */
223         #if 0
224         if (omode & ORCLOSE) {
225                 if (strcmp(srv->user, up->env->user) != 0)
226                         error(Eperm);
227                 else
228                         srv->flags |= SORCLOSE;
229         }
230         #endif
231         if ((srv->perm & DMEXCL) && atomic_read(&srv->opens))
232                 error(Einuse);
233         /* srv->chan is write-once, so we don't need to sync. */
234         if (!srv->chan)
235                 error("srv file has no chan yet");
236         /* this is more than just the ref - 1, since there will be refs in flight
237          * as gens work their way through the list */
238         atomic_inc(&srv->opens);
239         /* the magic of srv: open c, get c->srv->chan back */
240         cclose(c);      /* also closes/decrefs c->aux */
241         c = srv->chan;
242         kref_get(&c->ref, 1);
243         return c;
244 }
245
246 static void srvcreate(struct chan *c, char *name, int omode, uint32_t perm)
247 {
248         struct srvfile *srv;
249         srv = kzmalloc(sizeof(struct srvfile), KMALLOC_WAIT);
250         kstrdup(&srv->name, name);
251         kstrdup(&srv->user, current ? current->user : "eve");
252         srv->perm = 0770;       /* TODO need some security thoughts */
253         atomic_set(&srv->opens, 1);                     /* we return it opened */
254         mkqid(&c->qid, Qsrvfile, 0, QTFILE);
255         /* we're switching the chan that came in from the old one to the one we
256          * created.  we're caleled from namec, where our c == cnew. */
257         kref_put(&((struct srvfile*)c->aux)->ref);
258         c->aux = srv;
259         /* one ref for being on the list, another for c->aux */
260         kref_init(&srv->ref, srv_release, 2);
261         spin_lock(&srvlock);
262         srv->on_list = TRUE;
263         TAILQ_INSERT_TAIL(&srvfiles, srv, link);
264         spin_unlock(&srvlock);
265         atomic_inc(&nr_srvs);
266 }
267
268 static int srvwstat(struct chan *c, uint8_t * dp, int n)
269 {
270         error("srvwstat not supported yet");
271         return -1;
272 }
273
274 static void srvclose(struct chan *c)
275 {
276         struct srvfile *srv = c->aux;
277         atomic_dec(&srv->opens);
278         kref_put(&srv->ref);
279 }
280
281 static void srvremove(struct chan *c)
282 {
283         struct srvfile *srv = c->aux;
284
285         spin_lock(&srvlock);
286         /* could have a concurrent removal */
287         if (srv->on_list) {
288                 TAILQ_REMOVE(&srvfiles, srv, link);
289                 srv->on_list = FALSE;
290                 /* for my sanity.  when closing, we should have two refs, one for being
291                  * on the list, and the other for c->aux, which gets closed later. */
292                 assert(kref_refcnt(&srv->ref) > 1);
293                 kref_put(&srv->ref);    /* dropping ref from the list */
294         }
295         spin_unlock(&srvlock);
296 }
297
298 /* N.B. srvopen gives the chan back. The only 'reading' we do
299  * in srv is of the top level directory.
300  */
301 static long srvread(struct chan *c, void *va, long count, int64_t offset)
302 {
303         return devdirread(c, va, count, 0, 0, srvgen);
304 }
305
306 static long srvwrite(struct chan *c, void *va, long count, int64_t offset)
307 {
308         ERRSTACK(1);
309         struct srvfile *srv;
310         struct chan *new_chan;
311         char *kbuf = 0;
312         int fd;
313
314         if (c->qid.type & QTDIR)
315                 error(Eperm);
316         /* srv is refcnt'd, no fear of it disappearing */
317         srv = c->aux;
318         if (srv->chan)
319                 error("srv file already has a stored chan!");
320         if (waserror()) {
321                 kfree(kbuf);
322                 nexterror();
323         }
324         kbuf = kmalloc(count + 1, KMALLOC_WAIT);
325         strncpy(kbuf, va, count);
326         kbuf[count] = 0;
327         fd = strtoul(kbuf, 0, 10);
328         /* the magic of srv: srv stores the chan corresponding to the fd.  -1 for
329          * mode, so we just get the chan with no checks (RDWR would work too). */
330         new_chan = fdtochan(current->fgrp, fd, -1, FALSE, TRUE);
331         /* fdtochan already increffed for us */
332         if (!__sync_bool_compare_and_swap(&srv->chan, 0, new_chan)) {
333                 cclose(new_chan);
334                 error("srv file already has a stored chan!");
335         }
336         poperror();
337         kfree(kbuf);
338         return count;
339 }
340
341 struct dev srvdevtab __devtab = {
342         's',
343         "srv",
344
345         devreset,
346         srvinit,
347         devshutdown,
348         srvattach,
349         srvwalk,
350         srvstat,
351         srvopen,
352         srvcreate,
353         srvclose,
354         srvread,
355         devbread,
356         srvwrite,
357         devbwrite,
358         srvremove,
359         srvwstat
360 };