7 * Copyright (c) 2010, ETH Zurich.
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.
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>
25 #define SERVICE_NAME "ramfs"
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)
33 #define NULL_FH ((trivfs_fh_t)-1u)
36 enum trivfs_msg_enum msgnum;
37 union trivfs_rx_arg_union a;
38 struct dirent *dirent;
39 struct msgq_elem *next;
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;
51 /* ------------------------------------------------------------------------- */
53 static void client_state_init(struct client_state *st, struct dirent *root)
56 memset(st->fhtab, 0, sizeof(st->fhtab));
59 st->qstart = st->qend = NULL;
60 st->bulk_vregion = NULL;
63 static trivfs_fh_t fh_set(struct client_state *st, struct dirent *d)
65 // use the next index slot
66 st->fhtab[st->fhindex] = d;
69 // construct fh: generation and index
70 trivfs_fh_t fh = ((trivfs_fh_t)st->fhgen << FHTAB_SIZE_BITS) | st->fhindex;
72 // update index (and generation if needed)
73 if (++st->fhindex == FHTAB_LEN) {
81 static struct dirent *fh_get(struct client_state *st, trivfs_fh_t fh)
84 unsigned gen = fh >> FHTAB_SIZE_BITS;
85 unsigned idx = fh & FHTAB_SIZE_MASK;
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)) {
95 return NULL; // invalid or stale
98 if (ramfs_islive(e)) {
103 st->fhtab[idx] = NULL;
108 /* ------------------------------------------------------------------------- */
110 static errval_t ramfs_bulk_init(struct trivfs_binding *b, struct capref shared_frame,
113 struct client_state *st = b->st;
116 *reterr = SYS_ERR_OK;
118 if (st->bulk_vregion != NULL) {
119 *reterr = FS_ERR_BULK_ALREADY_INIT;
120 cap_destroy(shared_frame);
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);
133 size_t bulk_size = frameid.bytes;
135 // Map the frame in local memory
137 err = vspace_map_one_frame_attr(&bulk_pool, bulk_size, shared_frame,
138 VREGION_FLAGS_READ_WRITE_MPB, NULL,
140 if (err_is_fail(err)) {
141 cap_destroy(shared_frame);
142 *reterr = err_push(err, LIB_ERR_VSPACE_MAP);
145 assert(bulk_pool != NULL);
146 assert(st->bulk_vregion != NULL);
148 // Init the bulk transfer library
149 err = bulk_slave_init(bulk_pool, bulk_size, &st->bulk);
150 assert(err_is_ok(err));
155 static errval_t getroot(struct trivfs_binding *b, trivfs_fh_t *rootfh)
157 struct client_state *st = b->st;
158 *rootfh = fh_set(st, st->root);
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)
168 *reterr = SYS_ERR_OK;
169 struct client_state *st = b->st;
174 struct dirent *d = fh_get(st, dir);
176 *reterr = FS_ERR_INVALID_FH;
180 struct dirent *e = NULL;
181 err = ramfs_readdir(d, idx, &e);
182 if (err_is_fail(err)) {
185 } else if (e == NULL) {
186 *reterr = FS_ERR_INDEX_BOUNDS;
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);
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)
201 *reterr = SYS_ERR_OK;
202 struct client_state *st = b->st;
206 struct dirent *d = fh_get(st, dir);
208 *reterr = FS_ERR_INVALID_FH;
213 *reterr = FS_ERR_NOTFOUND;
217 struct dirent *e = NULL;
218 err = ramfs_lookup(d, name, &e);
219 if (err_is_fail(err)) {
222 } else if (e == NULL) {
223 *reterr = FS_ERR_INDEX_BOUNDS;
227 *retfh = fh_set(st, e);
228 *isdir = ramfs_isdir(e);
232 static errval_t getattr(struct trivfs_binding *b, trivfs_fh_t fh,
233 errval_t *reterr, bool *isdir, trivfs_fsize_t *size)
235 *reterr = SYS_ERR_OK;
236 struct client_state *st = b->st;
240 struct dirent *e = fh_get(st, fh);
242 *reterr = FS_ERR_INVALID_FH;
246 *isdir = ramfs_isdir(e);
247 *size = ramfs_get_size(e);
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)
256 *reterr = SYS_ERR_OK;
257 struct client_state *st = b->st;
261 struct dirent *f = fh_get(st, fh);
263 *reterr = FS_ERR_INVALID_FH;
267 err = ramfs_read(f, offset, &buf, len);
268 if (err_is_fail(err)) {
276 memcpy(data, buf, *len);
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,
286 *reterr = SYS_ERR_OK;
287 struct client_state *st = b->st;
289 struct dirent *f = fh_get(st, fh);
291 *reterr = FS_ERR_INVALID_FH;
297 err = ramfs_grow(f, offset, len, &buf);
298 if (err_is_fail(err)) {
303 memcpy(buf, data, len);
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)
313 *reterr = SYS_ERR_OK;
314 struct client_state *st = b->st;
315 uint8_t *ramfsbuf = NULL;
318 if (st->bulk_vregion == NULL) {
319 *reterr = FS_ERR_BULK_NOT_INIT;
323 struct dirent *f = fh_get(st, fh);
325 *reterr = FS_ERR_INVALID_FH;
329 err = ramfs_read(f, offset, &ramfsbuf, &len);
330 if (err_is_fail(err)) {
335 // determine local address of bulk buffer
337 void *bulkbuf = bulk_slave_buf_get_mem(&st->bulk, bulkid, &bulk_size);
339 // limit max len to size of bulk buffer
340 if (maxlen > bulk_size) {
344 // limit read len to maxlen
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);
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)
362 *reterr = SYS_ERR_OK;
363 struct client_state *st = b->st;
365 if (st->bulk_vregion == NULL) {
366 *reterr = FS_ERR_BULK_NOT_INIT;
370 struct dirent *f = fh_get(st, fh);
372 *reterr = FS_ERR_INVALID_FH;
376 // determine local address of bulk buffer
378 void *bulkbuf = bulk_slave_buf_get_mem(&st->bulk, bulkid, &maxlen);
380 // limit len to size of bulk buffer
386 err = ramfs_grow(f, offset, len, &ramfsbuf);
387 if (err_is_fail(err)) {
392 bulk_slave_prepare_recv(&st->bulk, bulkid);
394 memcpy(ramfsbuf, bulkbuf, len);
398 static errval_t truncate(struct trivfs_binding *b, trivfs_fh_t fh,
399 trivfs_fsize_t newsize, errval_t *reterr)
401 *reterr = SYS_ERR_OK;
402 struct client_state *st = b->st;
404 struct dirent *f = fh_get(st, fh);
406 *reterr = FS_ERR_INVALID_FH;
408 *reterr = ramfs_resize(f, newsize);
413 static errval_t create(struct trivfs_binding *b, trivfs_fh_t dir, const char *name,
414 errval_t *reterr, trivfs_fh_t *fh)
417 *reterr = SYS_ERR_OK;
418 struct client_state *st = b->st;
421 struct dirent *d = fh_get(st, dir);
423 *reterr = FS_ERR_INVALID_FH;
428 *reterr = FS_ERR_EXISTS; // XXX
433 err = ramfs_create(d, name, &newf);
434 if (err_is_fail(err)) {
439 *fh = fh_set(st, newf);
443 static errval_t mkdir(struct trivfs_binding *b, trivfs_fh_t dir, const char *name,
444 errval_t *reterr, trivfs_fh_t *fh)
447 *reterr = SYS_ERR_OK;
448 struct client_state *st = b->st;
451 struct dirent *d = fh_get(st, dir);
453 *reterr = FS_ERR_INVALID_FH;
458 *reterr = FS_ERR_EXISTS; // XXX
463 err = ramfs_mkdir(d, name, &newd);
464 if (err_is_fail(err)) {
469 *fh = fh_set(st, newd);
473 static errval_t delete(struct trivfs_binding *b, trivfs_fh_t fh, errval_t *reterr)
475 *reterr = SYS_ERR_OK;
476 struct client_state *st = b->st;
478 struct dirent *d = fh_get(st, fh);
480 *reterr = FS_ERR_INVALID_FH;
482 *reterr = ramfs_delete(d);
487 /* ------------------------------------------------------------------------- */
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,
497 .read_bulk_call = read_bulk,
498 .write_bulk_call = write_bulk,
499 .truncate_call = truncate,
500 .create_call = create,
502 .delete_call = delete,
505 static void export_cb(void *st, errval_t err, iref_t iref)
507 if (err_is_fail(err)) {
508 DEBUG_ERR(err, "export failed");
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");
520 static errval_t connect_cb(void *st, struct trivfs_binding *b)
522 // copy my message receive handler vtable to the binding
523 b->rpc_rx_vtbl = rpc_rx_vtbl;
526 struct client_state *bst = malloc(sizeof(struct client_state));
528 client_state_init(bst, st);
534 errval_t start_service(struct dirent *root)
536 // Offer the fs service
537 return trivfs_export(root, export_cb, connect_cb, get_default_waitset(),
538 IDC_EXPORT_FLAGS_DEFAULT);