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, Universitaetstrasse 6, 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 35struct 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 42struct 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 53static 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 63static 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 81static 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 110static 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 = 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 155static 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 163static 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 197static 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 232static 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 251static 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 281static 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 307static 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 357static 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 398static errval_t trivfs_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 413static 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 443static 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 473static 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 489static 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 = trivfs_truncate, 500 .create_call = create, 501 .mkdir_call = mkdir, 502 .delete_call = delete, 503}; 504 505static 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 520static 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 534errval_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} 540