summaryrefslogtreecommitdiff
path: root/cmd_fusemount.c
diff options
context:
space:
mode:
authorJustin Husted <sigstop@gmail.com>2019-10-07 16:41:38 -0700
committerKent Overstreet <kent.overstreet@gmail.com>2019-10-18 16:23:39 -0400
commitf8076573b547f9c5a5dca058c392c83a773a0f30 (patch)
tree7413872e3f70b9b93ff3711923939ee51c0165fe /cmd_fusemount.c
parent52771aa7d2f9284e86069ef6274c92b9757c313e (diff)
Make fuse read and write work (for aligned writes).
Read: There was a missing refcount on the closure. Write: Unlike in the Linux kernel, we need to manually update the size and timestamps, otherwise the operation will appear complete when viewed via the cached inode, but after unmounting and mounting again the write will be undone.
Diffstat (limited to 'cmd_fusemount.c')
-rw-r--r--cmd_fusemount.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/cmd_fusemount.c b/cmd_fusemount.c
index 90d3d869..6460e7b9 100644
--- a/cmd_fusemount.c
+++ b/cmd_fusemount.c
@@ -188,6 +188,7 @@ retry:
inode_u.bi_atime = now;
if (to_set & FUSE_SET_ATTR_MTIME_NOW)
inode_u.bi_mtime = now;
+ /* TODO: CTIME? */
ret = bch2_inode_write(&trans, iter, &inode_u) ?:
bch2_trans_commit(&trans, NULL, NULL,
@@ -409,6 +410,7 @@ static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t inum,
userbio_init(&rbio.bio, &bv, buf, size);
bio_set_op_attrs(&rbio.bio, REQ_OP_READ, REQ_SYNC);
rbio.bio.bi_iter.bi_sector = offset >> 9;
+ closure_get(&cl);
rbio.bio.bi_end_io = bcachefs_fuse_read_endio;
rbio.bio.bi_private = &cl;
@@ -425,6 +427,43 @@ static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t inum,
free(buf);
}
+static int write_set_inode(struct bch_fs *c, fuse_ino_t inum, off_t new_size)
+{
+ struct btree_trans trans;
+ struct btree_iter *iter;
+ struct bch_inode_unpacked inode_u;
+ int ret = 0;
+ u64 now;
+
+ bch2_trans_init(&trans, c, 0, 0);
+retry:
+ bch2_trans_begin(&trans);
+ now = bch2_current_time(c);
+
+ iter = bch2_inode_peek(&trans, &inode_u, inum, BTREE_ITER_INTENT);
+ ret = PTR_ERR_OR_ZERO(iter);
+ if (ret)
+ goto err;
+
+ inode_u.bi_size = max_t(u64, inode_u.bi_size, new_size);
+ inode_u.bi_mtime = now;
+ inode_u.bi_ctime = now;
+
+ ret = bch2_inode_write(&trans, iter, &inode_u);
+ if (ret)
+ goto err;
+
+ ret = bch2_trans_commit(&trans, NULL, NULL,
+ BTREE_INSERT_ATOMIC|BTREE_INSERT_NOFAIL);
+
+err:
+ if (ret == -EINTR)
+ goto retry;
+
+ bch2_trans_exit(&trans);
+ return ret;
+}
+
static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum,
const char *buf, size_t size,
off_t offset,
@@ -469,7 +508,16 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum,
closure_call(&op.cl, bch2_write, NULL, &cl);
closure_sync(&cl);
- if (op.written) {
+ /*
+ * Update inode data.
+ * TODO: could possibly do asynchronously.
+ * TODO: could also possibly do atomically with the extents.
+ */
+ if (!op.error)
+ op.error = write_set_inode(c, inum, offset + size);
+
+ if (!op.error) {
+ BUG_ON(op.written == 0);
fuse_reply_write(req, (size_t) op.written << 9);
} else {
BUG_ON(!op.error);
@@ -478,6 +526,13 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum,
}
#if 0
+/*
+ * FUSE flush is essentially the close() call, however it is not guaranteed
+ * that one flush happens per open/create.
+ *
+ * It doesn't have to do anything, and is mostly relevant for NFS-style
+ * filesystems where close has some relationship to caching.
+ */
static void bcachefs_fuse_flush(fuse_req_t req, fuse_ino_t inum,
struct fuse_file_info *fi)
{