static int _cmd_qgroup_create(int create, int argc, char **argv) { int ret = 0; int fd; int e; char *path; struct btrfs_ioctl_qgroup_create_args args; DIR *dirstream = NULL; if (check_argc_exact(argc - optind, 2)) return -1; memset(&args, 0, sizeof(args)); args.create = create; args.qgroupid = parse_qgroupid(argv[optind]); path = argv[optind + 1]; fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) { error("unable to %s quota group: %s", create ? "create":"destroy", strerror(e)); return 1; } return 0; }
static int qgroup_create(int create, int argc, char **argv) { int ret = 0; int fd; int e; char *path = argv[2]; struct btrfs_ioctl_qgroup_create_args args; DIR *dirstream = NULL; if (check_argc_exact(argc, 3)) return -1; memset(&args, 0, sizeof(args)); args.create = create; args.qgroupid = parse_qgroupid(argv[1]); fd = open_file_or_dir(path, &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", path); return 1; } ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) { fprintf(stderr, "ERROR: unable to %s quota group: %s\n", create ? "create":"destroy", strerror(e)); return 1; } return 0; }
int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg, int type) { int ret; u64 qgroup_src; u64 qgroup_dst; char *p; int pos = 0; p = strchr(arg, ':'); if (!p) { bad: fprintf(stderr, "ERROR: bad copy specification\n"); return 12; } *p = 0; qgroup_src = parse_qgroupid(arg); qgroup_dst = parse_qgroupid(p + 1); *p = ':'; if (!qgroup_src || !qgroup_dst) goto bad; if (*inherit) pos = (*inherit)->num_qgroups + (*inherit)->num_ref_copies * 2 * type; ret = qgroup_inherit_realloc(inherit, 2, pos); if (ret) return ret; (*inherit)->qgroups[pos++] = qgroup_src; (*inherit)->qgroups[pos++] = qgroup_dst; if (!type) ++(*inherit)->num_ref_copies; else ++(*inherit)->num_excl_copies; return 0; }
static int qgroup_assign(int assign, int argc, char **argv) { int ret = 0; int fd; int e; char *path = argv[3]; struct btrfs_ioctl_qgroup_assign_args args; DIR *dirstream = NULL; if (check_argc_exact(argc, 4)) return -1; memset(&args, 0, sizeof(args)); args.assign = assign; args.src = parse_qgroupid(argv[1]); args.dst = parse_qgroupid(argv[2]); /* * FIXME src should accept subvol path */ if (btrfs_qgroup_level(args.src) >= btrfs_qgroup_level(args.dst)) { fprintf(stderr, "ERROR: bad relation requested '%s'\n", path); return 1; } fd = open_file_or_dir(path, &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", path); return 1; } ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) { fprintf(stderr, "ERROR: unable to assign quota group: %s\n", strerror(e)); return 1; } return 0; }
int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg) { int ret; u64 qgroupid = parse_qgroupid(arg); int pos = 0; if (qgroupid == 0) { fprintf(stderr, "ERROR: bad qgroup specification\n"); return 12; } if (*inherit) pos = (*inherit)->num_qgroups; ret = qgroup_inherit_realloc(inherit, 1, pos); if (ret) return ret; (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid; return 0; }
static int cmd_qgroup_limit(int argc, char **argv) { int ret = 0; int fd; int e; char *path = NULL; struct btrfs_ioctl_qgroup_limit_args args; unsigned long long size; int compressed = 0; int exclusive = 0; DIR *dirstream = NULL; optind = 1; while (1) { int c = getopt(argc, argv, "ce"); if (c < 0) break; switch (c) { case 'c': compressed = 1; break; case 'e': exclusive = 1; break; default: usage(cmd_qgroup_limit_usage); } } if (check_argc_min(argc - optind, 2)) usage(cmd_qgroup_limit_usage); if (!parse_limit(argv[optind], &size)) { error("invalid size argument: %s", argv[optind]); return 1; } memset(&args, 0, sizeof(args)); if (compressed) args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR | BTRFS_QGROUP_LIMIT_EXCL_CMPR; if (exclusive) { args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL; args.lim.max_exclusive = size; } else { args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER; args.lim.max_referenced = size; } if (argc - optind == 2) { args.qgroupid = 0; path = argv[optind + 1]; ret = test_issubvolume(path); if (ret < 0) { error("cannot access '%s': %s", path, strerror(-ret)); return 1; } if (!ret) { error("'%s' is not a subvolume", path); return 1; } /* * keep qgroupid at 0, this indicates that the subvolume the * fd refers to is to be limited */ } else if (argc - optind == 3) { args.qgroupid = parse_qgroupid(argv[optind + 1]); path = argv[optind + 2]; } else usage(cmd_qgroup_limit_usage); fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args); e = errno; close_file_or_dir(fd, dirstream); if (ret < 0) { error("unable to limit requested quota group: %s", strerror(e)); return 1; } return 0; }
static int _cmd_qgroup_assign(int assign, int argc, char **argv, const char * const *usage_str) { int ret = 0; int fd; int rescan = 0; char *path; struct btrfs_ioctl_qgroup_assign_args args; DIR *dirstream = NULL; if (assign) { while (1) { enum { GETOPT_VAL_RESCAN = 256, GETOPT_VAL_NO_RESCAN }; static const struct option long_options[] = { { "rescan", no_argument, NULL, GETOPT_VAL_RESCAN }, { "no-rescan", no_argument, NULL, GETOPT_VAL_NO_RESCAN }, { NULL, 0, NULL, 0 } }; int c = getopt_long(argc, argv, "", long_options, NULL); if (c < 0) break; switch (c) { case GETOPT_VAL_RESCAN: rescan = 1; break; case GETOPT_VAL_NO_RESCAN: rescan = 0; break; default: /* Usage printed by the caller */ return -1; } } } else { clean_args_no_options(argc, argv, usage_str); } if (check_argc_exact(argc - optind, 3)) usage(usage_str); memset(&args, 0, sizeof(args)); args.assign = assign; args.src = parse_qgroupid(argv[optind]); args.dst = parse_qgroupid(argv[optind + 1]); path = argv[optind + 2]; /* * FIXME src should accept subvol path */ if (btrfs_qgroup_level(args.src) >= btrfs_qgroup_level(args.dst)) { error("bad relation requested: %s", path); return 1; } fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args); if (ret < 0) { error("unable to assign quota group: %s", strerror(errno)); close_file_or_dir(fd, dirstream); return 1; } /* * If ret > 0, it means assign caused qgroup data inconsistent state. * Schedule a quota rescan if requested. * * The return value change only happens in newer kernel. But will not * cause problem since old kernel has a bug that will never clear * INCONSISTENT bit. */ if (ret > 0) { if (rescan) { struct btrfs_ioctl_quota_rescan_args qargs; printf("Quota data changed, rescan scheduled\n"); memset(&qargs, 0, sizeof(qargs)); ret = ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &qargs); if (ret < 0) error("quota rescan failed: %s", strerror(errno)); } else { warning("quotas may be inconsistent, rescan needed"); } } close_file_or_dir(fd, dirstream); return ret; }