aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorMax Reitz <mreitz@redhat.com>2020-10-27 20:05:44 +0100
committerKevin Wolf <kwolf@redhat.com>2020-12-11 17:52:40 +0100
commit4fba06d5941e74169a6d33bcfd09093a49dd311f (patch)
tree0cfff0def1e32a62dbdd94a4bfb30e1b4c8b30df /block
parent41429e3d79c331503a87ec23b5da3cc1440a73fa (diff)
downloadqemu-4fba06d5941e74169a6d33bcfd09093a49dd311f.zip
qemu-4fba06d5941e74169a6d33bcfd09093a49dd311f.tar.gz
qemu-4fba06d5941e74169a6d33bcfd09093a49dd311f.tar.bz2
fuse: Allow growable exports
These will behave more like normal files in that writes beyond the EOF will automatically grow the export size. As an optimization, keep the RESIZE permission for growable exports so we do not have to take it for every post-EOF write. (This permission is not released when the export is destroyed, because at that point the BlockBackend is destroyed altogether anyway.) Signed-off-by: Max Reitz <mreitz@redhat.com> Message-Id: <20201027190600.192171-5-mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/export/fuse.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/block/export/fuse.c b/block/export/fuse.c
index d995829..92d2f50 100644
--- a/block/export/fuse.c
+++ b/block/export/fuse.c
@@ -45,6 +45,7 @@ typedef struct FuseExport {
char *mountpoint;
bool writable;
+ bool growable;
} FuseExport;
static GHashTable *exports;
@@ -72,6 +73,19 @@ static int fuse_export_create(BlockExport *blk_exp,
assert(blk_exp_args->type == BLOCK_EXPORT_TYPE_FUSE);
+ /* For growable exports, take the RESIZE permission */
+ if (args->growable) {
+ uint64_t blk_perm, blk_shared_perm;
+
+ blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm);
+
+ ret = blk_set_perm(exp->common.blk, blk_perm | BLK_PERM_RESIZE,
+ blk_shared_perm, errp);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
init_exports_table();
/*
@@ -102,6 +116,7 @@ static int fuse_export_create(BlockExport *blk_exp,
exp->mountpoint = g_strdup(args->mountpoint);
exp->writable = blk_exp_args->writable;
+ exp->growable = args->growable;
ret = setup_fuse_export(exp, args->mountpoint, errp);
if (ret < 0) {
@@ -349,19 +364,24 @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size,
truncate_flags |= BDRV_REQ_ZERO_WRITE;
}
- blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm);
+ /* Growable exports have a permanent RESIZE permission */
+ if (!exp->growable) {
+ blk_get_perm(exp->common.blk, &blk_perm, &blk_shared_perm);
- ret = blk_set_perm(exp->common.blk, blk_perm | BLK_PERM_RESIZE,
- blk_shared_perm, NULL);
- if (ret < 0) {
- return ret;
+ ret = blk_set_perm(exp->common.blk, blk_perm | BLK_PERM_RESIZE,
+ blk_shared_perm, NULL);
+ if (ret < 0) {
+ return ret;
+ }
}
ret = blk_truncate(exp->common.blk, size, true, prealloc,
truncate_flags, NULL);
- /* Must succeed, because we are only giving up the RESIZE permission */
- blk_set_perm(exp->common.blk, blk_perm, blk_shared_perm, &error_abort);
+ if (!exp->growable) {
+ /* Must succeed, because we are only giving up the RESIZE permission */
+ blk_set_perm(exp->common.blk, blk_perm, blk_shared_perm, &error_abort);
+ }
return ret;
}
@@ -482,7 +502,15 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
}
if (offset + size > length) {
- size = length - offset;
+ if (exp->growable) {
+ ret = fuse_do_truncate(exp, offset + size, true, PREALLOC_MODE_OFF);
+ if (ret < 0) {
+ fuse_reply_err(req, -ret);
+ return;
+ }
+ } else {
+ size = length - offset;
+ }
}
ret = blk_pwrite(exp->common.blk, offset, buf, size, 0);