return "not started";
case BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED:
return "already started";
+ case BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS:
+ return "scrub is in progress";
default:
return "<illegal result value>";
}
int i;
int c;
int fdmnt = -1;
- int fdsrcdev = -1;
int fddstdev = -1;
char *path;
char *srcdev;
- char *dstdev;
+ char *dstdev = NULL;
int avoid_reading_from_srcdev = 0;
int force_using_targetdev = 0;
- struct stat st;
u64 dstdev_block_count;
int do_not_background = 0;
int mixed = 0;
DIR *dirstream = NULL;
- char estr[100]; /* check test_dev_for_mkfs() for error string size*/
while ((c = getopt(argc, argv, "Brf")) != -1) {
switch (c) {
/* 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, %s\n",
- path, strerror(errno),
- replace_dev_result2string(status_args.result));
+ "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;
}
}
srcdev = argv[optind];
- dstdev = argv[optind + 1];
+ 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;
srcdev, path);
goto leave_with_error;
}
- } else {
- fdsrcdev = open(srcdev, O_RDWR);
- if (fdsrcdev < 0) {
- fprintf(stderr, "Error: Unable to open device '%s'\n",
- srcdev);
- fprintf(stderr, "\tTry using the devid instead of the path\n");
- goto leave_with_error;
- }
- ret = fstat(fdsrcdev, &st);
- if (ret) {
- fprintf(stderr, "Error: Unable to stat '%s'\n", srcdev);
- goto leave_with_error;
- }
- if (!S_ISBLK(st.st_mode)) {
- fprintf(stderr, "Error: '%s' is not a block device\n",
- srcdev);
- goto leave_with_error;
- }
+ } else if (is_block_device(srcdev)) {
strncpy((char *)start_args.start.srcdev_name, srcdev,
BTRFS_DEVICE_PATH_NAME_MAX);
- close(fdsrcdev);
- fdsrcdev = -1;
start_args.start.srcdevid = 0;
}
- ret = test_dev_for_mkfs(dstdev, force_using_targetdev, estr);
- if (ret) {
- fprintf(stderr, "%s", estr);
+ ret = test_dev_for_mkfs(dstdev, force_using_targetdev);
+ if (ret)
goto leave_with_error;
- }
+
fddstdev = open(dstdev, O_RDWR);
if (fddstdev < 0) {
fprintf(stderr, "Unable to open %s\n", dstdev);
close(fddstdev);
fddstdev = -1;
+ free(dstdev);
+ dstdev = NULL;
dev_replace_handle_sigint(fdmnt);
if (!do_not_background) {
}
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, %s\n",
- path, strerror(errno),
- replace_dev_result2string(start_args.result));
+ "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;
}
return 0;
leave_with_error:
+ if (dstdev)
+ free(dstdev);
if (fdmnt != -1)
close(fdmnt);
- if (fdsrcdev != -1)
- close(fdsrcdev);
if (fddstdev != -1)
close(fddstdev);
return 1;
for (;;) {
args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS;
+ args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
if (ret) {
- fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s, %s\n",
- path, strerror(errno),
- replace_dev_result2string(args.result));
+ fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
+ path, strerror(errno));
+ if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+ fprintf(stderr, ", %s\n",
+ replace_dev_result2string(args.result));
+ else
+ fprintf(stderr, "\n");
return ret;
}
}
args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL;
+ args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
e = errno;
close_file_or_dir(fd, dirstream);
if (ret) {
- fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s, %s\n",
- path, strerror(e),
- replace_dev_result2string(args.result));
+ fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s",
+ path, strerror(e));
+ if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+ fprintf(stderr, ", %s\n",
+ replace_dev_result2string(args.result));
+ else
+ fprintf(stderr, "\n");
return 1;
}
if (args.result == BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED) {
return 0;
}
+static const char replace_cmd_group_info[] =
+"replace a device in the filesystem";
+
const struct cmd_group replace_cmd_group = {
- replace_cmd_group_usage, NULL, {
+ replace_cmd_group_usage, replace_cmd_group_info, {
{ "start", cmd_start_replace, cmd_start_replace_usage, NULL,
0 },
{ "status", cmd_status_replace, cmd_status_replace_usage, NULL,