6349bb3f63aa572d4e8f2dc243557cf43737bf17
[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         strncpy(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), KMALLOC_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);
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("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);
212                 else
213                         srv->flags |= SORCLOSE;
214         }
215 #endif
216         if ((srv->perm & DMEXCL) && atomic_read(&srv->opens))
217                 error(Einuse);
218         /* srv->chan is write-once, so we don't need to sync. */
219         if (!srv->chan)
220                 error("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), KMALLOC_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("srvwstat not supported yet");
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);
301         srv = c->aux;
302         if (!grab_ref(srv))
303                 error("Unable to write srv file, concurrent removal");
304         if (waserror()) {
305                 kref_put(&srv->ref);
306                 nexterror();
307         }
308         if (srv->chan)
309                 error("srv file already has a stored chan!");
310         if (waserror()) {
311                 kfree(kbuf);
312                 nexterror();
313         }
314         kbuf = kmalloc(count + 1, KMALLOC_WAIT);
315         strncpy(kbuf, va, count);
316         kbuf[count] = 0;
317         fd = strtoul(kbuf, 0, 10);
318         /* the magic of srv: srv stores the chan corresponding to the fd.  -1 for
319          * mode, so we just get the chan with no checks (RDWR would work too). */
320         new_chan = fdtochan(&current->open_files, fd, -1, FALSE, TRUE);
321         /* fdtochan already increffed for us */
322         if (!__sync_bool_compare_and_swap(&srv->chan, 0, new_chan)) {
323                 cclose(new_chan);
324                 error("srv file already has a stored chan!");
325         }
326         poperror();
327         kfree(kbuf);
328         poperror();
329         kref_put(&srv->ref);
330         return count;
331 }
332
333 struct dev srvdevtab __devtab = {
334         "srv",
335
336         devreset,
337         srvinit,
338         devshutdown,
339         srvattach,
340         srvwalk,
341         srvstat,
342         srvopen,
343         srvcreate,
344         srvclose,
345         srvread,
346         devbread,
347         srvwrite,
348         devbwrite,
349         srvremove,
350         srvwstat,
351         devpower,
352         devchaninfo,
353 };