aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/export/fuse.c44
-rw-r--r--qapi/block-export.json6
2 files changed, 41 insertions, 9 deletions
diff --git a/block/export/fuse.c b/block/export/fuse.c
index d995829ab7..92d2f50bcc 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);
diff --git a/qapi/block-export.json b/qapi/block-export.json
index 430bc69f35..e819e70cac 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -129,10 +129,14 @@
# @mountpoint: Path on which to export the block device via FUSE.
# This must point to an existing regular file.
#
+# @growable: Whether writes beyond the EOF should grow the block node
+# accordingly. (default: false)
+#
# Since: 6.0
##
{ 'struct': 'BlockExportOptionsFuse',
- 'data': { 'mountpoint': 'str' },
+ 'data': { 'mountpoint': 'str',
+ '*growable': 'bool' },
'if': 'defined(CONFIG_FUSE)' }
##