Message ID | 20191026101127.36851-1-wqu@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs-progs: rescue-zero-log: Modify super block directly | expand |
On Sat, Oct 26, 2019 at 06:11:27PM +0800, Qu Wenruo wrote: > + /* > + * Log tree only exists in the primary super block, so SBREAD_DEFAULT > + * is enough. For read it should be enough to read the default one, but do you mean that 1st and 2nd copy don't have the log_root values set? They're written from the same buffer so I'd expect the contents to be the same. > + ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET, > + SBREAD_DEFAULT); > + if (ret < 0) { > + errno = -ret; > + error("failed to read super block on '%s': %m", devname); > + goto close_fd; > } > > - sb = root->fs_info->super_copy; > printf("Clearing log on %s, previous log_root %llu, level %u\n", > devname, > (unsigned long long)btrfs_super_log_root(sb), > (unsigned)btrfs_super_log_root_level(sb)); > - trans = btrfs_start_transaction(root, 1); > - BUG_ON(IS_ERR(trans)); > btrfs_set_super_log_root(sb, 0); > btrfs_set_super_log_root_level(sb, 0); > - btrfs_commit_transaction(trans, root); > - close_ctree(root); > + btrfs_csum_data(btrfs_super_csum_type(sb), (u8 *)sb + BTRFS_CSUM_SIZE, > + result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); > + memcpy(&sb->csum[0], result, BTRFS_CSUM_SIZE); > + ret = pwrite64(fd, sb, BTRFS_SUPER_INFO_SIZE, BTRFS_SUPER_INFO_OFFSET); So this only writes on the one device that's passed to the command. Previously it would update superblocks on all devices.
On 2019/11/1 下午6:52, David Sterba wrote: > On Sat, Oct 26, 2019 at 06:11:27PM +0800, Qu Wenruo wrote: >> + /* >> + * Log tree only exists in the primary super block, so SBREAD_DEFAULT >> + * is enough. > > For read it should be enough to read the default one, but do you mean > that 1st and 2nd copy don't have the log_root values set? They're > written from the same buffer so I'd expect the contents to be the same. Log tree update only happens for primary sb. The kernel code has this: btrfs_sync_log() |- ret = write_all_supers(fs_info, 1) |- write_dev_supers(max_mirrors); # max_mirrors == 1 |- for (i = 0; i < max_mirrors; i++) > >> + ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET, >> + SBREAD_DEFAULT); >> + if (ret < 0) { >> + errno = -ret; >> + error("failed to read super block on '%s': %m", devname); >> + goto close_fd; >> } >> >> - sb = root->fs_info->super_copy; >> printf("Clearing log on %s, previous log_root %llu, level %u\n", >> devname, >> (unsigned long long)btrfs_super_log_root(sb), >> (unsigned)btrfs_super_log_root_level(sb)); >> - trans = btrfs_start_transaction(root, 1); >> - BUG_ON(IS_ERR(trans)); >> btrfs_set_super_log_root(sb, 0); >> btrfs_set_super_log_root_level(sb, 0); >> - btrfs_commit_transaction(trans, root); >> - close_ctree(root); >> + btrfs_csum_data(btrfs_super_csum_type(sb), (u8 *)sb + BTRFS_CSUM_SIZE, >> + result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); >> + memcpy(&sb->csum[0], result, BTRFS_CSUM_SIZE); >> + ret = pwrite64(fd, sb, BTRFS_SUPER_INFO_SIZE, BTRFS_SUPER_INFO_OFFSET); > > So this only writes on the one device that's passed to the command. > Previously it would update superblocks on all devices. Oh, you got me. That's indeed the case. I guess we need to do the same skip_bg behavior just like kernel to handle multiple devices. Thanks, Qu
On Fri, Nov 01, 2019 at 10:56:36AM +0000, Qu WenRuo wrote: > >> + btrfs_csum_data(btrfs_super_csum_type(sb), (u8 *)sb + BTRFS_CSUM_SIZE, > >> + result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); > >> + memcpy(&sb->csum[0], result, BTRFS_CSUM_SIZE); > >> + ret = pwrite64(fd, sb, BTRFS_SUPER_INFO_SIZE, BTRFS_SUPER_INFO_OFFSET); > > > > So this only writes on the one device that's passed to the command. > > Previously it would update superblocks on all devices. > > Oh, you got me. > > That's indeed the case. I guess we need to do the same skip_bg behavior > just like kernel to handle multiple devices. In progs we can add another mode for open_ctree to open only devices, then iterate over their superblocks and update it in place.
diff --git a/cmds/rescue.c b/cmds/rescue.c index e8eab6808bc3..3e2dedf04fda 100644 --- a/cmds/rescue.c +++ b/cmds/rescue.c @@ -19,6 +19,9 @@ #include "kerncompat.h" #include <getopt.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> #include "ctree.h" #include "volumes.h" #include "transaction.h" @@ -164,10 +167,11 @@ static const char * const cmd_rescue_zero_log_usage[] = { static int cmd_rescue_zero_log(const struct cmd_struct *cmd, int argc, char **argv) { - struct btrfs_root *root; - struct btrfs_trans_handle *trans; - struct btrfs_super_block *sb; char *devname; + u8 buf[BTRFS_SUPER_INFO_SIZE]; + u8 result[BTRFS_CSUM_SIZE]; + struct btrfs_super_block *sb = (struct btrfs_super_block *)buf; + int fd; int ret; clean_args_no_options(cmd, argc, argv); @@ -187,24 +191,44 @@ static int cmd_rescue_zero_log(const struct cmd_struct *cmd, goto out; } - root = open_ctree(devname, 0, OPEN_CTREE_WRITES | OPEN_CTREE_PARTIAL); - if (!root) { - error("could not open ctree"); - return 1; + fd = open(devname, O_RDWR); + if (fd < 0) { + ret = -errno; + error("failed to open '%s': %m", devname); + goto out; + } + /* + * Log tree only exists in the primary super block, so SBREAD_DEFAULT + * is enough. + */ + ret = btrfs_read_dev_super(fd, sb, BTRFS_SUPER_INFO_OFFSET, + SBREAD_DEFAULT); + if (ret < 0) { + errno = -ret; + error("failed to read super block on '%s': %m", devname); + goto close_fd; } - sb = root->fs_info->super_copy; printf("Clearing log on %s, previous log_root %llu, level %u\n", devname, (unsigned long long)btrfs_super_log_root(sb), (unsigned)btrfs_super_log_root_level(sb)); - trans = btrfs_start_transaction(root, 1); - BUG_ON(IS_ERR(trans)); btrfs_set_super_log_root(sb, 0); btrfs_set_super_log_root_level(sb, 0); - btrfs_commit_transaction(trans, root); - close_ctree(root); + btrfs_csum_data(btrfs_super_csum_type(sb), (u8 *)sb + BTRFS_CSUM_SIZE, + result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); + memcpy(&sb->csum[0], result, BTRFS_CSUM_SIZE); + ret = pwrite64(fd, sb, BTRFS_SUPER_INFO_SIZE, BTRFS_SUPER_INFO_OFFSET); + if (ret != BTRFS_SUPER_INFO_SIZE) { + ret = -EIO; + errno = -ret; + error("failed to write super block for '%s': %m", devname); + } else { + ret = 0; + } +close_fd: + close(fd); out: return !!ret; }
For log zeroing, we only need to reset log_root and log_root_level to 0. However current zero-log still goes full open_ctree() which can be rejected easily by extent tree corruption. So this patch will change the behavior to modifying super block directly, avoid any possible rejection from open_ctree() Reported-by: Christian Pernegger <pernegger@gmail.com> Signed-off-by: Qu Wenruo <wqu@suse.com> --- cmds/rescue.c | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-)