From f2cb11368c8459fc2041b015f1655612e8da0b3f Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 26 Mar 2024 10:52:44 +1030 Subject: [PATCH] btrfs-progs: tune: properly open zoned devices for RW [BUG] There is a report that, for zoned devices btrfstune is unable to convert it to block group tree. # btrfstune /dev/nullb0 --convert-to-block-group-tree Error reading 1342193664, -1 Error reading 1342193664, -1 ERROR: cannot read chunk root ERROR: open ctree failed [CAUSE] For read-write opened zoned devices, all the read/write has to be aligned to its sector size. However btrfs stores its metadata by extent_buffer::data[], which has all the structures before it, thus never aligned to zoned device sector size. Normally we would require btrfs_pread() and btrfs_pwrite() to do the extra alignment, but during open_ctree(), we are not aware if a device is zoned or not. Thus we rely on if the fd is opened with O_DIRECT flag, if the fd has O_DIRECT, then we would temporarily set fs_info->zoned for chunk tree read. Unforunately not all open_ctree_fd() callers have the flags set properly, and btrfstune is one of the missing call site. This makes all the read not properly aligned and cause read failure. [FIX] Just manually check if the target device is a zoned one, and set O_DIRECT accordingly. Issue: #765 Reviewed-by: Johannes Thumshirn Reviewed-by: Naohiro Aota Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- tune/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tune/main.c b/tune/main.c index aa9f39d987..397549837c 100644 --- a/tune/main.c +++ b/tune/main.c @@ -29,6 +29,7 @@ #include "kernel-shared/transaction.h" #include "kernel-shared/volumes.h" #include "kernel-shared/free-space-tree.h" +#include "kernel-shared/zoned.h" #include "common/utils.h" #include "common/open-utils.h" #include "common/device-scan.h" @@ -193,6 +194,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) u64 super_flags = 0; int quota = 0; int fd = -1; + int oflags = O_RDWR; btrfs_config_init(); @@ -336,7 +338,9 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) } } - fd = open(device, O_RDWR); + if (zoned_model(device) == ZONED_HOST_MANAGED) + oflags |= O_DIRECT; + fd = open(device, oflags); if (fd < 0) { error("mount check: cannot open %s: %m", device); ret = 1;