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