Before commit a94a1d7699 ("fuse: Manually process requests (without
libfuse)"), the O_TRUNC flag when open()-ing an export would be
ignored. This is because libfuse sets FUSE_CAP_ATOMIC_O_TRUNC, so the
kernel lets user space handle the O_TRUNC flag, which is ignored by
the fuse code for export. After the commit, FUSE_CAP_ATOMIC_O_TRUNC is
not set anymore, so the O_TRUNC flag is handled by the kernel, which
executes a truncate.For blockdev-based exports, this causes a regression, because opening with O_TRUNC would previously work, but results in an ENOTSUP after commit a94a1d7699. For file-based exports, the fact that truncate is executed can be considered an improvement in general. However, in combination with growable=off, this still results in a practical regression in combination with virt-fw-vars, which opens its output file with O_TRUNC and previously worked with a file-based export with growable=off. After commit a94a1d7699, the file is truncated upon open and then cannot grow, meaning virt-fw-vars won't be able to write the output. To fix these regressions, while keeping the improved behavior for file-based exports with growable=on, set the FUSE_CAP_ATOMIC_O_TRUNC flag again if growable=off. Cc: [email protected] Fixes: a94a1d7699 ("fuse: Manually process requests (without libfuse)") Signed-off-by: Fiona Ebner <[email protected]> --- block/export/fuse.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/block/export/fuse.c b/block/export/fuse.c index c0e8dfb643..9ae22a2e00 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -859,6 +859,18 @@ fuse_co_init(FuseExport *exp, struct fuse_init_out *out, uint32_t supported_flags = FUSE_ASYNC_READ | FUSE_ASYNC_DIO; uint32_t flags2 = 0; + if (!exp->growable) { + /* + * Back when libfuse was used, it would always set this flag and thus + * the kernel did not execute a truncate itself and passed along O_TRUNC + * to user space. Continue setting the flag for backwards compatibility + * when the export is not growable to avoid issues with O_TRUNC, i.e. + * blockdev-based exports running into ENOTSUP and file-based exports + * with growable=off to be truncated and then stuck with size 0. + */ + supported_flags = FUSE_ATOMIC_O_TRUNC; + } + if (in->major != 7) { error_report("FUSE major version mismatch: We have 7, but kernel has %" PRIu32, in->major); -- 2.47.3
