int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, u64 max_block_count, int *mixed, int nodiscard) { u64 block_count; u64 bytenr; struct stat st; int i, ret; ret = fstat(fd, &st); if (ret < 0) { fprintf(stderr, "unable to stat %s\n", file); exit(1); } block_count = btrfs_device_size(fd, &st); if (block_count == 0) { fprintf(stderr, "unable to find %s size\n", file); exit(1); } if (max_block_count) block_count = min(block_count, max_block_count); zero_end = 1; if (block_count < 1024 * 1024 * 1024 && !(*mixed)) { printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); *mixed = 1; } if (!nodiscard) { /* * We intentionally ignore errors from the discard ioctl. It is * not necessary for the mkfs functionality but just an optimization. */ discard_blocks(fd, 0, block_count); } ret = zero_dev_start(fd); if (ret) { fprintf(stderr, "failed to zero device start %d\n", ret); exit(1); } for (i = 0 ; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); if (bytenr >= block_count) break; zero_blocks(fd, bytenr, BTRFS_SUPER_INFO_SIZE); } if (zero_end) { ret = zero_dev_end(fd, block_count); if (ret) { fprintf(stderr, "failed to zero device end %d\n", ret); exit(1); } } *block_count_ret = block_count; return 0; }
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr) { u8 fsid[BTRFS_FSID_SIZE]; int fsid_is_initialized = 0; struct btrfs_super_block buf; int i; int ret; u64 transid = 0; u64 bytenr; if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) { ret = pread64(fd, &buf, sizeof(buf), sb_bytenr); if (ret < sizeof(buf)) return -1; if (btrfs_super_bytenr(&buf) != sb_bytenr || buf.magic != cpu_to_le64(BTRFS_MAGIC)) return -1; memcpy(sb, &buf, sizeof(*sb)); return 0; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); ret = pread64(fd, &buf, sizeof(buf), bytenr); if (ret < sizeof(buf)) break; if (btrfs_super_bytenr(&buf) != bytenr ) continue; /* if magic is NULL, the device was removed */ if (buf.magic == 0 && i == 0) return -1; if (buf.magic != cpu_to_le64(BTRFS_MAGIC)) continue; if (!fsid_is_initialized) { memcpy(fsid, buf.fsid, sizeof(fsid)); fsid_is_initialized = 1; } else if (memcmp(fsid, buf.fsid, sizeof(fsid))) { /* * the superblocks (the original one and * its backups) contain data of different * filesystems -> the super cannot be trusted */ continue; } if (btrfs_super_generation(&buf) > transid) { memcpy(sb, &buf, sizeof(*sb)); transid = btrfs_super_generation(&buf); } } return transid > 0 ? 0 : -1; }
int write_dev_supers(struct btrfs_root *root, struct btrfs_super_block *sb, struct btrfs_device *device) { u64 bytenr; u32 crc; int i, ret; if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) { btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr); crc = ~(u32)0; crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, (char *)&sb->csum[0]); /* * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is * zero filled, we can use it directly */ ret = pwrite64(device->fd, root->fs_info->super_copy, BTRFS_SUPER_INFO_SIZE, root->fs_info->super_bytenr); BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); return 0; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes) break; btrfs_set_super_bytenr(sb, bytenr); crc = ~(u32)0; crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, (char *)&sb->csum[0]); /* * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is * zero filled, we can use it directly */ ret = pwrite64(device->fd, root->fs_info->super_copy, BTRFS_SUPER_INFO_SIZE, bytenr); BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); } return 0; }
int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) { u64 block_count; u64 bytenr; struct stat st; int i, ret; ret = fstat(fd, &st); if (ret < 0) { fprintf(stderr, "unable to stat %s\n", file); exit(1); } block_count = device_size(fd, &st); if (block_count == 0) { fprintf(stderr, "unable to find %s size\n", file); exit(1); } zero_end = 1; if (block_count < 256 * 1024 * 1024) { fprintf(stderr, "device %s is too small " "(must be at least 256 MB)\n", file); exit(1); } ret = zero_dev_start(fd); if (ret) { fprintf(stderr, "failed to zero device start %d\n", ret); exit(1); } for (i = 0 ; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); if (bytenr >= block_count) break; zero_blocks(fd, bytenr, BTRFS_SUPER_INFO_SIZE); } if (zero_end) { ret = zero_dev_end(fd, block_count); if (ret) { fprintf(stderr, "failed to zero device end %d\n", ret); exit(1); } } *block_count_ret = block_count; return 0; }
static int hole_includes_sb_mirror(const u64 start, const u64 end) { int i; int ret = 0; for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { u64 bytenr = btrfs_sb_offset(i); if (bytenr >= start && bytenr <= end) { ret = 1; break; } } return ret; }
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr) { u8 fsid[BTRFS_FSID_SIZE]; struct btrfs_super_block buf; int i; int ret; u64 transid = 0; u64 bytenr; if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) { ret = pread64(fd, &buf, sizeof(buf), sb_bytenr); if (ret < sizeof(buf)) return -1; if (btrfs_super_bytenr(&buf) != sb_bytenr || strncmp((char *)(&buf.magic), BTRFS_MAGIC, sizeof(buf.magic))) return -1; memcpy(sb, &buf, sizeof(*sb)); return 0; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); ret = pread64(fd, &buf, sizeof(buf), bytenr); if (ret < sizeof(buf)) break; if (btrfs_super_bytenr(&buf) != bytenr || strncmp((char *)(&buf.magic), BTRFS_MAGIC, sizeof(buf.magic))) continue; if (i == 0) memcpy(fsid, buf.fsid, sizeof(fsid)); else if (memcmp(fsid, buf.fsid, sizeof(fsid))) continue; if (btrfs_super_generation(&buf) > transid) { memcpy(sb, &buf, sizeof(*sb)); transid = btrfs_super_generation(&buf); } } return transid > 0 ? 0 : -1; }
int main(int argc, char **argv) { int opt; int all = 0; int full = 0; int force = 0; char *filename; int fd = -1; int i; u64 arg; u64 sb_bytenr = btrfs_sb_offset(0); while ((opt = getopt(argc, argv, "fFai:s:")) != -1) { switch (opt) { case 'i': arg = arg_strtou64(optarg); if (arg >= BTRFS_SUPER_MIRROR_MAX) { fprintf(stderr, "Illegal super_mirror %llu\n", arg); print_usage(); exit(1); } sb_bytenr = btrfs_sb_offset(arg); break; case 'a': all = 1; break; case 'f': full = 1; break; case 'F': force = 1; break; case 's': sb_bytenr = arg_strtou64(optarg); all = 0; break; default: print_usage(); exit(1); } } set_argv0(argv); if (check_argc_min(argc - optind, 1)) { print_usage(); exit(1); } for (i = optind; i < argc; i++) { filename = argv[i]; fd = open(filename, O_RDONLY, 0666); if (fd < 0) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } if (all) { int idx; for (idx = 0; idx < BTRFS_SUPER_MIRROR_MAX; idx++) { sb_bytenr = btrfs_sb_offset(idx); if (load_and_dump_sb(filename, fd, sb_bytenr, full, force)) { close(fd); exit(1); } putchar('\n'); } } else { load_and_dump_sb(filename, fd, sb_bytenr, full, force); putchar('\n'); } close(fd); } exit(0); }
int cmd_inspect_dump_super(int argc, char **argv) { int all = 0; int full = 0; int force = 0; char *filename; int fd = -1; int i; int ret = 0; u64 arg; u64 sb_bytenr = btrfs_sb_offset(0); while (1) { int c; enum { GETOPT_VAL_BYTENR = 257 }; static const struct option long_options[] = { {"all", no_argument, NULL, 'a'}, {"bytenr", required_argument, NULL, GETOPT_VAL_BYTENR }, {"full", no_argument, NULL, 'f'}, {"force", no_argument, NULL, 'F'}, {"super", required_argument, NULL, 's' }, {NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "fFai:s:", long_options, NULL); if (c < 0) break; switch (c) { case 'i': warning( "option -i is deprecated, please use -s or --super"); arg = arg_strtou64(optarg); if (arg >= BTRFS_SUPER_MIRROR_MAX) { error("super mirror too big: %llu >= %d", arg, BTRFS_SUPER_MIRROR_MAX); return 1; } sb_bytenr = btrfs_sb_offset(arg); break; case 'a': all = 1; break; case 'f': full = 1; break; case 'F': force = 1; break; case 's': arg = arg_strtou64(optarg); if (BTRFS_SUPER_MIRROR_MAX <= arg) { warning( "deprecated use of -s <bytenr> with %llu, assuming --bytenr", (unsigned long long)arg); sb_bytenr = arg; } else { sb_bytenr = btrfs_sb_offset(arg); } all = 0; break; case GETOPT_VAL_BYTENR: arg = arg_strtou64(optarg); sb_bytenr = arg; all = 0; break; default: usage_unknown_option(cmd_inspect_dump_super_usage, argv); } } if (check_argc_min(argc - optind, 1)) return 1; for (i = optind; i < argc; i++) { filename = argv[i]; fd = open(filename, O_RDONLY); if (fd < 0) { error("cannot open %s: %m", filename); ret = 1; goto out; } if (all) { int idx; for (idx = 0; idx < BTRFS_SUPER_MIRROR_MAX; idx++) { sb_bytenr = btrfs_sb_offset(idx); if (load_and_dump_sb(filename, fd, sb_bytenr, full, force)) { close(fd); ret = 1; goto out; } putchar('\n'); } } else { load_and_dump_sb(filename, fd, sb_bytenr, full, force); putchar('\n'); } close(fd); } out: return ret; }
int main(int ac, char **av) { struct btrfs_root *root; int ret; u64 num = 0; u64 bytenr = 0; while(1) { int c; c = getopt(ac, av, "s:"); if (c < 0) break; switch(c) { case 's': num = arg_strtou64(optarg); if (num >= BTRFS_SUPER_MIRROR_MAX) { fprintf(stderr, "ERROR: super mirror should be less than: %d\n", BTRFS_SUPER_MIRROR_MAX); exit(1); } bytenr = btrfs_sb_offset(((int)num)); break; default: print_usage(); } } set_argv0(av); ac = ac - optind; if (check_argc_exact(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) { fprintf(stderr, "Open ctree failed\n"); 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 */ printf("using SB copy %llu, bytenr %llu\n", (unsigned long long)num, (unsigned long long)bytenr); close_ctree(root); btrfs_close_all_devices(); return ret; }