static int cmd_rm_dev(int argc, char **argv) { char *mntpnt; int i, fdmnt, ret=0, e; DIR *dirstream = NULL; if (check_argc_min(argc, 3)) usage(cmd_rm_dev_usage); mntpnt = argv[argc - 1]; fdmnt = open_file_or_dir(mntpnt, &dirstream); if (fdmnt < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt); return 1; } for(i=1 ; i < argc - 1; i++ ){ struct btrfs_ioctl_vol_args arg; int res; if (!is_block_device(argv[i])) { fprintf(stderr, "ERROR: %s is not a block device\n", argv[i]); ret++; continue; } memset(&arg, 0, sizeof(arg)); strncpy_null(arg.name, argv[i]); res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); e = errno; if (res) { const char *msg; if (res > 0) msg = btrfs_err_str(res); else msg = strerror(e); fprintf(stderr, "ERROR: error removing the device '%s' - %s\n", argv[i], msg); ret++; } } close_file_or_dir(fdmnt, dirstream); return !!ret; }
static int _cmd_device_remove(int argc, char **argv, const char * const *usagestr) { char *mntpnt; int i, fdmnt, ret = 0; DIR *dirstream = NULL; clean_args_no_options(argc, argv, usagestr); if (check_argc_min(argc - optind, 2)) usage(usagestr); mntpnt = argv[argc - 1]; fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1); if (fdmnt < 0) return 1; for(i = optind; i < argc - 1; i++) { struct btrfs_ioctl_vol_args arg; struct btrfs_ioctl_vol_args_v2 argv2 = {0}; int is_devid = 0; int res; if (string_is_numerical(argv[i])) { argv2.devid = arg_strtou64(argv[i]); argv2.flags = BTRFS_DEVICE_SPEC_BY_ID; is_devid = 1; } else if (is_block_device(argv[i]) == 1 || strcmp(argv[i], "missing") == 0) { strncpy_null(argv2.name, argv[i]); } else { error("not a block device: %s", argv[i]); ret++; continue; } /* * Positive values are from BTRFS_ERROR_DEV_*, * otherwise it's a generic error, one of errnos */ res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2); /* * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if * argv2.flags includes a flag which kernel doesn't understand then * we shall get EOPNOTSUPP */ if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) { if (is_devid) { error("device delete by id failed: %m"); ret++; continue; } memset(&arg, 0, sizeof(arg)); strncpy_null(arg.name, argv[i]); res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); } if (res) { const char *msg; if (res > 0) msg = btrfs_err_str(res); else msg = strerror(errno); if (is_devid) { error("error removing devid %llu: %s", (unsigned long long)argv2.devid, msg); } else { error("error removing device '%s': %s", argv[i], msg); } ret++; } } close_file_or_dir(fdmnt, dirstream); return !!ret; }
static int do_balance(const char *path, struct btrfs_ioctl_balance_args *args, unsigned flags) { int fd; int ret; DIR *dirstream = NULL; fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; if (!(flags & BALANCE_START_FILTERS) && !(flags & BALANCE_START_NOWARN)) { int delay = 10; printf("WARNING:\n\n"); printf("\tFull balance without filters requested. This operation is very\n"); printf("\tintense and takes potentially very long. It is recommended to\n"); printf("\tuse the balance filters to narrow down the scope of balance.\n"); printf("\tUse 'btrfs balance start --full-balance' option to skip this\n"); printf("\twarning. The operation will start in %d seconds.\n", delay); printf("\tUse Ctrl-C to stop it.\n"); while (delay) { printf("%2d", delay--); fflush(stdout); sleep(1); } printf("\nStarting balance without any filters.\n"); } ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, args); if (ret < 0) { /* * older kernels don't have the new balance ioctl, try the * old one. But, the old one doesn't know any filters, so * don't fall back if they tried to use the fancy new things */ if (errno == ENOTTY && !(flags & BALANCE_START_FILTERS)) { ret = do_balance_v1(fd); if (ret == 0) goto out; } if (errno == ECANCELED) { if (args->state & BTRFS_BALANCE_STATE_PAUSE_REQ) fprintf(stderr, "balance paused by user\n"); if (args->state & BTRFS_BALANCE_STATE_CANCEL_REQ) fprintf(stderr, "balance canceled by user\n"); ret = 0; } else { error("error during balancing '%s': %m", path); if (errno != EINPROGRESS) fprintf(stderr, "There may be more info in syslog - try dmesg | tail\n"); ret = 1; } } else if (ret > 0) { error("balance: %s", btrfs_err_str(ret)); } else { printf("Done, had to relocate %llu out of %llu chunks\n", (unsigned long long)args->stat.completed, (unsigned long long)args->stat.considered); } out: close_file_or_dir(fd, dirstream); return ret; }