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