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;
}
Example #2
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;
}
Example #4
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;
}