From patchwork Sun Apr 10 21:16:31 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hugo Mills X-Patchwork-Id: 697171 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3ALGdFf024061 for ; Sun, 10 Apr 2011 21:16:52 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758020Ab1DJVQo (ORCPT ); Sun, 10 Apr 2011 17:16:44 -0400 Received: from frost.carfax.org.uk ([212.13.194.111]:1749 "EHLO frost.carfax.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758004Ab1DJVQh (ORCPT ); Sun, 10 Apr 2011 17:16:37 -0400 Received: from ruthven.carfax.org.uk ([10.0.0.10]) by frost.carfax.org.uk with esmtp (Exim 4.69) (envelope-from ) id 1Q91zn-0005Aq-9J; Sun, 10 Apr 2011 21:16:36 +0000 Received: from [10.0.0.10] (helo=ruthven.carfax.org.uk) by ruthven.carfax.org.uk with esmtp (Exim 4.72) (envelope-from ) id 1Q91zn-0003TJ-1E; Sun, 10 Apr 2011 22:16:35 +0100 From: Hugo Mills To: chris.mason@oracle.com, linux-btrfs@vger.kernel.org Subject: [PATCH v5 5/8] Initial implementation of userspace interface for filtered balancing. Date: Sun, 10 Apr 2011 22:16:31 +0100 Message-Id: <3824e7bcaa36bcfbf5b2e91badeb53af211ccc43.1302469689.git.hugo@carfax.org.uk> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: References: In-Reply-To: References: To: linux-btrfs@vger.kernel.org X-frost.carfax.org.uk-Spam-Score: -0.0 (/) X-frost.carfax.org.uk-Spam-Report: Spam detection software, running on the system "spamd3.lon.bitfolk.com", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: It is useful to be able to balance a subset of the full filesystem. This patch implements the infrastructure for filtering block groups on different criteria when balancing the filesystem. Signed-off-by: Hugo Mills --- btrfs.c | 4 +- btrfs_cmds.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- ioctl.h | 24 ++++++++ man/btrfs.8.in | 40 +++++++++++-- 4 files changed, 225 insertions(+), 12 deletions(-) [...] Content analysis details: (-0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sun, 10 Apr 2011 21:16:52 +0000 (UTC) It is useful to be able to balance a subset of the full filesystem. This patch implements the infrastructure for filtering block groups on different criteria when balancing the filesystem. Signed-off-by: Hugo Mills --- btrfs.c | 4 +- btrfs_cmds.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- ioctl.h | 24 ++++++++ man/btrfs.8.in | 40 +++++++++++-- 4 files changed, 225 insertions(+), 12 deletions(-) diff --git a/btrfs.c b/btrfs.c index 7b42658..19b0e56 100644 --- a/btrfs.c +++ b/btrfs.c @@ -92,8 +92,8 @@ static struct Command commands[] = { "Show space usage information for a mount point\n." }, { do_balance, -1, - "filesystem balance", "[-w|--wait] \n" - "Balance the chunks across the device." + "filesystem balance", "[-w|--wait] [-f|--filter=:...] \n" + "Balance chunks across the devices. --filter=help for help on filters.\n" }, { do_balance, -1, "balance start", "[-w|--wait] \n" diff --git a/btrfs_cmds.c b/btrfs_cmds.c index fadcb4f..f0588d2 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -756,26 +756,175 @@ int do_add_volume(int nargs, char **args) const struct option balance_options[] = { { "wait", 0, NULL, 'w' }, + { "filter", 1, NULL, 'f' }, + { "count", 0, NULL, 'c' }, + { "verbose", 0, NULL, 'v' }, { NULL, 0, NULL, 0 } }; +struct filter_class_desc { + char *keyword; + char *description; + int flag; +}; + +const struct filter_class_desc filter_class[] = { + { "type", + "type=[~][,...]\n" + "\tWhere is one of:\n" + "\t\tmeta, sys, data, raid0, raid1, raid10, dup\n" + "\tPrefix a with ~ to negate the match.\n", + BTRFS_BALANCE_FILTER_CHUNK_TYPE }, + { NULL, NULL, 0 } +}; + +struct type_filter_desc { + char *keyword; + __u64 mask; + __u64 set; + __u64 unset; +}; + +#define BTRFS_BLOCK_GROUP_SINGLE \ + BTRFS_BLOCK_GROUP_RAID0 | \ + BTRFS_BLOCK_GROUP_RAID1 | \ + BTRFS_BLOCK_GROUP_RAID10 | \ + BTRFS_BLOCK_GROUP_DUP + +const struct type_filter_desc type_filters[] = { + { "data", BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_DATA, 0 }, + { "sys", BTRFS_BLOCK_GROUP_SYSTEM, BTRFS_BLOCK_GROUP_SYSTEM, 0 }, + { "meta", BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_METADATA, 0 }, + { "raid0", BTRFS_BLOCK_GROUP_RAID0, BTRFS_BLOCK_GROUP_RAID0, 0 }, + { "raid1", BTRFS_BLOCK_GROUP_RAID1, BTRFS_BLOCK_GROUP_RAID1, 0 }, + { "raid10", BTRFS_BLOCK_GROUP_RAID10, BTRFS_BLOCK_GROUP_RAID10, 0 }, + { "dup", BTRFS_BLOCK_GROUP_DUP, BTRFS_BLOCK_GROUP_DUP, 0 }, + { "single", BTRFS_BLOCK_GROUP_SINGLE, 0, BTRFS_BLOCK_GROUP_SINGLE }, + { NULL, 0, 0, 0 } +}; + +int parse_filter(struct btrfs_ioctl_balance_start *args, char *filters_string) +{ + char *this_filter_string; + char *saveptr; + + printf("(entry) %s Args: required %llx, mask %llx\n", filters_string, args->chunk_type, args->chunk_type_mask); + + /* Parse the filters string, if there is one */ + this_filter_string = strtok_r(filters_string, ":", &saveptr); + while(this_filter_string) { + char *subsave; + char *part; + char *type = strtok_r(this_filter_string, "=,", &subsave); + int class_id = -1; + + /* Work out what filter type we're looking at */ + if(strcmp(type, "help") == 0) { + while(filter_class[++class_id].keyword) { + printf("%s", filter_class[class_id].description); + } + return 1; + } + + while(filter_class[++class_id].keyword) { + if(strcmp(type, filter_class[class_id].keyword) == 0) + break; + } + if(filter_class[class_id].keyword == NULL) { + fprintf(stderr, "ERROR: Unknown filter type '%s'\n", type); + free(args); + return 14; + } + + /* Mark this filter class as being in use */ + args->flags |= filter_class[class_id].flag; + + /* Parse the arguments for this filter */ + part = strtok_r(NULL, "=,", &subsave); + + switch(filter_class[class_id].flag) { + case BTRFS_BALANCE_FILTER_CHUNK_TYPE: + while(part) { + int negated = 0; + int i = 0; + if(part[0] == '~') { + negated = 1; + part += 1; + } + while(type_filters[i].keyword) { + if(strcmp(part, type_filters[i].keyword) == 0) + break; + i += 1; + } + if(type_filters[i].keyword == NULL) { + fprintf(stderr, "ERROR: Unknown chunk type '%s'\n", part); + free(args); + return 15; + } + + args->chunk_type_mask |= type_filters[i].mask; + args->chunk_type &= ~type_filters[i].mask; + if (negated) + args->chunk_type |= type_filters[i].unset; + else + args->chunk_type |= type_filters[i].set; + + part = strtok_r(NULL, "=,", &subsave); + } + break; + } + + this_filter_string = strtok_r(NULL, ":", &saveptr); + } + + printf("(exit) %s Args: required %llx, mask %llx\n", filters_string, args->chunk_type, args->chunk_type_mask); + + return 0; +} + int do_balance(int argc, char **argv) { int fdmnt, ret=0; int background = 1; - struct btrfs_ioctl_vol_args args; + struct btrfs_ioctl_balance_start *args; char *path; int ttyfd; + int verbose = 0; + int count_only = 0; + + args = malloc(4096); + if (!args) { + fprintf(stderr, "ERROR: Not enough memory\n"); + return 13; + } + + args->flags = 0; + args->chunk_type = 0; + args->chunk_type_mask = 0; optind = 1; while(1) { - int c = getopt_long(argc, argv, "w", balance_options, NULL); + int c = getopt_long(argc, argv, "wf:", balance_options, NULL); if (c < 0) break; switch(c) { case 'w': background = 0; break; + case 'f': + ret = parse_filter(args, optarg); + if (ret != 0) { + free(args); + return ret; + } + break; + case 'c': + count_only = 1; + background = 0; + /* Counting is only sensible if we also print some output. */ + case 'v': + verbose = 1; + break; default: fprintf(stderr, "Invalid arguments for balance\n"); free(argv); @@ -783,6 +932,9 @@ int do_balance(int argc, char **argv) } } + if (background) + verbose = 0; + if(optind >= argc) { fprintf(stderr, "No filesystem path given for balance\n"); return 1; @@ -796,6 +948,9 @@ int do_balance(int argc, char **argv) return 12; } + if (count_only) + args->flags |= BTRFS_BALANCE_FILTER_COUNT_ONLY; + if (background) { int pid = fork(); if (pid == 0) { @@ -815,14 +970,20 @@ int do_balance(int argc, char **argv) } } - memset(&args, 0, sizeof(args)); - ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args); + ret = ioctl(fdmnt, BTRFS_IOC_BALANCE_FILTERED, args); + free(args); close(fdmnt); if(ret<0){ fprintf(stderr, "ERROR: balancing '%s'\n", path); return 19; } + + if (verbose) { + printf("%llu chunks considered, %llu chunks balanced\n", + args->examined, args->balanced); + } + return 0; } diff --git a/ioctl.h b/ioctl.h index 40c0b57..6488e82 100644 --- a/ioctl.h +++ b/ioctl.h @@ -137,6 +137,28 @@ struct btrfs_ioctl_balance_progress { __u32 completed; }; +/* Types of balance filter */ +#define BTRFS_BALANCE_FILTER_COUNT_ONLY 0x1 + +#define BTRFS_BALANCE_FILTER_CHUNK_TYPE 0x2 +#define BTRFS_BALANCE_FILTER_MASK 0x3 + +/* All the possible options for a filter */ +struct btrfs_ioctl_balance_start { + __u64 flags; /* Bit field indicating which fields of this struct are filled */ + + /* Output values: chunk counts */ + __u64 examined; + __u64 balanced; + + /* For FILTER_CHUNK_TYPE */ + __u64 chunk_type; /* Flag bits required */ + __u64 chunk_type_mask; /* Mask of bits to examine */ + + __u64 spare[506]; /* Make up the size of the structure to 4088 + * bytes for future expansion */ +}; + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ @@ -177,4 +199,6 @@ struct btrfs_ioctl_balance_progress { #define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 27, \ struct btrfs_ioctl_balance_progress) #define BTRFS_IOC_BALANCE_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) +#define BTRFS_IOC_BALANCE_FILTERED _IOWR(BTRFS_IOCTL_MAGIC, 29, \ + struct btrfs_ioctl_balance_start) #endif diff --git a/man/btrfs.8.in b/man/btrfs.8.in index 95e39c3..3023eb5 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -31,7 +31,7 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBdevice show\fP\fI |