diff options
author | Nikolaus Rath <Nikolaus@rath.org> | 2017-08-04 22:38:03 +0200 |
---|---|---|
committer | Nikolaus Rath <Nikolaus@rath.org> | 2017-08-06 10:13:43 +0200 |
commit | b3109e71faf2713402f70d226617352815f6c72e (patch) | |
tree | 46d878cf848256eb420ccf66af20fa9faa269e2b /example | |
parent | 53c07425fa378eedb9b38c05025da5832d7a3a2e (diff) |
Added writeback cache to passthrough_ll
This fixes issue #191 (where the test was done by simply adding
FUSE_CAP_WRITEBACK_CACHE without adjusting the flags in the
open() call).
Fixes: #191.
Diffstat (limited to 'example')
-rw-r--r-- | example/passthrough_ll.c | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c index 36ca120..65ab0f3 100644 --- a/example/passthrough_ll.c +++ b/example/passthrough_ll.c @@ -19,6 +19,13 @@ * until the file is not opened anymore would make the example much * more complicated. * + * When writeback caching is enabled (-o writeback mount option), it + * is only possible to write to files for which the mounting user has + * read permissions. This is because the writeback cache requires the + * kernel to be able to issue read requests for all files (which the + * passthrough filesystem cannot satisfy if it can't read the file in + * the underlying filesystem). + * * Compile with: * * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll @@ -72,9 +79,18 @@ struct lo_inode { struct lo_data { int debug; + int writeback; struct lo_inode root; }; +static const struct fuse_opt lo_opts[] = { + { "writeback", + offsetof(struct lo_data, writeback), 1 }, + { "no_writeback", + offsetof(struct lo_data, writeback), 0 }, + FUSE_OPT_END +}; + static struct lo_data *lo_data(fuse_req_t req) { return (struct lo_data *) fuse_req_userdata(req); @@ -101,8 +117,15 @@ static bool lo_debug(fuse_req_t req) static void lo_init(void *userdata, struct fuse_conn_info *conn) { - (void) userdata; + struct lo_data *lo = (struct lo_data*) userdata; conn->want |= FUSE_CAP_EXPORT_SUPPORT; + + if (lo->writeback && + conn->capable & FUSE_CAP_WRITEBACK_CACHE) { + if (lo->debug) + fprintf(stderr, "lo_init: activating writeback\n"); + conn->want |= FUSE_CAP_WRITEBACK_CACHE; + } } static void lo_getattr(fuse_req_t req, fuse_ino_t ino, @@ -427,6 +450,23 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, fprintf(stderr, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino, fi->flags); + /* With writeback cache, kernel may send read requests even + when userspace opened write-only */ + if (lo_data(req)->writeback && + (fi->flags & O_ACCMODE) == O_WRONLY) { + fi->flags &= ~O_ACCMODE; + fi->flags |= O_RDWR; + } + + /* With writeback cache, O_APPEND is handled by the kernel. + This breaks atomicity (since the file may change in the + underlying filesystem, so that the kernel's idea of the + end of the file isn't accurate anymore). In this example, + we just accept that. A more rigorous filesystem may want + to return an error here */ + if (lo_data(req)->writeback && (fi->flags & O_APPEND)) + fi->flags &= ~O_APPEND; + sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino)); fd = open(buf, fi->flags & ~O_NOFOLLOW); if (fd == -1) @@ -505,7 +545,8 @@ int main(int argc, char *argv[]) struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts opts; - struct lo_data lo = { .debug = 0 }; + struct lo_data lo = { .debug = 0, + .writeback = 0 }; int ret = -1; lo.root.next = lo.root.prev = &lo.root; @@ -526,6 +567,9 @@ int main(int argc, char *argv[]) goto err_out1; } + if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1) + return 1; + lo.debug = opts.debug; lo.root.fd = open("/", O_PATH); lo.root.nlookup = 2; |