flounder: making const pointers in receiving handlers, using CONST_CAST as a temporar...
[barrelfish] / usr / ramfsd / service.c
1 /**
2  * \file
3  * \brief ramfs service
4  */
5
6 /*
7  * Copyright (c) 2010, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <string.h>
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/nameservice_client.h>
18 #include <barrelfish/bulk_transfer.h>
19 #include <barrelfish/vregion.h>
20 #include <if/trivfs_defs.h>
21 #include <if/monitor_defs.h>
22
23 #include "ramfs.h"
24
25 #define SERVICE_NAME    "ramfs"
26
27 #define FHTAB_SIZE_BITS 8
28 #define FHTAB_SIZE_MASK ((1U << FHTAB_SIZE_BITS) - 1)
29 #define FHTAB_LEN       (1U << FHTAB_SIZE_BITS)
30 #define FH_BITS         (sizeof(trivfs_fh_t) * NBBY)
31 #define FHGEN_BITS      (FH_BITS - FHTAB_SIZE_BITS)
32
33 #define NULL_FH         ((trivfs_fh_t)-1u)
34
35 struct msgq_elem {
36     enum trivfs_msg_enum msgnum;
37     union trivfs_rx_arg_union a;
38     struct dirent *dirent;
39     struct msgq_elem *next;
40 };
41
42 struct client_state {
43     struct dirent *root;
44     struct dirent *fhtab[FHTAB_LEN];
45     unsigned fhindex, fhgen;
46     struct msgq_elem *qstart, *qend; ///< queue of pending replies
47     struct bulk_transfer_slave bulk;
48     struct vregion *bulk_vregion;
49 };
50
51 /* ------------------------------------------------------------------------- */
52
53 static void client_state_init(struct client_state *st, struct dirent *root)
54 {
55     st->root = root;
56     memset(st->fhtab, 0, sizeof(st->fhtab));
57     st->fhindex = 0;
58     st->fhgen = 0;
59     st->qstart = st->qend = NULL;
60     st->bulk_vregion = NULL;
61 }
62
63 static trivfs_fh_t fh_set(struct client_state *st, struct dirent *d)
64 {
65     // use the next index slot
66     st->fhtab[st->fhindex] = d;
67     ramfs_incref(d);
68
69     // construct fh: generation and index
70     trivfs_fh_t fh = ((trivfs_fh_t)st->fhgen << FHTAB_SIZE_BITS) | st->fhindex;
71
72     // update index (and generation if needed)
73     if (++st->fhindex == FHTAB_LEN) {
74         st->fhindex = 0;
75         st->fhgen++;
76     }
77
78     return fh;
79 }
80
81 static struct dirent *fh_get(struct client_state *st, trivfs_fh_t fh)
82 {
83     // unpack fh
84     unsigned gen = fh >> FHTAB_SIZE_BITS;
85     unsigned idx = fh & FHTAB_SIZE_MASK;
86
87     // check if it's still valid
88     struct dirent *e = NULL;
89     if ((gen == st->fhgen && idx < st->fhindex)
90         || (gen == st->fhgen - 1 && idx >= st->fhindex)) {
91         e = st->fhtab[idx];
92     }
93
94     if (e == NULL) {
95         return NULL; // invalid or stale
96     }
97
98     if (ramfs_islive(e)) {
99         return e; // valid
100     }
101
102     // has been deleted
103     st->fhtab[idx] = NULL;
104     ramfs_decref(e);
105     return NULL;
106 }
107
108 /* ------------------------------------------------------------------------- */
109
110 static errval_t ramfs_bulk_init(struct trivfs_binding *b, struct capref shared_frame,
111                                 errval_t *reterr)
112 {
113     struct client_state *st = b->st;
114     errval_t err;
115
116     *reterr = SYS_ERR_OK;
117
118     if (st->bulk_vregion != NULL) {
119         *reterr = FS_ERR_BULK_ALREADY_INIT;
120         cap_destroy(shared_frame);
121         return SYS_ERR_OK;
122     }
123
124     // Determine size of frame
125     struct frame_identity frameid;
126     err = invoke_frame_identify(shared_frame, &frameid);
127     if (err_is_fail(err)) {
128         *reterr = err_push(err, LIB_ERR_FRAME_IDENTIFY);
129         cap_destroy(shared_frame);
130         return SYS_ERR_OK;
131     }
132
133     size_t bulk_size = frameid.bytes;
134
135     // Map the frame in local memory
136     void *bulk_pool;
137     err = vspace_map_one_frame_attr(&bulk_pool, bulk_size, shared_frame,
138                                     VREGION_FLAGS_READ_WRITE_MPB, NULL,
139                                     &st->bulk_vregion);
140     if (err_is_fail(err)) {
141         cap_destroy(shared_frame);
142         *reterr = err_push(err, LIB_ERR_VSPACE_MAP);
143         return SYS_ERR_OK;
144     }
145     assert(bulk_pool != NULL);
146     assert(st->bulk_vregion != NULL);
147
148     // Init the bulk transfer library
149     err = bulk_slave_init(bulk_pool, bulk_size, &st->bulk);
150     assert(err_is_ok(err));
151
152     return SYS_ERR_OK;
153 }
154
155 static errval_t getroot(struct trivfs_binding *b, trivfs_fh_t *rootfh)
156 {
157     struct client_state *st = b->st;
158     *rootfh = fh_set(st, st->root);
159
160     return SYS_ERR_OK;
161 }
162
163 static errval_t readdir(struct trivfs_binding *b, trivfs_fh_t dir, uint32_t idx,
164                         errval_t *reterr, char *name, bool *isdir,
165                         trivfs_fsize_t *size)
166 {
167     errval_t err;
168     *reterr = SYS_ERR_OK;
169     struct client_state *st = b->st;
170     name[0] = 0;
171     *isdir = false;
172     *size = 0;
173
174     struct dirent *d = fh_get(st, dir);
175     if (d == NULL) {
176         *reterr = FS_ERR_INVALID_FH;
177         return SYS_ERR_OK;
178     }
179
180     struct dirent *e = NULL;
181     err = ramfs_readdir(d, idx, &e);
182     if (err_is_fail(err)) {
183         *reterr = err;
184         return SYS_ERR_OK;
185     } else if (e == NULL) {
186         *reterr = FS_ERR_INDEX_BOUNDS;
187         return SYS_ERR_OK;
188     }
189
190     ramfs_incref(e);
191     strncpy(name, ramfs_get_name(e), trivfs__read_response_data_MAX_ARGUMENT_SIZE);
192     *isdir = ramfs_isdir(e);
193     *size = ramfs_get_size(e);
194     return SYS_ERR_OK;
195 }
196
197 static errval_t lookup(struct trivfs_binding *b, trivfs_fh_t dir, const char *name,
198                        errval_t *reterr, trivfs_fh_t *retfh, bool *isdir)
199 {
200     errval_t err;
201     *reterr = SYS_ERR_OK;
202     struct client_state *st = b->st;
203     *retfh = NULL_FH;
204     *isdir = false;
205
206     struct dirent *d = fh_get(st, dir);
207     if (d == NULL) {
208         *reterr = FS_ERR_INVALID_FH;
209         return SYS_ERR_OK;
210     }
211
212     if (name == NULL) {
213         *reterr = FS_ERR_NOTFOUND;
214         return SYS_ERR_OK;
215     }
216
217     struct dirent *e = NULL;
218     err = ramfs_lookup(d, name, &e);
219     if (err_is_fail(err)) {
220         *reterr = err;
221         return SYS_ERR_OK;
222     } else if (e == NULL) {
223         *reterr = FS_ERR_INDEX_BOUNDS;
224         return SYS_ERR_OK;
225     }
226
227     *retfh = fh_set(st, e);
228     *isdir = ramfs_isdir(e);
229     return SYS_ERR_OK;
230 }
231
232 static errval_t getattr(struct trivfs_binding *b, trivfs_fh_t fh,
233                         errval_t *reterr, bool *isdir, trivfs_fsize_t *size)
234 {
235     *reterr = SYS_ERR_OK;
236     struct client_state *st = b->st;
237     *isdir = false;
238     *size = 0;
239
240     struct dirent *e = fh_get(st, fh);
241     if (e == NULL) {
242         *reterr = FS_ERR_INVALID_FH;
243         return SYS_ERR_OK;
244
245     }
246     *isdir = ramfs_isdir(e);
247     *size = ramfs_get_size(e);
248     return SYS_ERR_OK;
249 }
250
251 static errval_t read(struct trivfs_binding *b, trivfs_fh_t fh,
252                  trivfs_offset_t offset, trivfs_fsize_t maxlen,
253                  errval_t *reterr, uint8_t data[2048], size_t *len)
254 {
255     errval_t err;
256     *reterr = SYS_ERR_OK;
257     struct client_state *st = b->st;
258     uint8_t *buf = NULL;
259     *len = 0;
260
261     struct dirent *f = fh_get(st, fh);
262     if (f == NULL) {
263         *reterr = FS_ERR_INVALID_FH;
264         return SYS_ERR_OK;
265     }
266
267     err = ramfs_read(f, offset, &buf, len);
268     if (err_is_fail(err)) {
269         *reterr = err;
270         return SYS_ERR_OK;
271     }
272
273     if (*len > maxlen) {
274         *len = maxlen;
275     }
276     memcpy(data, buf, *len);
277     ramfs_incref(f);
278     return SYS_ERR_OK;
279 }
280
281 static errval_t write(struct trivfs_binding *b, trivfs_fh_t fh,
282                       trivfs_offset_t offset, const uint8_t *data, size_t len,
283                       errval_t *reterr)
284 {
285     errval_t err;
286     *reterr = SYS_ERR_OK;
287     struct client_state *st = b->st;
288
289     struct dirent *f = fh_get(st, fh);
290     if (f == NULL) {
291         *reterr = FS_ERR_INVALID_FH;
292         return SYS_ERR_OK;
293     }
294
295     uint8_t *buf;
296
297     err = ramfs_grow(f, offset, len, &buf);
298     if (err_is_fail(err)) {
299         *reterr = err;
300         return SYS_ERR_OK;
301     }
302
303     memcpy(buf, data, len);
304     return SYS_ERR_OK;
305 }
306
307 static errval_t read_bulk(struct trivfs_binding *b, trivfs_fh_t fh,
308                           trivfs_offset_t offset, trivfs_fsize_t maxlen,
309                           trivfs_bulkid_t bulkid, errval_t *reterr,
310                           trivfs_fsize_t *retlen)
311 {
312     errval_t err;
313     *reterr = SYS_ERR_OK;
314     struct client_state *st = b->st;
315     uint8_t *ramfsbuf = NULL;
316     size_t len = 0;
317
318     if (st->bulk_vregion == NULL) {
319         *reterr = FS_ERR_BULK_NOT_INIT;
320         return SYS_ERR_OK;
321     }
322
323     struct dirent *f = fh_get(st, fh);
324     if (f == NULL) {
325         *reterr = FS_ERR_INVALID_FH;
326         return SYS_ERR_OK;
327     }
328
329     err = ramfs_read(f, offset, &ramfsbuf, &len);
330     if (err_is_fail(err)) {
331         *reterr = err;
332         return SYS_ERR_OK;
333     }
334
335     // determine local address of bulk buffer
336     size_t bulk_size;
337     void *bulkbuf = bulk_slave_buf_get_mem(&st->bulk, bulkid, &bulk_size);
338
339     // limit max len to size of bulk buffer
340     if (maxlen > bulk_size) {
341         maxlen = bulk_size;
342     }
343
344     // limit read len to maxlen
345     if (len > maxlen) {
346         len = maxlen;
347     }
348
349     *retlen = len;
350     // copy data to bulk buffer
351     memcpy(bulkbuf, ramfsbuf, len);
352     // prepare bulk buffer for reply
353     bulk_slave_prepare_send(&st->bulk, bulkid);
354     return SYS_ERR_OK;
355 }
356
357 static errval_t write_bulk(struct trivfs_binding *b, trivfs_fh_t fh,
358                        trivfs_offset_t offset, trivfs_fsize_t len,
359                        trivfs_bulkid_t bulkid, errval_t *reterr)
360 {
361     errval_t err;
362     *reterr = SYS_ERR_OK;
363     struct client_state *st = b->st;
364
365     if (st->bulk_vregion == NULL) {
366         *reterr = FS_ERR_BULK_NOT_INIT;
367         return SYS_ERR_OK;
368     }
369
370     struct dirent *f = fh_get(st, fh);
371     if (f == NULL) {
372         *reterr = FS_ERR_INVALID_FH;
373         return SYS_ERR_OK;
374     }
375
376     // determine local address of bulk buffer
377     size_t maxlen;
378     void *bulkbuf = bulk_slave_buf_get_mem(&st->bulk, bulkid, &maxlen);
379
380     // limit len to size of bulk buffer
381     if (len > maxlen) {
382         len = maxlen;
383     }
384
385     uint8_t *ramfsbuf;
386     err = ramfs_grow(f, offset, len, &ramfsbuf);
387     if (err_is_fail(err)) {
388         *reterr = err;
389         return SYS_ERR_OK;
390     }
391
392     bulk_slave_prepare_recv(&st->bulk, bulkid);
393
394     memcpy(ramfsbuf, bulkbuf, len);
395     return SYS_ERR_OK;
396 }
397
398 static errval_t truncate(struct trivfs_binding *b, trivfs_fh_t fh,
399                          trivfs_fsize_t newsize, errval_t *reterr)
400 {
401     *reterr = SYS_ERR_OK;
402     struct client_state *st = b->st;
403
404     struct dirent *f = fh_get(st, fh);
405     if (f == NULL) {
406         *reterr = FS_ERR_INVALID_FH;
407     } else {
408         *reterr = ramfs_resize(f, newsize);
409     }
410     return SYS_ERR_OK;
411 }
412
413 static errval_t create(struct trivfs_binding *b, trivfs_fh_t dir, const char *name,
414                        errval_t *reterr, trivfs_fh_t *fh)
415 {
416     errval_t err;
417     *reterr = SYS_ERR_OK;
418     struct client_state *st = b->st;
419     *fh = NULL_FH;
420
421     struct dirent *d = fh_get(st, dir);
422     if (d == NULL) {
423         *reterr = FS_ERR_INVALID_FH;
424         return SYS_ERR_OK;
425     }
426
427     if (name == NULL) {
428         *reterr = FS_ERR_EXISTS; // XXX
429         return SYS_ERR_OK;
430     }
431
432     struct dirent *newf;
433     err = ramfs_create(d, name, &newf);
434     if (err_is_fail(err)) {
435         *reterr = err;
436         return SYS_ERR_OK;
437     }
438
439     *fh = fh_set(st, newf);
440     return SYS_ERR_OK;
441 }
442
443 static errval_t mkdir(struct trivfs_binding *b, trivfs_fh_t dir, const char *name,
444                       errval_t *reterr, trivfs_fh_t *fh)
445 {
446     errval_t err;
447     *reterr = SYS_ERR_OK;
448     struct client_state *st = b->st;
449     *fh = NULL_FH;
450
451     struct dirent *d = fh_get(st, dir);
452     if (d == NULL) {
453         *reterr = FS_ERR_INVALID_FH;
454         return SYS_ERR_OK;
455     }
456
457     if (name == NULL) {
458         *reterr = FS_ERR_EXISTS; // XXX
459         return SYS_ERR_OK;
460     }
461
462     struct dirent *newd;
463     err = ramfs_mkdir(d, name, &newd);
464     if (err_is_fail(err)) {
465         *reterr = err;
466         return SYS_ERR_OK;
467     }
468
469     *fh = fh_set(st, newd);
470     return SYS_ERR_OK;
471 }
472
473 static errval_t delete(struct trivfs_binding *b, trivfs_fh_t fh, errval_t *reterr)
474 {
475     *reterr = SYS_ERR_OK;
476     struct client_state *st = b->st;
477
478     struct dirent *d = fh_get(st, fh);
479     if (d == NULL) {
480         *reterr = FS_ERR_INVALID_FH;
481     } else {
482         *reterr = ramfs_delete(d);
483     }
484     return SYS_ERR_OK;
485 }
486
487 /* ------------------------------------------------------------------------- */
488
489 static struct trivfs_rpc_rx_vtbl rpc_rx_vtbl = {
490     .bulk_init_call = ramfs_bulk_init,
491     .getroot_call = getroot,
492     .readdir_call = readdir,
493     .lookup_call = lookup,
494     .getattr_call = getattr,
495     .read_call = read,
496     .write_call = write,
497     .read_bulk_call = read_bulk,
498     .write_bulk_call = write_bulk,
499     .truncate_call = truncate,
500     .create_call = create,
501     .mkdir_call = mkdir,
502     .delete_call = delete,
503 };
504
505 static void export_cb(void *st, errval_t err, iref_t iref)
506 {
507     if (err_is_fail(err)) {
508         DEBUG_ERR(err, "export failed");
509         abort();
510     }
511
512     // register this iref with the name service
513     struct monitor_binding *mb = get_monitor_binding();
514     err = mb->tx_vtbl.set_ramfs_iref_request(mb, NOP_CONT, iref);
515     if(err_is_fail(err)) {
516         USER_PANIC_ERR(err, "failed to send set_ramfs_iref_request to monitor");
517     }
518 }
519
520 static errval_t connect_cb(void *st, struct trivfs_binding *b)
521 {
522     // copy my message receive handler vtable to the binding
523     b->rpc_rx_vtbl = rpc_rx_vtbl;
524
525     // init state
526     struct client_state *bst = malloc(sizeof(struct client_state));
527     assert(bst != NULL);
528     client_state_init(bst, st);
529     b->st = bst;
530
531     return SYS_ERR_OK;
532 }
533
534 errval_t start_service(struct dirent *root)
535 {
536     // Offer the fs service
537     return trivfs_export(root, export_cb, connect_cb, get_default_waitset(),
538                          IDC_EXPORT_FLAGS_DEFAULT);
539 }