int main(int argc, char **argv)
{
	int ret;

	if (argc > 1 && !strcmp(argv[1], "--help"))
		usage(cmd_inspect_tree_stats_usage);

	ret = cmd_inspect_tree_stats(argc, argv);

	btrfs_close_all_devices();

	return ret;
}
int main(int argc, char **argv)
{
	const struct cmd_struct *cmd;
	const char *bname;
	int ret;

	if ((bname = strrchr(argv[0], '/')) != NULL)
		bname++;
	else
		bname = argv[0];

	if (!strcmp(bname, "btrfsck")) {
		argv[0] = "check";
	} else {
		argc--;
		argv++;
		check_options(argc, argv);
		if (argc > 0) {
			if (!prefixcmp(argv[0], "--"))
				argv[0] += 2;
		} else {
			usage_command_group_short(&btrfs_cmd_group);
			exit(1);
		}
	}

	cmd = parse_command_token(argv[0], &btrfs_cmd_group);

	handle_help_options_next_level(cmd, argc, argv);

	crc32c_optimization_init();

	fixup_argv0(argv, cmd->token);

	ret = cmd->fn(argc, argv);

	btrfs_close_all_devices();

	exit(ret);
}
Esempio n. 3
0
int main(int ac, char **av)
{
    struct btrfs_root *root;
    struct btrfs_fs_info *info;
    struct btrfs_path path;
    struct btrfs_key key;
    struct btrfs_root_item ri;
    struct extent_buffer *leaf;
    struct btrfs_disk_key disk_key;
    struct btrfs_key found_key;
    char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
    int ret;
    int slot;
    int extent_only = 0;
    int device_only = 0;
    int uuid_tree_only = 0;
    int roots_only = 0;
    int root_backups = 0;
    u64 block_only = 0;
    struct btrfs_root *tree_root_scan;
    u64 tree_id = 0;

    radix_tree_init();

    while(1) {
        int c;
        static const struct option long_options[] = {
            { "help", no_argument, NULL, GETOPT_VAL_HELP},
            { NULL, 0, NULL, 0 }
        };

        c = getopt_long(ac, av, "deb:rRut:", long_options, NULL);
        if (c < 0)
            break;
        switch(c) {
        case 'e':
            extent_only = 1;
            break;
        case 'd':
            device_only = 1;
            break;
        case 'r':
            roots_only = 1;
            break;
        case 'u':
            uuid_tree_only = 1;
            break;
        case 'R':
            roots_only = 1;
            root_backups = 1;
            break;
        case 'b':
            block_only = arg_strtou64(optarg);
            break;
        case 't':
            tree_id = arg_strtou64(optarg);
            break;
        case GETOPT_VAL_HELP:
        default:
            print_usage(c != GETOPT_VAL_HELP);
        }
    }
    set_argv0(av);
    ac = ac - optind;
    if (check_argc_exact(ac, 1))
        print_usage(1);

    ret = check_arg_type(av[optind]);
    if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) {
        fprintf(stderr, "'%s' is not a block device or regular file\n",
                av[optind]);
        exit(1);
    }

    info = open_ctree_fs_info(av[optind], 0, 0, OPEN_CTREE_PARTIAL);
    if (!info) {
        fprintf(stderr, "unable to open %s\n", av[optind]);
        exit(1);
    }

    root = info->fs_root;
    if (!root) {
        fprintf(stderr, "unable to open %s\n", av[optind]);
        exit(1);
    }

    if (block_only) {
        leaf = read_tree_block(root,
                               block_only,
                               root->leafsize, 0);

        if (extent_buffer_uptodate(leaf) &&
                btrfs_header_level(leaf) != 0) {
            free_extent_buffer(leaf);
            leaf = NULL;
        }

        if (!leaf) {
            leaf = read_tree_block(root,
                                   block_only,
                                   root->nodesize, 0);
        }
        if (!extent_buffer_uptodate(leaf)) {
            fprintf(stderr, "failed to read %llu\n",
                    (unsigned long long)block_only);
            goto close_root;
        }
        btrfs_print_tree(root, leaf, 0);
        free_extent_buffer(leaf);
        goto close_root;
    }

    if (!(extent_only || uuid_tree_only || tree_id)) {
        if (roots_only) {
            printf("root tree: %llu level %d\n",
                   (unsigned long long)info->tree_root->node->start,
                   btrfs_header_level(info->tree_root->node));
            printf("chunk tree: %llu level %d\n",
                   (unsigned long long)info->chunk_root->node->start,
                   btrfs_header_level(info->chunk_root->node));
        } else {
            if (info->tree_root->node) {
                printf("root tree\n");
                btrfs_print_tree(info->tree_root,
                                 info->tree_root->node, 1);
            }

            if (info->chunk_root->node) {
                printf("chunk tree\n");
                btrfs_print_tree(info->chunk_root,
                                 info->chunk_root->node, 1);
            }
        }
    }
    tree_root_scan = info->tree_root;

    btrfs_init_path(&path);
again:
    if (!extent_buffer_uptodate(tree_root_scan->node))
        goto no_node;

    /*
     * Tree's that are not pointed by the tree of tree roots
     */
    if (tree_id && tree_id == BTRFS_ROOT_TREE_OBJECTID) {
        if (!info->tree_root->node) {
            error("cannot print root tree, invalid pointer");
            goto no_node;
        }
        printf("root tree\n");
        btrfs_print_tree(info->tree_root, info->tree_root->node, 1);
        goto no_node;
    }

    if (tree_id && tree_id == BTRFS_CHUNK_TREE_OBJECTID) {
        if (!info->chunk_root->node) {
            error("cannot print chunk tree, invalid pointer");
            goto no_node;
        }
        printf("chunk tree\n");
        btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1);
        goto no_node;
    }

    key.offset = 0;
    key.objectid = 0;
    btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
    ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0);
    BUG_ON(ret < 0);
    while(1) {
        leaf = path.nodes[0];
        slot = path.slots[0];
        if (slot >= btrfs_header_nritems(leaf)) {
            ret = btrfs_next_leaf(tree_root_scan, &path);
            if (ret != 0)
                break;
            leaf = path.nodes[0];
            slot = path.slots[0];
        }
        btrfs_item_key(leaf, &disk_key, path.slots[0]);
        btrfs_disk_key_to_cpu(&found_key, &disk_key);
        if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
            unsigned long offset;
            struct extent_buffer *buf;
            int skip = extent_only | device_only | uuid_tree_only;

            offset = btrfs_item_ptr_offset(leaf, slot);
            read_extent_buffer(leaf, &ri, offset, sizeof(ri));
            buf = read_tree_block(tree_root_scan,
                                  btrfs_root_bytenr(&ri),
                                  btrfs_level_size(tree_root_scan,
                                                   btrfs_root_level(&ri)),
                                  0);
            if (!extent_buffer_uptodate(buf))
                goto next;
            if (tree_id && found_key.objectid != tree_id) {
                free_extent_buffer(buf);
                goto next;
            }

            switch(found_key.objectid) {
            case BTRFS_ROOT_TREE_OBJECTID:
                if (!skip)
                    printf("root");
                break;
            case BTRFS_EXTENT_TREE_OBJECTID:
                if (!device_only && !uuid_tree_only)
                    skip = 0;
                if (!skip)
                    printf("extent");
                break;
            case BTRFS_CHUNK_TREE_OBJECTID:
                if (!skip) {
                    printf("chunk");
                }
                break;
            case BTRFS_DEV_TREE_OBJECTID:
                if (!uuid_tree_only)
                    skip = 0;
                if (!skip)
                    printf("device");
                break;
            case BTRFS_FS_TREE_OBJECTID:
                if (!skip) {
                    printf("fs");
                }
                break;
            case BTRFS_ROOT_TREE_DIR_OBJECTID:
                skip = 0;
                printf("directory");
                break;
            case BTRFS_CSUM_TREE_OBJECTID:
                if (!skip) {
                    printf("checksum");
                }
                break;
            case BTRFS_ORPHAN_OBJECTID:
                if (!skip) {
                    printf("orphan");
                }
                break;
            case BTRFS_TREE_LOG_OBJECTID:
                if (!skip) {
                    printf("log");
                }
                break;
            case BTRFS_TREE_LOG_FIXUP_OBJECTID:
                if (!skip) {
                    printf("log fixup");
                }
                break;
            case BTRFS_TREE_RELOC_OBJECTID:
                if (!skip) {
                    printf("reloc");
                }
                break;
            case BTRFS_DATA_RELOC_TREE_OBJECTID:
                if (!skip) {
                    printf("data reloc");
                }
                break;
            case BTRFS_EXTENT_CSUM_OBJECTID:
                if (!skip) {
                    printf("extent checksum");
                }
                break;
            case BTRFS_QUOTA_TREE_OBJECTID:
                if (!skip) {
                    printf("quota");
                }
                break;
            case BTRFS_UUID_TREE_OBJECTID:
                if (!extent_only && !device_only)
                    skip = 0;
                if (!skip)
                    printf("uuid");
                break;
            case BTRFS_FREE_SPACE_TREE_OBJECTID:
                if (!skip)
                    printf("free space");
                break;
            case BTRFS_MULTIPLE_OBJECTIDS:
                if (!skip) {
                    printf("multiple");
                }
                break;
            default:
                if (!skip) {
                    printf("file");
                }
            }
            if (extent_only && !skip) {
                print_extents(tree_root_scan, buf);
            } else if (!skip) {
                printf(" tree ");
                btrfs_print_key(&disk_key);
                if (roots_only) {
                    printf(" %llu level %d\n",
                           (unsigned long long)buf->start,
                           btrfs_header_level(buf));
                } else {
                    printf(" \n");
                    btrfs_print_tree(tree_root_scan, buf, 1);
                }
            }
            free_extent_buffer(buf);
        }
next:
        path.slots[0]++;
    }
no_node:
    btrfs_release_path(&path);

    if (tree_root_scan == info->tree_root &&
            info->log_root_tree) {
        tree_root_scan = info->log_root_tree;
        goto again;
    }

    if (extent_only || device_only || uuid_tree_only)
        goto close_root;

    if (root_backups)
        print_old_roots(info->super_copy);

    printf("total bytes %llu\n",
           (unsigned long long)btrfs_super_total_bytes(info->super_copy));
    printf("bytes used %llu\n",
           (unsigned long long)btrfs_super_bytes_used(info->super_copy));
    uuidbuf[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0';
    uuid_unparse(info->super_copy->fsid, uuidbuf);
    printf("uuid %s\n", uuidbuf);
    printf("%s\n", PACKAGE_STRING);
close_root:
    ret = close_ctree(root);
    btrfs_close_all_devices();
    return ret;
}
Esempio n. 4
0
int main(int argc, char *argv[])
{
	struct btrfs_root *root;
	unsigned ctree_flags = OPEN_CTREE_WRITES;
	int success = 0;
	int total = 0;
	int seeding_flag = 0;
	u64 seeding_value = 0;
	int random_fsid = 0;
	char *new_fsid_str = NULL;
	int ret;
	u64 super_flags = 0;

	while(1) {
		static const struct option long_options[] = {
			{ "help", no_argument, NULL, GETOPT_VAL_HELP},
			{ NULL, 0, NULL, 0 }
		};
		int c = getopt_long(argc, argv, "S:rxfuU:n", long_options, NULL);

		if (c < 0)
			break;
		switch(c) {
		case 'S':
			seeding_flag = 1;
			seeding_value = arg_strtou64(optarg);
			break;
		case 'r':
			super_flags |= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF;
			break;
		case 'x':
			super_flags |= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA;
			break;
		case 'n':
			super_flags |= BTRFS_FEATURE_INCOMPAT_NO_HOLES;
			break;
		case 'f':
			force = 1;
			break;
		case 'U':
			ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
			new_fsid_str = optarg;
			break;
		case 'u':
			ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
			random_fsid = 1;
			break;
		case GETOPT_VAL_HELP:
		default:
			print_usage();
			return c != GETOPT_VAL_HELP;
		}
	}

	set_argv0(argv);
	device = argv[optind];
	if (check_argc_exact(argc - optind, 1)) {
		print_usage();
		return 1;
	}

	if (random_fsid && new_fsid_str) {
		error("random fsid can't be used with specified fsid");
		return 1;
	}
	if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str)) {
		error("at least one option should be specified");
		print_usage();
		return 1;
	}

	if (new_fsid_str) {
		uuid_t tmp;

		ret = uuid_parse(new_fsid_str, tmp);
		if (ret < 0) {
			error("could not parse UUID: %s", new_fsid_str);
			return 1;
		}
		if (!test_uuid_unique(new_fsid_str)) {
			error("fsid %s is not unique", new_fsid_str);
			return 1;
		}
	}

	ret = check_mounted(device);
	if (ret < 0) {
		error("could not check mount status of %s: %s", device,
			strerror(-ret));
		return 1;
	} else if (ret) {
		error("%s is mounted", device);
		return 1;
	}

	root = open_ctree(device, 0, ctree_flags);

	if (!root) {
		error("open ctree failed");
		return 1;
	}

	if (seeding_flag) {
		if (!seeding_value && !force) {
			warning(
"this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
			ret = ask_user("We are going to clear the seeding flag, are you sure?");
			if (!ret) {
				fprintf(stderr, "Clear seeding flag canceled\n");
				ret = 1;
				goto out;
			}
		}

		ret = update_seeding_flag(root, seeding_value);
		if (!ret)
			success++;
		total++;
	}

	if (super_flags) {
		ret = set_super_incompat_flags(root, super_flags);
		if (!ret)
			success++;
		total++;
	}

	if (random_fsid || new_fsid_str) {
		if (!force) {
			warning(
	"it's highly recommended to run 'btrfs check' before this operation");
			warning(
	"also canceling running UUID change progress may cause corruption");
			ret = ask_user("We are going to change UUID, are your sure?");
			if (!ret) {
				fprintf(stderr, "UUID change canceled\n");
				ret = 1;
				goto out;
			}
		}
		ret = change_uuid(root->fs_info, new_fsid_str);
		if (!ret)
			success++;
		total++;
	}

	if (success == total) {
		ret = 0;
	} else {
		root->fs_info->readonly = 1;
		ret = 1;
		error("btrfstune failed");
	}
out:
	close_ctree(root);
	btrfs_close_all_devices();

	return ret;
}
Esempio n. 5
0
int main(int argc, char **argv)
{
	struct cache_tree root_cache;
	struct btrfs_root *root;
	char *dev;
	char *output_file = NULL;
	u64 copy = 0;
	u64 logical = 0;
	u64 bytes = 0;
	u64 cur_logical = 0;
	u64 cur_len = 0;
	int out_fd = -1;
	int found = 0;
	int ret = 0;

	while(1) {
		int c;
		static const struct option long_options[] = {
			/* { "byte-count", 1, NULL, 'b' }, */
			{ "logical", required_argument, NULL, 'l' },
			{ "copy", required_argument, NULL, 'c' },
			{ "output", required_argument, NULL, 'o' },
			{ "bytes", required_argument, NULL, 'b' },
			{ NULL, 0, NULL, 0}
		};

		c = getopt_long(argc, argv, "l:c:o:b:", long_options, NULL);
		if (c < 0)
			break;
		switch(c) {
			case 'l':
				logical = arg_strtou64(optarg);
				break;
			case 'c':
				copy = arg_strtou64(optarg);
				break;
			case 'b':
				bytes = arg_strtou64(optarg);
				break;
			case 'o':
				output_file = strdup(optarg);
				break;
			default:
				print_usage();
		}
	}
	set_argv0(argv);
	if (check_argc_min(argc - optind, 1))
		print_usage();
	if (logical == 0)
		print_usage();

	dev = argv[optind];

	radix_tree_init();
	cache_tree_init(&root_cache);

	root = open_ctree(dev, 0, 0);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		free(output_file);
		exit(1);
	}

	info_file = stdout;
	if (output_file) {
		if (strcmp(output_file, "-") == 0) {
			out_fd = 1;
			info_file = stderr;
		} else {
			out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
			if (out_fd < 0)
				goto close;
			ret = ftruncate(out_fd, 0);
			if (ret) {
				ret = 1;
				close(out_fd);
				goto close;
			}
			info_file = stdout;
		}
	}

	if (bytes == 0)
		bytes = root->nodesize;
	cur_logical = logical;
	cur_len = bytes;

	/* First find the nearest extent */
	ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 0);
	if (ret < 0) {
		fprintf(stderr, "Failed to find extent at [%llu,%llu): %s\n",
			cur_logical, cur_logical + cur_len, strerror(-ret));
		goto out_close_fd;
	}
	/*
	 * Normally, search backward should be OK, but for special case like
	 * given logical is quite small where no extents are before it,
	 * we need to search forward.
	 */
	if (ret > 0) {
		ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1);
		if (ret < 0) {
			fprintf(stderr,
				"Failed to find extent at [%llu,%llu): %s\n",
				cur_logical, cur_logical + cur_len,
				strerror(-ret));
			goto out_close_fd;
		}
		if (ret > 0) {
			fprintf(stderr,
				"Failed to find any extent at [%llu,%llu)\n",
				cur_logical, cur_logical + cur_len);
			goto out_close_fd;
		}
	}

	while (cur_logical + cur_len >= logical && cur_logical < logical +
	       bytes) {
		u64 real_logical;
		u64 real_len;

		found = 1;
		ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1);
		if (ret < 0)
			goto out_close_fd;
		if (ret > 0)
			break;
		/* check again if there is overlap. */
		if (cur_logical + cur_len < logical ||
		    cur_logical >= logical + bytes)
			break;

		real_logical = max(logical, cur_logical);
		real_len = min(logical + bytes, cur_logical + cur_len) -
			   real_logical;

		ret = print_mapping_info(root->fs_info, real_logical, real_len);
		if (ret < 0)
			goto out_close_fd;
		if (output_file && out_fd != -1) {
			ret = write_extent_content(root->fs_info, out_fd,
					real_logical, real_len, copy);
			if (ret < 0)
				goto out_close_fd;
		}

		cur_logical += cur_len;
	}

	if (!found) {
		fprintf(stderr, "No extent found at range [%llu,%llu)\n",
			logical, logical + bytes);
	}
out_close_fd:
	if (output_file && out_fd != 1)
		close(out_fd);
close:
	free(output_file);
	close_ctree(root);
	if (ret < 0)
		ret = 1;
	btrfs_close_all_devices();
	return ret;
}
Esempio n. 6
0
static int dev_replace_handle_sigint(int fd)
{
	struct sigaction sa = {
		.sa_handler = fd == -1 ? SIG_DFL : dev_replace_sigint_handler
	};

	dev_replace_cancel_fd = fd;
	return sigaction(SIGINT, &sa, NULL);
}

static const char *const cmd_replace_start_usage[] = {
	"btrfs replace start [-Bfr] <srcdev>|<devid> <targetdev> <mount_point>",
	"Replace device of a btrfs filesystem.",
	"On a live filesystem, duplicate the data to the target device which",
	"is currently stored on the source device. If the source device is not",
	"available anymore, or if the -r option is set, the data is built",
	"only using the RAID redundancy mechanisms. After completion of the",
	"operation, the source device is removed from the filesystem.",
	"If the <srcdev> is a numerical value, it is assumed to be the device id",
	"of the filesystem which is mounted at <mount_point>, otherwise it is",
	"the path to the source device. If the source device is disconnected,",
	"from the system, you have to use the <devid> parameter format.",
	"The <targetdev> needs to be same size or larger than the <srcdev>.",
	"",
	"-r     only read from <srcdev> if no other zero-defect mirror exists",
	"       (enable this if your drive has lots of read errors, the access",
	"       would be very slow)",
	"-f     force using and overwriting <targetdev> even if it looks like",
	"       containing a valid btrfs filesystem. A valid filesystem is",
	"       assumed if a btrfs superblock is found which contains a",
	"       correct checksum. Devices which are currently mounted are",
	"       never allowed to be used as the <targetdev>",
	"-B     do not background",
	NULL
};

static int cmd_replace_start(int argc, char **argv)
{
	struct btrfs_ioctl_dev_replace_args start_args = {0};
	struct btrfs_ioctl_dev_replace_args status_args = {0};
	int ret;
	int i;
	int c;
	int fdmnt = -1;
	int fddstdev = -1;
	char *path;
	char *srcdev;
	char *dstdev = NULL;
	int avoid_reading_from_srcdev = 0;
	int force_using_targetdev = 0;
	u64 dstdev_block_count;
	int do_not_background = 0;
	int mixed = 0;
	DIR *dirstream = NULL;
	u64 srcdev_size;
	u64 dstdev_size;

	while ((c = getopt(argc, argv, "Brf")) != -1) {
		switch (c) {
		case 'B':
			do_not_background = 1;
			break;
		case 'r':
			avoid_reading_from_srcdev = 1;
			break;
		case 'f':
			force_using_targetdev = 1;
			break;
		case '?':
		default:
			usage(cmd_replace_start_usage);
		}
	}

	start_args.start.cont_reading_from_srcdev_mode =
		avoid_reading_from_srcdev ?
		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID :
		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;
	if (check_argc_exact(argc - optind, 3))
		usage(cmd_replace_start_usage);
	path = argv[optind + 2];

	fdmnt = open_path_or_dev_mnt(path, &dirstream);

	if (fdmnt < 0) {
		if (errno == EINVAL)
			fprintf(stderr,
				"ERROR: '%s' is not a mounted btrfs device\n",
				path);
		else
			fprintf(stderr, "ERROR: can't access '%s': %s\n",
				path, strerror(errno));
		goto leave_with_error;
	}

	/* check for possible errors before backgrounding */
	status_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS;
	status_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
	ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &status_args);
	if (ret) {
		fprintf(stderr,
			"ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
			path, strerror(errno));
		if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
			fprintf(stderr, ", %s\n",
				replace_dev_result2string(status_args.result));
		else
			fprintf(stderr, "\n");
		goto leave_with_error;
	}

	if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
		fprintf(stderr,
			"ERROR: ioctl(DEV_REPLACE_STATUS) on \"%s\" returns error: %s\n",
			path, replace_dev_result2string(status_args.result));
		goto leave_with_error;
	}

	if (status_args.status.replace_state ==
	    BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
		fprintf(stderr,
			"ERROR: btrfs replace on \"%s\" already started!\n",
			path);
		goto leave_with_error;
	}

	srcdev = argv[optind];
	dstdev = canonicalize_path(argv[optind + 1]);
	if (!dstdev) {
		fprintf(stderr,
			"ERROR: Could not canonicalize path '%s': %s\n",
			argv[optind + 1], strerror(errno));
		goto leave_with_error;
	}

	if (is_numerical(srcdev)) {
		struct btrfs_ioctl_fs_info_args fi_args;
		struct btrfs_ioctl_dev_info_args *di_args = NULL;

		start_args.start.srcdevid = arg_strtou64(srcdev);

		ret = get_fs_info(path, &fi_args, &di_args);
		if (ret) {
			fprintf(stderr, "ERROR: getting dev info for devstats failed: "
					"%s\n", strerror(-ret));
			free(di_args);
			goto leave_with_error;
		}
		if (!fi_args.num_devices) {
			fprintf(stderr, "ERROR: no devices found\n");
			free(di_args);
			goto leave_with_error;
		}

		for (i = 0; i < fi_args.num_devices; i++)
			if (start_args.start.srcdevid == di_args[i].devid)
				break;
		srcdev_size = di_args[i].total_bytes;
		free(di_args);
		if (i == fi_args.num_devices) {
			fprintf(stderr, "Error: '%s' is not a valid devid for filesystem '%s'\n",
				srcdev, path);
			goto leave_with_error;
		}
	} else if (is_block_device(srcdev) > 0) {
		strncpy((char *)start_args.start.srcdev_name, srcdev,
			BTRFS_DEVICE_PATH_NAME_MAX);
		start_args.start.srcdevid = 0;
		srcdev_size = get_partition_size(srcdev);
	} else {
		fprintf(stderr, "ERROR: source device must be a block device or a devid\n");
		goto leave_with_error;
	}

	ret = test_dev_for_mkfs(dstdev, force_using_targetdev);
	if (ret)
		goto leave_with_error;

	dstdev_size = get_partition_size(dstdev);
	if (srcdev_size > dstdev_size) {
		fprintf(stderr, "ERROR: target device smaller than source device (required %llu bytes)\n",
			srcdev_size);
		goto leave_with_error;
	}

	fddstdev = open(dstdev, O_RDWR);
	if (fddstdev < 0) {
		fprintf(stderr, "Unable to open %s\n", dstdev);
		goto leave_with_error;
	}
	strncpy((char *)start_args.start.tgtdev_name, dstdev,
		BTRFS_DEVICE_PATH_NAME_MAX);
	ret = btrfs_prepare_device(fddstdev, dstdev, 1, &dstdev_block_count, 0,
				 &mixed, 0);
	if (ret)
		goto leave_with_error;

	close(fddstdev);
	fddstdev = -1;
	free(dstdev);
	dstdev = NULL;

	dev_replace_handle_sigint(fdmnt);
	if (!do_not_background) {
		if (daemon(0, 0) < 0) {
			fprintf(stderr, "ERROR, backgrounding failed: %s\n",
				strerror(errno));
			goto leave_with_error;
		}
	}

	start_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_START;
	start_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
	ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &start_args);
	if (do_not_background) {
		if (ret) {
			fprintf(stderr,
				"ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s",
				path, strerror(errno));
			if (start_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
				fprintf(stderr, ", %s\n",
					replace_dev_result2string(start_args.result));
			else
				fprintf(stderr, "\n");

			if (errno == EOPNOTSUPP)
				fprintf(stderr,
					"WARNING: dev_replace does not yet handle RAID5/6\n");

			goto leave_with_error;
		}

		if (start_args.result !=
		    BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
			fprintf(stderr,
				"ERROR: ioctl(DEV_REPLACE_START) on \"%s\" returns error: %s\n",
				path,
				replace_dev_result2string(start_args.result));
			goto leave_with_error;
		}
	}
	close_file_or_dir(fdmnt, dirstream);
	btrfs_close_all_devices();
	return 0;

leave_with_error:
	if (dstdev)
		free(dstdev);
	if (fdmnt != -1)
		close(fdmnt);
	if (fddstdev != -1)
		close(fddstdev);
	btrfs_close_all_devices();
	return 1;
}

static const char *const cmd_replace_status_usage[] = {
	"btrfs replace status [-1] <mount_point>",
	"Print status and progress information of a running device replace",
	"operation",
	"",
	"-1     print once instead of print continuously until the replace",
	"       operation finishes (or is canceled)",
	NULL
};

static int cmd_replace_status(int argc, char **argv)
{
	int fd;
	int e;
	int c;
	char *path;
	int once = 0;
	int ret;
	DIR *dirstream = NULL;

	while ((c = getopt(argc, argv, "1")) != -1) {
		switch (c) {
		case '1':
			once = 1;
			break;
		case '?':
		default:
			usage(cmd_replace_status_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_replace_status_usage);

	path = argv[optind];
	fd = open_file_or_dir(path, &dirstream);
	e = errno;
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
			path, strerror(e));
		return 1;
	}

	ret = print_replace_status(fd, path, once);
	close_file_or_dir(fd, dirstream);
	return !!ret;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
int main(int argc, char **argv)
{
	struct btrfs_fs_info *fs_info;
	struct btrfs_find_root_filter filter = {0};
	struct cache_tree result;
	struct cache_extent *found;
	int ret;

	/* Default to search root tree */
	filter.objectid = BTRFS_ROOT_TREE_OBJECTID;
	filter.match_gen = (u64)-1;
	filter.match_level = (u8)-1;
	while (1) {
		static const struct option long_options[] = {
			{ "help", no_argument, NULL, GETOPT_VAL_HELP},
			{ NULL, 0, NULL, 0 }
		};
		int c = getopt_long(argc, argv, "al:o:g:", long_options, NULL);

		if (c < 0)
			break;

		switch (c) {
		case 'a':
			filter.search_all = 1;
			break;
		case 'o':
			filter.objectid = arg_strtou64(optarg);
			break;
		case 'g':
			filter.generation = arg_strtou64(optarg);
			break;
		case 'l':
			filter.level = arg_strtou64(optarg);
			break;
		case GETOPT_VAL_HELP:
		default:
			find_root_usage();
			exit(c != GETOPT_VAL_HELP);
		}
	}

	set_argv0(argv);
	if (check_argc_min(argc - optind, 1)) {
		find_root_usage();
		exit(1);
	}

	fs_info = open_ctree_fs_info(argv[optind], 0, 0, 0,
			OPEN_CTREE_CHUNK_ROOT_ONLY |
			OPEN_CTREE_IGNORE_CHUNK_TREE_ERROR);
	if (!fs_info) {
		error("open ctree failed");
		exit(1);
	}
	cache_tree_init(&result);

	get_root_gen_and_level(filter.objectid, fs_info,
			       &filter.match_gen, &filter.match_level);
	ret = btrfs_find_root_search(fs_info, &filter, &result, &found);
	if (ret < 0) {
		fprintf(stderr, "Fail to search the tree root: %s\n",
			strerror(-ret));
		goto out;
	}
	if (ret > 0) {
		printf("Found tree root at %llu gen %llu level %u\n",
		       found->start, filter.match_gen, filter.match_level);
		ret = 0;
	}
	print_find_root_result(&result, &filter);
out:
	btrfs_find_root_free(&result);
	close_ctree_fs_info(fs_info);
	btrfs_close_all_devices();
	return ret;
}