1/* 2 * Copyright (c) 2009, 2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#define _USE_XOPEN // for strdup() 11#include <stdio.h> 12#include <string.h> 13#include <barrelfish/barrelfish.h> 14#include <barrelfish/nameservice_client.h> 15#include <barrelfish/bulk_transfer.h> 16#include <vfs/vfs_path.h> 17#include <if/trivfs_defs.h> 18#include <if/trivfs_defs.h> 19#include <if/monitor_defs.h> 20 21#include "vfs_backends.h" 22 23/// configuration setting to use bulk data (TODO: make this a mount option?) 24static const bool use_bulk_data = true; 25 26#define BULK_MEM_SIZE (1U << 16) // 64kB 27#define BULK_BLOCK_SIZE BULK_MEM_SIZE // (it's RPC) 28 29struct ramfs_client { 30 struct trivfs_binding *rpc; 31 struct bulk_transfer bulk; 32 trivfs_fh_t rootfh; 33 bool bound; 34}; 35 36struct ramfs_handle { 37 struct vfs_handle common; 38 char *path; 39 bool isdir; 40 trivfs_fh_t fh; 41 size_t pos; 42}; 43 44static errval_t resolve_path(struct ramfs_client *cl, const char *path, 45 trivfs_fh_t *retfh, size_t *retpos, bool *retisdir) 46{ 47restart: ; 48 errval_t err, msgerr = SYS_ERR_OK; 49 bool isdir = true; 50 51 /* resolve path, starting from the root */ 52 trivfs_fh_t fh = cl->rootfh; 53 54 // skip leading / 55 size_t pos = 0; 56 if (path[0] == VFS_PATH_SEP) { 57 pos++; 58 } 59 60 while (path[pos] != '\0') { 61 // copy next chunk of path to private buffer 62 char *nextsep = strchr(&path[pos], VFS_PATH_SEP); 63 size_t nextlen; 64 if (nextsep == NULL) { 65 nextlen = strlen(&path[pos]); 66 } else { 67 nextlen = nextsep - &path[pos]; 68 } 69 70 char pathbuf[nextlen + 1]; 71 memcpy(pathbuf, &path[pos], nextlen); 72 pathbuf[nextlen] = '\0'; 73 74 // lookup 75 trivfs_fh_t nextfh; 76 err = cl->rpc->rpc_tx_vtbl.lookup(cl->rpc, fh, pathbuf, &msgerr, &nextfh, &isdir); 77 if (err_is_fail(err)) { 78 DEBUG_ERR(err, "transport error in lookup"); 79 return err; 80 } else if (err_is_fail(msgerr)) { 81 if (err_no(msgerr) == FS_ERR_INVALID_FH) { 82 if (fh == cl->rootfh) { // revalidate root 83 err = cl->rpc->rpc_tx_vtbl.getroot(cl->rpc, &cl->rootfh); 84 if (err_is_fail(err)) { 85 USER_PANIC_ERR(err, "failed to get root fh"); 86 } 87 fh = cl->rootfh; 88 continue; 89 } else { 90 USER_PANIC("vfs_ramfs: handle we just received is invalid?\n"); 91 goto restart; 92 } 93 } else if (err_no(msgerr) != FS_ERR_NOTFOUND) { 94 DEBUG_ERR(msgerr, "server error in lookup of '%s' while at '%s'", 95 path, pathbuf); 96 } 97 goto out; 98 } else if (!isdir && nextsep != NULL) { 99 // not a directory, don't bother going further 100 fh = nextfh; 101 pos += nextlen + 1; 102 msgerr = FS_ERR_NOTDIR; 103 goto out; 104 } 105 106 fh = nextfh; 107 if (nextsep == NULL) { 108 break; 109 } 110 111 pos += nextlen + 1; 112 } 113 114out: 115 if (retpos != NULL) { 116 *retpos = pos; 117 } 118 if (retfh != NULL) { 119 *retfh = fh; 120 } 121 if (retisdir != NULL) { 122 *retisdir = isdir; 123 } 124 return msgerr; 125} 126 127static errval_t open(void *st, const char *path, vfs_handle_t *rethandle) 128{ 129 struct ramfs_client *cl = st; 130 trivfs_fh_t fh; 131 bool isdir; 132 errval_t err; 133 134 err = resolve_path(cl, path, &fh, NULL, &isdir); 135 if (err_is_ok(err)) { 136 if (isdir) { 137 err = FS_ERR_NOTFILE; 138 } else { 139 struct ramfs_handle *handle = malloc(sizeof(struct ramfs_handle)); 140 assert(handle != NULL); 141 142 handle->path = strdup(path); 143 assert(handle->path != NULL); 144 handle->fh = fh; 145 handle->pos = 0; 146 handle->isdir = false; 147 148 *rethandle = handle; 149 } 150 } 151 152 return err; 153} 154 155static errval_t create(void *st, const char *path, vfs_handle_t *rethandle) 156{ 157 struct ramfs_client *cl = st; 158 struct ramfs_handle *handle; 159 trivfs_fh_t fh; 160 errval_t err, msgerr; 161 bool isdir; 162 size_t pos = 0; 163 164 // try to open it normally 165 err = resolve_path(cl, path, &fh, &pos, &isdir); 166 if (err_is_ok(err)) { 167 if (isdir) { 168 return FS_ERR_NOTFILE; 169 } else { 170 goto out; // ok 171 } 172 } else if (err_no(err) != FS_ERR_NOTFOUND 173 || strchr(&path[pos], VFS_PATH_SEP) != NULL) { 174 // failed before getting to the last part of the path: error 175 return err; 176 } 177 178 // create the last part of the path 179 err = cl->rpc->rpc_tx_vtbl.create(cl->rpc, fh, &path[pos], &msgerr, &fh); 180 if (err_is_fail(err)) { 181 DEBUG_ERR(err, "transport error in create"); 182 return err; 183 } else if (err_is_fail(msgerr)) { 184 DEBUG_ERR(msgerr, "server error in create"); 185 return msgerr; 186 } 187 err = msgerr; 188 189out: 190 handle = malloc(sizeof(struct ramfs_handle)); 191 assert(handle != NULL); 192 193 handle->path = strdup(path); 194 assert(handle->path != NULL); 195 handle->fh = fh; 196 handle->pos = 0; 197 handle->isdir = false; 198 199 *rethandle = handle; 200 return err; 201} 202 203static errval_t ramfs_remove(void *st, const char *path) 204{ 205 struct ramfs_client *cl = st; 206 trivfs_fh_t fh; 207 errval_t err, msgerr; 208 bool isdir; 209 210 err = resolve_path(cl, path, &fh, NULL, &isdir); 211 if (err_is_fail(err)) { 212 return err; 213 } else if (isdir) { 214 return FS_ERR_NOTFILE; 215 } 216 217 err = cl->rpc->rpc_tx_vtbl.delete(cl->rpc, fh, &msgerr); 218 if (err_is_fail(err)) { 219 DEBUG_ERR(err, "transport error in delete"); 220 return err; 221 } else if (err_is_fail(msgerr)) { 222 DEBUG_ERR(msgerr, "server error in delete"); 223 return msgerr; 224 } 225 226 return msgerr; 227} 228 229static errval_t read(void *st, vfs_handle_t handle, void *buffer, size_t bytes, 230 size_t *bytes_read) 231{ 232 struct ramfs_handle *h = handle; 233 struct ramfs_client *cl = st; 234 int restarts = 0; 235 errval_t err, msgerr; 236 237 assert(!h->isdir); 238 239restart: 240 err = cl->rpc->rpc_tx_vtbl.read(cl->rpc, h->fh, h->pos, bytes, 241 &msgerr, buffer, bytes_read); 242 if (err_is_fail(err)) { 243 DEBUG_ERR(err, "transport error in read"); 244 return err; 245 } else if (err_is_fail(msgerr)) { 246 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 247 // revalidate handle and try again 248 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 249 if (err_is_ok(msgerr)) { 250 goto restart; 251 } 252 } 253 DEBUG_ERR(msgerr, "server error in read"); 254 return msgerr; 255 } 256 257 h->pos += *bytes_read; 258 259 if (*bytes_read < bytes) { // XXX: this can only mean EOF for ramfs 260 return VFS_ERR_EOF; 261 } else { 262 return SYS_ERR_OK; 263 } 264} 265 266static errval_t write(void *st, vfs_handle_t handle, const void *buffer, 267 size_t bytes, size_t *bytes_written) 268{ 269 struct ramfs_handle *h = handle; 270 struct ramfs_client *cl = st; 271 int restarts = 0; 272 errval_t err, msgerr; 273 274 assert(!h->isdir); 275 276restart: 277 err = cl->rpc->rpc_tx_vtbl.write(cl->rpc, h->fh, h->pos, buffer, bytes, &msgerr); 278 if (err_is_fail(err)) { 279 DEBUG_ERR(err, "transport error in write"); 280 return err; 281 } else if (err_is_fail(msgerr)) { 282 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 283 // revalidate handle and try again 284 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 285 if (err_is_ok(msgerr)) { 286 goto restart; 287 } 288 } 289 DEBUG_ERR(msgerr, "server error in write"); 290 return msgerr; 291 } 292 293 h->pos += bytes; 294 if (bytes_written != NULL) { 295 *bytes_written = bytes; 296 } 297 298 return msgerr; 299} 300 301static errval_t read_bulk(void *st, vfs_handle_t handle, void *buffer, 302 size_t bytes, size_t *ret_bytes_read) 303{ 304 struct ramfs_handle *h = handle; 305 struct ramfs_client *cl = st; 306 trivfs_fsize_t reqlen, retlen; 307 size_t bytes_read = 0; 308 errval_t err, msgerr, reterr = SYS_ERR_OK; 309 310 assert(!h->isdir); 311 312 struct bulk_buf *buf = bulk_alloc(&cl->bulk); 313 assert(buf != NULL); // shouldn't fail; we only ever use one at a time! 314 315 void *mybuf = bulk_buf_get_mem(buf); 316 317 uintptr_t bufid = bulk_buf_get_id(buf); 318 trivfs_bulkid_t txbufid = bufid; 319 assert(bufid == txbufid); 320 321 while (bytes_read < bytes) { 322 if (bytes - bytes_read > BULK_BLOCK_SIZE) { 323 reqlen = BULK_BLOCK_SIZE; 324 } else { 325 reqlen = bytes - bytes_read; 326 } 327 328 int restarts = 0; 329 330restart: 331 err = cl->rpc->rpc_tx_vtbl.read_bulk(cl->rpc, h->fh, h->pos, reqlen, 332 txbufid, &msgerr, &retlen); 333 if (err_is_fail(err)) { 334 DEBUG_ERR(err, "transport error in read"); 335 reterr = err; 336 goto out; 337 } else if (err_is_fail(msgerr)) { 338 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 339 // revalidate handle and try again 340 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 341 if (err_is_ok(msgerr)) { 342 goto restart; 343 } 344 } 345 DEBUG_ERR(msgerr, "server error in read"); 346 reterr = msgerr; 347 goto out; 348 } 349 350 bulk_prepare_recv(buf); 351 352 memcpy((char *)buffer + bytes_read, mybuf, retlen); 353 h->pos += retlen; 354 bytes_read += retlen; 355 356 if (retlen < reqlen) { // XXX: this can only mean EOF for ramfs 357 reterr = VFS_ERR_EOF; 358 goto out; 359 } 360 } 361 362out: 363 err = bulk_free(&cl->bulk, bufid); 364 assert(err_is_ok(err)); 365 366 if (ret_bytes_read != NULL) { 367 *ret_bytes_read = bytes_read; 368 } 369 370 return reterr; 371} 372 373static errval_t write_bulk(void *st, vfs_handle_t handle, const void *buffer, 374 size_t bytes, size_t *ret_bytes_written) 375{ 376 struct ramfs_handle *h = handle; 377 struct ramfs_client *cl = st; 378 size_t bytes_written = 0; 379 trivfs_fsize_t reqlen; 380 errval_t err, msgerr, reterr = SYS_ERR_OK; 381 382 assert(!h->isdir); 383 384 struct bulk_buf *buf = bulk_alloc(&cl->bulk); 385 assert(buf != NULL); // shouldn't fail; we only ever use one at a time! 386 387 void *mybuf = bulk_buf_get_mem(buf); 388 389 while (bytes_written < bytes) { 390 if (bytes - bytes_written > BULK_BLOCK_SIZE) { 391 reqlen = BULK_BLOCK_SIZE; 392 } else { 393 reqlen = bytes - bytes_written; 394 } 395 396 memcpy(mybuf, (char *)buffer + bytes_written, reqlen); 397 uintptr_t bufid = bulk_prepare_send(buf); 398 399 int restarts = 0; 400 401restart: 402 err = cl->rpc->rpc_tx_vtbl.write_bulk(cl->rpc, h->fh, h->pos, reqlen, bufid, 403 &msgerr); 404 if (err_is_fail(err)) { 405 DEBUG_ERR(err, "transport error in write"); 406 reterr = err; 407 goto out; 408 } else if (err_is_fail(msgerr)) { 409 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 410 // revalidate handle and try again 411 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 412 if (err_is_ok(msgerr)) { 413 goto restart; 414 } 415 } 416 DEBUG_ERR(msgerr, "server error in write"); 417 reterr = msgerr; 418 goto out; 419 } 420 421 h->pos += reqlen; 422 bytes_written += reqlen; 423 } 424 425out: 426 err = bulk_free(&cl->bulk, bulk_buf_get_id(buf)); 427 assert(err_is_ok(err)); 428 429 if (ret_bytes_written != NULL) { 430 *ret_bytes_written = bytes_written; 431 } 432 433 return reterr; 434} 435 436static errval_t ramfs_truncate(void *st, vfs_handle_t handle, size_t bytes) 437{ 438 struct ramfs_handle *h = handle; 439 struct ramfs_client *cl = st; 440 int restarts = 0; 441 errval_t err, msgerr; 442 443 assert(!h->isdir); 444 445restart: 446 err = cl->rpc->rpc_tx_vtbl.truncate(cl->rpc, h->fh, bytes, &msgerr); 447 if (err_is_fail(err)) { 448 DEBUG_ERR(err, "transport error in truncate"); 449 return err; 450 } else if (err_is_fail(msgerr)) { 451 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 452 // revalidate handle and try again 453 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 454 if (err_is_ok(msgerr)) { 455 goto restart; 456 } 457 } 458 DEBUG_ERR(msgerr, "server error in truncate"); 459 return msgerr; 460 } 461 462 return msgerr; 463} 464 465static errval_t tell(void *st, vfs_handle_t handle, size_t *pos) 466{ 467 struct ramfs_handle *h = handle; 468 *pos = h->pos; 469 return SYS_ERR_OK; 470} 471 472static errval_t stat(void *st, vfs_handle_t inhandle, struct vfs_fileinfo *info) 473{ 474 struct ramfs_handle *h = inhandle; 475 struct ramfs_client *cl = st; 476 trivfs_fsize_t size; 477 bool isdir; 478 errval_t err, msgerr; 479 int restarts = 0; 480 481restart: 482 err = cl->rpc->rpc_tx_vtbl.getattr(cl->rpc, h->fh, &msgerr, &isdir, &size); 483 if (err_is_fail(err)) { 484 DEBUG_ERR(err, "transport error in getattr"); 485 return err; 486 } else if (err_is_fail(msgerr)) { 487 if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) { 488 // revalidate handle and try again 489 msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL); 490 if (err_is_ok(msgerr)) { 491 goto restart; 492 } 493 } 494 DEBUG_ERR(msgerr, "server error in getattr"); 495 return msgerr; 496 } 497 498 assert(isdir == h->isdir); 499 500 assert(info != NULL); 501 info->type = isdir ? VFS_DIRECTORY : VFS_FILE; 502 info->size = size; 503 504 return SYS_ERR_OK; 505} 506 507static errval_t seek(void *st, vfs_handle_t handle, enum vfs_seekpos whence, 508 off_t offset) 509{ 510 struct ramfs_handle *h = handle; 511 struct vfs_fileinfo info; 512 errval_t err; 513 514 switch (whence) { 515 case VFS_SEEK_SET: 516 assert(offset >= 0); 517 h->pos = offset; 518 break; 519 520 case VFS_SEEK_CUR: 521 assert(offset >= 0 || -offset <= h->pos); 522 h->pos += offset; 523 break; 524 525 case VFS_SEEK_END: 526 err = stat(st, handle, &info); 527 if (err_is_fail(err)) { 528 return err; 529 } 530 assert(offset >= 0 || -offset <= info.size); 531 h->pos = info.size + offset; 532 break; 533 534 default: 535 USER_PANIC("invalid whence argument to ramfs seek"); 536 } 537 538 return SYS_ERR_OK; 539} 540 541static errval_t close(void *st, vfs_handle_t inhandle) 542{ 543 struct ramfs_handle *handle = inhandle; 544 assert(!handle->isdir); 545 free(handle->path); 546 free(handle); 547 return SYS_ERR_OK; 548} 549 550static errval_t opendir(void *st, const char *path, vfs_handle_t *rethandle) 551{ 552 struct ramfs_client *cl = st; 553 struct ramfs_handle *handle; 554 trivfs_fh_t fh; 555 errval_t err; 556 bool isdir; 557 558 err = resolve_path(cl, path, &fh, NULL, &isdir); 559 if (err_is_ok(err)) { 560 if (isdir) { 561 handle = malloc(sizeof(struct ramfs_handle)); 562 assert(handle != NULL); 563 564 handle->path = strdup(path); 565 assert(handle->path != NULL); 566 handle->fh = fh; 567 handle->pos = 0; 568 handle->isdir = true; 569 570 *rethandle = handle; 571 } else { 572 err = FS_ERR_NOTDIR; 573 } 574 } 575 576 return err; 577} 578 579static errval_t dir_read_next(void *st, vfs_handle_t inhandle, char **retname, 580 struct vfs_fileinfo *info) 581{ 582 struct ramfs_handle *h = inhandle; 583 struct ramfs_client *cl = st; 584 585 errval_t err; 586 int restarts = 0; 587 588 assert(h->isdir); 589 590 struct trivfs_readdir_response__rx_args reply; 591restart: 592 err = cl->rpc->rpc_tx_vtbl.readdir(cl->rpc, h->fh, h->pos, 593 &reply.err, reply.name, &reply.isdir, &reply.size); 594 if (err_is_fail(err)) { 595 DEBUG_ERR(err, "transport error in readdir"); 596 return err; 597 } else if (err_is_fail(reply.err)) { 598 if (err_no(reply.err) == FS_ERR_INVALID_FH && !restarts++) { 599 // revalidate handle and try again 600 if (h->fh == cl->rootfh) { // XXX: revalidate root 601 err = cl->rpc->rpc_tx_vtbl.getroot(cl->rpc, &cl->rootfh); 602 if (err_is_fail(err)) { 603 USER_PANIC_ERR(err, "failed to get root fh"); 604 } 605 h->fh = cl->rootfh; 606 goto restart; 607 } else { 608 reply.err = resolve_path(cl, h->path, &h->fh, NULL, NULL); 609 if (err_is_ok(reply.err)) { 610 goto restart; 611 } 612 } 613 } 614 if (err_no(reply.err) != FS_ERR_INDEX_BOUNDS) { 615 DEBUG_ERR(reply.err, "server error in readdir"); 616 } 617 return reply.err; 618 } 619 620 h->pos++; 621 622 if (retname != NULL) { 623 *retname = strdup(reply.name); 624 } 625 626 if (info != NULL) { 627 info->type = reply.isdir ? VFS_DIRECTORY : VFS_FILE; 628 info->size = reply.size; 629 } 630 631 return SYS_ERR_OK; 632} 633 634static errval_t closedir(void *st, vfs_handle_t dhandle) 635{ 636 struct ramfs_handle *handle = dhandle; 637 assert(handle->isdir); 638 free(handle->path); 639 free(handle); 640 return SYS_ERR_OK; 641} 642 643// fails if already present 644static errval_t mkdir(void *st, const char *path) 645{ 646 struct ramfs_client *cl = st; 647 trivfs_fh_t parent; 648 const char *childname; 649 errval_t err, msgerr; 650 bool isdir; 651 652 // find parent directory 653 char *lastsep = strrchr(path, VFS_PATH_SEP); 654 if (lastsep != NULL) { 655 childname = lastsep + 1; 656 657 size_t pathlen = lastsep - path; 658 char pathbuf[pathlen + 1]; 659 memcpy(pathbuf, path, pathlen); 660 pathbuf[pathlen] = '\0'; 661 662 // resolve parent directory 663 err = resolve_path(cl, pathbuf, &parent, NULL, &isdir); 664 if (err_is_fail(err)) { 665 return err; 666 } else if (!isdir) { 667 return FS_ERR_NOTDIR; // parent is not a directory 668 } 669 } else { 670 parent = cl->rootfh; 671 childname = path; 672 } 673 674 // create child 675 trivfs_fh_t newfh; 676 err = cl->rpc->rpc_tx_vtbl.mkdir(cl->rpc, parent, childname, &msgerr, &newfh); 677 if (err_is_fail(err)) { 678 DEBUG_ERR(err, "transport error in mkdir"); 679 return err; 680 } 681 682 return msgerr; 683} 684 685static errval_t rmdir(void *st, const char *path) 686{ 687 struct ramfs_client *cl = st; 688 trivfs_fh_t fh; 689 errval_t err, msgerr; 690 bool isdir; 691 692 err = resolve_path(cl, path, &fh, NULL, &isdir); 693 if (err_is_fail(err)) { 694 return err; 695 } else if (!isdir) { 696 return FS_ERR_NOTDIR; 697 } 698 699 err = cl->rpc->rpc_tx_vtbl.delete(cl->rpc, fh, &msgerr); 700 if (err_is_fail(err)) { 701 DEBUG_ERR(err, "transport error in delete"); 702 return err; 703 } else if (err_is_fail(msgerr)) { 704 DEBUG_ERR(msgerr, "server error in delete"); 705 return msgerr; 706 } 707 708 return msgerr; 709} 710 711static struct vfs_ops ramfsops_non_bulk = { 712 .open = open, 713 .create = create, 714 .remove = ramfs_remove, 715 .read = read, 716 .write = write, 717 .truncate = ramfs_truncate, 718 .seek = seek, 719 .tell = tell, 720 .stat = stat, 721 .close = close, 722 .opendir = opendir, 723 .dir_read_next = dir_read_next, 724 .closedir = closedir, 725 .mkdir = mkdir, 726 .rmdir = rmdir, 727}; 728 729static struct vfs_ops ramfsops_bulk = { 730 .open = open, 731 .create = create, 732 .remove = ramfs_remove, 733 .read = read_bulk, 734 .write = write_bulk, 735 .truncate = ramfs_truncate, 736 .seek = seek, 737 .tell = tell, 738 .stat = stat, 739 .close = close, 740 .opendir = opendir, 741 .dir_read_next = dir_read_next, 742 .closedir = closedir, 743 .mkdir = mkdir, 744 .rmdir = rmdir, 745}; 746 747static void bind_cb(void *st, errval_t err, struct trivfs_binding *b) 748{ 749 struct ramfs_client *cl = st; 750 751 if (err_is_fail(err)) { 752 USER_PANIC_ERR(err, "bind failed"); 753 } 754 755 cl->rpc = b; 756 trivfs_rpc_client_init(cl->rpc); 757 cl->bound = true; 758} 759 760struct iref_request_state { 761 bool is_done; 762 iref_t iref; 763 errval_t err; 764}; 765 766static void get_ramfs_iref_reply(struct monitor_binding* mb, iref_t iref, 767 uintptr_t state){ 768 struct iref_request_state* irs = (struct iref_request_state*) state; 769 770 irs->iref = iref; 771 irs->err = (iref != 0) ? SYS_ERR_OK : LIB_ERR_GET_RAMFS_IREF; 772 irs->is_done = true; 773} 774 775static errval_t get_ramfs_iref(iref_t* iref) 776{ 777 // Request iref for ramfsd directly from monitor (needed for SKB) 778 // XXX: broken :-( uintptr_t + message_wait_and_handle_next() 779 struct iref_request_state irs = { 0, 0, 0 }; 780 struct monitor_binding *mb = get_monitor_binding(); 781 mb->rx_vtbl.get_ramfs_iref_reply = get_ramfs_iref_reply; 782 783 errval_t err = mb->tx_vtbl.get_ramfs_iref_request(mb, NOP_CONT, (uintptr_t)&irs); 784 if (err_is_fail(err)) { 785 return err; 786 } 787 788 while (!irs.is_done) { 789 messages_wait_and_handle_next(); 790 } 791 792 *iref = irs.iref; 793 return irs.err; 794} 795 796errval_t vfs_ramfs_mount(const char *uri, void **retst, struct vfs_ops **retops) 797{ 798 errval_t err, msgerr; 799 iref_t iref = 0; 800 801 // skip over protocol part of URI to get service name 802 char *service = strstr(uri, "://"); 803 if (service == NULL) { 804 return VFS_ERR_BAD_URI; 805 } 806 service += 3; 807 808 // default service name 809 if (*service == '\0') { 810 service = "ramfs"; 811 } 812 813 err = get_ramfs_iref(&iref); 814 if (err_is_fail(err)) { 815 DEBUG_ERR(err, "get ramfs iref"); 816 return err; 817 } 818 819 struct ramfs_client *client = malloc(sizeof(struct ramfs_client)); 820 assert(client != NULL); 821 822 client->bound = false; 823 824 err = trivfs_bind(iref, bind_cb, client, get_default_waitset(), 825 use_bulk_data 826 ? IDC_BIND_FLAG_RPC_CAP_TRANSFER 827 : IDC_BIND_FLAGS_DEFAULT); 828 if (err_is_fail(err)) { 829 DEBUG_ERR(err, "bind failed"); 830 free(client); 831 return err; // FIXME 832 } 833 834 // XXX: block for bind completion (broken API!) 835 while (!client->bound) { 836 messages_wait_and_handle_next(); 837 } 838 839 // get root fh 840 err = client->rpc->rpc_tx_vtbl.getroot(client->rpc, &client->rootfh); 841 if (err_is_fail(err)) { 842 USER_PANIC_ERR(err, "failed to get root fh"); 843 } 844 845 if (use_bulk_data) { 846 // Init bulk data lib 847 struct capref shared_frame; 848 err = bulk_create(BULK_MEM_SIZE, BULK_BLOCK_SIZE, &shared_frame, 849 &client->bulk); 850 if(err_is_fail(err)) { 851 USER_PANIC_ERR(err, "bulk_create"); 852 } 853 854 // Send bulk frame cap to server 855 err = client->rpc->rpc_tx_vtbl.bulk_init(client->rpc, shared_frame, &msgerr); 856 if (err_is_fail(err)) { 857 USER_PANIC_ERR(err, "failed to call bulk_init"); 858 } else if (err_is_fail(msgerr)) { 859 USER_PANIC_ERR(msgerr, "bulk_init failed"); 860 } 861 } 862 863 if (use_bulk_data) { 864 *retops = &ramfsops_bulk; 865 } else { 866 *retops = &ramfsops_non_bulk; 867 } 868 *retst = client; 869 870 return SYS_ERR_OK; 871} 872