From b4382217f18a27be16f9a960ac3b1327c87297e7 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 9 Dec 2010 16:36:29 -0500 Subject: Btrfs-progs: add a btrfs-select-super command to overwrite the super Btrfs stores multiple copies of the superblock, and for common power-failure crashes where barriers were not in use, one of the super copies is often valid while the first copy is not. This adds a btrfs-select-super -s N /dev/xxx command, which can overwrite all the super blocks with a copy that you have already determined is valid with btrfsck -s Signed-off-by: Chris Mason --- Makefile | 3 ++ btrfs-select-super.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ disk-io.c | 2 +- disk-io.h | 1 + 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 btrfs-select-super.c diff --git a/Makefile b/Makefile index 6e6f6c68..d65f6a22 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,9 @@ btrfs-debug-tree: $(objects) debug-tree.o btrfs-zero-log: $(objects) btrfs-zero-log.o gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS) +btrfs-select-super: $(objects) btrfs-select-super.o + gcc $(CFLAGS) -o btrfs-select-super $(objects) btrfs-select-super.o $(LDFLAGS) $(LIBS) + btrfstune: $(objects) btrfstune.o gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS) diff --git a/btrfs-select-super.c b/btrfs-select-super.c new file mode 100644 index 00000000..f12f36ce --- /dev/null +++ b/btrfs-select-super.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2007 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#define _XOPEN_SOURCE 500 +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include "kerncompat.h" +#include "ctree.h" +#include "disk-io.h" +#include "print-tree.h" +#include "transaction.h" +#include "list.h" +#include "version.h" +#include "utils.h" + +static void print_usage(void) +{ + fprintf(stderr, "usage: btrfs-select-super -s number dev\n"); + fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); + exit(1); +} + +int main(int ac, char **av) +{ + struct btrfs_root *root; + int ret; + int num; + u64 bytenr = 0; + + while(1) { + int c; + c = getopt(ac, av, "s:"); + if (c < 0) + break; + switch(c) { + case 's': + num = atol(optarg); + bytenr = btrfs_sb_offset(num); + printf("using SB copy %d, bytenr %llu\n", num, + (unsigned long long)bytenr); + break; + default: + print_usage(); + } + } + ac = ac - optind; + + if (ac != 1) + print_usage(); + + if (bytenr == 0) { + fprintf(stderr, "Please select the super copy with -s\n"); + print_usage(); + } + + radix_tree_init(); + + if((ret = check_mounted(av[optind])) < 0) { + fprintf(stderr, "Could not check mount status: %s\n", strerror(ret)); + return ret; + } else if(ret) { + fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]); + return -EBUSY; + } + + root = open_ctree(av[optind], bytenr, 1); + + if (root == NULL) + return 1; + + /* make the super writing code think we've read the first super */ + root->fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET; + ret = write_all_supers(root); + + /* we don't close the ctree or anything, because we don't want a real + * transaction commit. We just want the super copy we pulled off the + * disk to overwrite all the other copies + */ + return ret; +} diff --git a/disk-io.c b/disk-io.c index fef3edab..f4368f3d 100644 --- a/disk-io.c +++ b/disk-io.c @@ -829,7 +829,7 @@ int write_dev_supers(struct btrfs_root *root, struct btrfs_super_block *sb, if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) { btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr); - +printk("speiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n"); crc = ~(u32)0; crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); diff --git a/disk-io.h b/disk-io.h index 49e5692c..7ebec24e 100644 --- a/disk-io.h +++ b/disk-io.h @@ -47,6 +47,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes); struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes); int close_ctree(struct btrfs_root *root); +int write_all_supers(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr); -- cgit v1.2.3