Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 0/5] introduce btrfs filesystem property command
This patchset introduces the btrfs filesystem property command. It is the result of a discussion we had on IRC. I tried to make the properties interface as generic and extensible as possible. Comments are welcome. Currently the command looks like this: btrfs fi prop /path/to/object [name[=value]] Some people may prefer other forms. For example I got suggestions for these forms: btrfs set/get /path/to/object [name [value]] btrfs prop /pach/to/object [name[=value]] (and also without the =) I''m open to more suggestions and a discussion on this. I''m definitely for removing the fi[lesystem] prefix but I''m neutral to the other suggestions made so far. For now, I''ve implemented three properties: 1. read-only. Usable on subvolumes to toggle the read-only flags. 2. label. I looked through btrfs to find good examples of things that could be moved to the new properties interface and the filesystem label looked like a good one. There are for sure more, but that is something for later (and maybe for someone else). I would suggest to move everthing that makes sense over to the props interface and mark the old interfaces as deprecated. Comments on this are welcome. Alex. Alexander Block (5): Btrfs-progs: add BTRFS_IOC_SUBVOL_GET/SETFLAGS to ioctl.h Btrfs-progs: move skip_prefix and prefixcmp to utils.c Btrfs-progs: let get_label return the label instead of of printing it Btrfs-progs: make filesystem_cmd_group non const Btrfs-progs: introduce btrfs filesystem property command Makefile | 3 +- btrfs.c | 19 +-- btrfslabel.c | 13 +- btrfslabel.h | 4 +- cmds-filesystem.c | 115 +++++++++++++- commands.h | 9 +- help.c | 2 + ioctl.h | 2 + props.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++++ props.h | 45 ++++++ utils.c | 15 ++ utils.h | 3 + 12 files changed, 659 insertions(+), 31 deletions(-) create mode 100644 props.c create mode 100644 props.h -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 1/5] Btrfs-progs: add BTRFS_IOC_SUBVOL_GET/SETFLAGS to ioctl.h
Btrfs send/receive needs this ioctl to make a subvolume r/o after it was received. --- ioctl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ioctl.h b/ioctl.h index f2e5d8d..d6311f6 100644 --- a/ioctl.h +++ b/ioctl.h @@ -312,6 +312,8 @@ struct btrfs_ioctl_logical_ino_args { struct btrfs_ioctl_space_args) #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ struct btrfs_ioctl_vol_args_v2) +#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) +#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ struct btrfs_ioctl_scrub_args) #define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 2/5] Btrfs-progs: move skip_prefix and prefixcmp to utils.c
Needed by btrfs fi prop. Signed-off-by: Alexander Block <ablock84@googlemail.com> --- btrfs.c | 17 ++--------------- commands.h | 2 -- help.c | 2 ++ utils.c | 15 +++++++++++++++ utils.h | 3 +++ 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/btrfs.c b/btrfs.c index 88238d6..f48e483 100644 --- a/btrfs.c +++ b/btrfs.c @@ -19,7 +19,9 @@ #include <stdlib.h> #include <string.h> +#include "ctree.h" #include "commands.h" +#include "utils.h" #include "version.h" static const char * const btrfs_cmd_group_usage[] = { @@ -32,21 +34,6 @@ static const char btrfs_cmd_group_info[] char argv0_buf[ARGV0_BUF_SIZE] = "btrfs"; -static inline const char *skip_prefix(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -int prefixcmp(const char *str, const char *prefix) -{ - for (; ; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - static int parse_one_token(const char *arg, const struct cmd_group *grp, const struct cmd_struct **cmd_ret) { diff --git a/commands.h b/commands.h index a303a50..64acf17 100644 --- a/commands.h +++ b/commands.h @@ -58,8 +58,6 @@ struct cmd_group { }; /* btrfs.c */ -int prefixcmp(const char *str, const char *prefix); - int check_argc_exact(int nargs, int expected); int check_argc_min(int nargs, int expected); int check_argc_max(int nargs, int expected); diff --git a/help.c b/help.c index 6d04293..29ff3d6 100644 --- a/help.c +++ b/help.c @@ -18,7 +18,9 @@ #include <stdlib.h> #include <string.h> +#include "ctree.h" #include "commands.h" +#include "utils.h" extern char argv0_buf[ARGV0_BUF_SIZE]; diff --git a/utils.c b/utils.c index 5833030..61ae39b 100644 --- a/utils.c +++ b/utils.c @@ -1216,3 +1216,18 @@ scan_again: return 0; } +const char *skip_prefix(const char *str, const char *prefix) +{ + size_t len = strlen(prefix); + return strncmp(str, prefix, len) ? NULL : str + len; +} + +int prefixcmp(const char *str, const char *prefix) +{ + for (; ; str++, prefix++) + if (!*prefix) + return 0; + else if (*str != *prefix) + return (unsigned char)*prefix - (unsigned char)*str; +} + diff --git a/utils.h b/utils.h index c5f55e1..e6b5df8 100644 --- a/utils.h +++ b/utils.h @@ -46,4 +46,7 @@ int check_label(char *input); int get_mountpt(char *dev, char *mntpt, size_t size); int btrfs_scan_block_devices(int run_ioctl); + +const char *skip_prefix(const char *str, const char *prefix); +int prefixcmp(const char *str, const char *prefix); #endif -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 3/5] Btrfs-progs: let get_label return the label instead of of printing it
get_label prints the label at the moment. Change this so that the label is returned and printing is done by the caller. Also bail out when open_ctree failed to avoid a crash when btrfs fi label is called on a device with no btrfs on it. Signed-off-by: Alexander Block <ablock84@googlemail.com> --- btrfslabel.c | 13 ++++++++----- btrfslabel.h | 4 ++-- cmds-filesystem.c | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/btrfslabel.c b/btrfslabel.c index bf73802..59cad82 100644 --- a/btrfslabel.c +++ b/btrfslabel.c @@ -67,7 +67,7 @@ static void change_label_unmounted(char *dev, char *nLabel) close_ctree(root); } -static void get_label_unmounted(char *dev) +static int get_label_unmounted(char *dev, char **label) { struct btrfs_root *root; @@ -75,14 +75,18 @@ static void get_label_unmounted(char *dev) * and as read-only. */ root = open_ctree(dev, 0, 0); + if (!root) + return -1; - fprintf(stdout, "%s\n", root->fs_info->super_copy.label); + *label = strdup(root->fs_info->super_copy.label); /* Now we close it since we are done. */ close_ctree(root); + + return 0; } -int get_label(char *btrfs_dev) +int get_label(char *btrfs_dev, char **label) { int ret; @@ -98,8 +102,7 @@ int get_label(char *btrfs_dev) fprintf(stderr, "FATAL: the filesystem has to be unmounted\n"); return -2; } - get_label_unmounted(btrfs_dev); - return 0; + return get_label_unmounted(btrfs_dev, label); } diff --git a/btrfslabel.h b/btrfslabel.h index abf43ad..ce6765b 100644 --- a/btrfslabel.h +++ b/btrfslabel.h @@ -1,5 +1,5 @@ /* btrflabel.h */ -int get_label(char *btrfs_dev); -int set_label(char *btrfs_dev, char *nLabel); \ No newline at end of file +int get_label(char *btrfs_dev, char **label); +int set_label(char *btrfs_dev, char *nLabel); diff --git a/cmds-filesystem.c b/cmds-filesystem.c index b1457de..a8f63b3 100644 --- a/cmds-filesystem.c +++ b/cmds-filesystem.c @@ -518,13 +518,22 @@ static const char * const cmd_label_usage[] = { static int cmd_label(int argc, char **argv) { + int ret; + char *label; if (check_argc_min(argc, 2) || check_argc_max(argc, 3)) usage(cmd_label_usage); - if (argc > 2) + if (argc > 2) { return set_label(argv[1], argv[2]); - else - return get_label(argv[1]); + } else { + ret = get_label(argv[1], &label); + if (ret < 0) + return ret; + fprintf(stdout, "%s\n", label); + free(label); + return ret; + } +} } const struct cmd_group filesystem_cmd_group = { -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 4/5] Btrfs-progs: make filesystem_cmd_group non const
Make filesystem_cmd_group non const so that btrfs fi prop can generate the usage string at runtime. The commands member of struct cmd_group is also non const now. Signed-off-by: Alexander Block <ablock84@googlemail.com> --- cmds-filesystem.c | 2 +- commands.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmds-filesystem.c b/cmds-filesystem.c index a8f63b3..4c61233 100644 --- a/cmds-filesystem.c +++ b/cmds-filesystem.c @@ -536,7 +536,7 @@ static int cmd_label(int argc, char **argv) } } -const struct cmd_group filesystem_cmd_group = { +struct cmd_group filesystem_cmd_group = { filesystem_cmd_group_usage, NULL, { { "df", cmd_df, cmd_df_usage, NULL, 0 }, { "show", cmd_show, cmd_show_usage, NULL, 0 }, diff --git a/commands.h b/commands.h index 64acf17..9405806 100644 --- a/commands.h +++ b/commands.h @@ -54,7 +54,7 @@ struct cmd_group { const char * const *usagestr; const char *infostr; - const struct cmd_struct commands[]; + struct cmd_struct commands[]; }; /* btrfs.c */ @@ -81,7 +81,7 @@ void help_command_group(const struct cmd_group *grp, int argc, char **argv); int open_file_or_dir(const char *fname); extern const struct cmd_group subvolume_cmd_group; -extern const struct cmd_group filesystem_cmd_group; +extern struct cmd_group filesystem_cmd_group; extern const struct cmd_group balance_cmd_group; extern const struct cmd_group device_cmd_group; extern const struct cmd_group scrub_cmd_group; -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 21:20 UTC
[PATCH 5/5] Btrfs-progs: introduce btrfs filesystem property command
"btrfs filesystem property" is a generic interface to set/get properties on filesystem objects (inodes/subvolumes/roots/devs). This patch adds the generic framework for properties and also implements two properties. The first is the read-only property for subvolumes and the second is the label property for devices. Signed-off-by: Alexander Block <ablock84@googlemail.com> --- Makefile | 3 +- btrfs.c | 2 + cmds-filesystem.c | 98 ++++++++++++ commands.h | 3 + props.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++++ props.h | 45 ++++++ 6 files changed, 610 insertions(+), 1 deletion(-) create mode 100644 props.c create mode 100644 props.h diff --git a/Makefile b/Makefile index 9694444..3e685d9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ CFLAGS = -g -O0 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \ - volumes.o utils.o btrfs-list.o btrfslabel.o repair.o + volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \ + props.o cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-inspect.o cmds-balance.o diff --git a/btrfs.c b/btrfs.c index f48e483..20f0845 100644 --- a/btrfs.c +++ b/btrfs.c @@ -243,6 +243,8 @@ int main(int argc, char **argv) { const struct cmd_struct *cmd; + init_cmd_prop_usage(); + argc--; argv++; handle_options(&argc, &argv); diff --git a/cmds-filesystem.c b/cmds-filesystem.c index 4c61233..5b8863f 100644 --- a/cmds-filesystem.c +++ b/cmds-filesystem.c @@ -33,6 +33,7 @@ #include "commands.h" #include "btrfslabel.h" +#include "props.h" static const char * const filesystem_cmd_group_usage[] = { "btrfs filesystem [<group>] <command> [<args>]", @@ -534,6 +535,102 @@ static int cmd_label(int argc, char **argv) return ret; } } + +static const char *cmd_prop_usage_base[] = { + "btrfs filesystem property [type:]<object> [<name>[=<value>]]", + "Get or set a property of a filesystem object.", + "A filesystem object can be a the root of a filesystem, a subvolume,", + "an inode or a device. The ''type:'' can be used to explicitly specify", + "what type of object you meant. This is only needed when a property", + "could be set for more then one object type. Possible types are", + "s[ubvol], r[oot], i[node], d[evice]. If you need to specify an", + "object that itself contains a colon, use ''\\:'' to escape it.", + "Depending on your shell, you may need to use two back slashes.", + "If only the object and no name is specified, all properties for", + "this object are dumped. If you specify a name but no value, this", + "property is dumped.", + "", + "Currently supported properties:", + NULL +}; + +static const char **gen_cmd_prop_usage() +{ + const char **result; + int cnt = 0; + int i; + int len; + + for (i = 0; cmd_prop_usage_base[i]; i++) + cnt++; + for (i = 0; prop_handlers[i].desc; i++) + cnt++; + + result = malloc(sizeof(char*) * (cnt + 1)); + + cnt = 0; + for (i = 0; cmd_prop_usage_base[i]; i++) + result[cnt++] = cmd_prop_usage_base[i]; + for (i = 0; prop_handlers[i].desc; i++) { + len = snprintf(NULL, 0, "%-16s%s", + prop_handlers[i].name, prop_handlers[i].desc); + result[cnt] = malloc(len + 2); + snprintf((char*)result[cnt], len + 1, "%-16s%s", + prop_handlers[i].name, prop_handlers[i].desc); + cnt++; + } + result[cnt] = NULL; + return result; +} + +static const char **cmd_prop_usage; + +void init_cmd_prop_usage() +{ + int i; + + cmd_prop_usage = gen_cmd_prop_usage(); + for (i = 0; filesystem_cmd_group.commands[i].fn; i++) { + if (!strcmp(filesystem_cmd_group.commands[i].token, + "property")) { + filesystem_cmd_group.commands[i].usagestr + cmd_prop_usage; + break; + } + } +} + +static int cmd_prop(int argc, char **argv) +{ + int ret; + char *object; + char *name_value; + char *name; + char *value; + + if (argc != 2 && argc != 3) + usage(cmd_prop_usage); + + object = argv[1]; + name_value = argv[2]; + + if (name_value) { + value = strchr(name_value, ''=''); + if (value) { + name = strndup(name_value, value - name_value); + value++; + } else { + name = strdup(name_value); + } + } else { + name = NULL; + value = NULL; + } + + ret = handle_prop(object, name, value); + free(name); + + return ret; } struct cmd_group filesystem_cmd_group = { @@ -545,6 +642,7 @@ struct cmd_group filesystem_cmd_group = { { "balance", cmd_balance, NULL, &balance_cmd_group, 1 }, { "resize", cmd_resize, cmd_resize_usage, NULL, 0 }, { "label", cmd_label, cmd_label_usage, NULL, 0 }, + { "property", cmd_prop, NULL, NULL, 0 }, { 0, 0, 0, 0, 0 }, } }; diff --git a/commands.h b/commands.h index 9405806..07a9f9f 100644 --- a/commands.h +++ b/commands.h @@ -87,6 +87,9 @@ extern const struct cmd_group device_cmd_group; extern const struct cmd_group scrub_cmd_group; extern const struct cmd_group inspect_cmd_group; +/* cmds-filesystem.c */ +void init_cmd_prop_usage(); + int cmd_subvolume(int argc, char **argv); int cmd_filesystem(int argc, char **argv); int cmd_balance(int argc, char **argv); diff --git a/props.c b/props.c new file mode 100644 index 0000000..a428c83 --- /dev/null +++ b/props.c @@ -0,0 +1,460 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> + +#include "ctree.h" +#include "commands.h" +#include "utils.h" +#include "btrfslabel.h" +#include "props.h" + +int prop_read_only(enum prop_object_type type, + const char *object, + const char *name, + const char *value) +{ + int ret = 0; + int fd = -1; + u64 flags = 0; + + fd = open(object, O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "ERROR: open %s failed. %s\n", + object, strerror(-ret)); + goto out; + } + + ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "ERROR: failed to get flags for %s. %s\n", + object, strerror(-ret)); + goto out; + } + + if (!value) { + if (flags & BTRFS_SUBVOL_RDONLY) + fprintf(stdout, "read-only=true\n"); + else + fprintf(stdout, "read-only=false\n"); + ret = 0; + goto out; + } + + if (!strcmp(value, "true")) + flags |= BTRFS_SUBVOL_RDONLY; + else if (!strcmp(value, "false")) + flags = flags & ~BTRFS_SUBVOL_RDONLY; + else { + ret = -EINVAL; + fprintf(stderr, "ERROR: invalid value for property.\n"); + goto out; + } + + ret = ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "ERROR: failed to set flags for %s. %s\n", + object, strerror(-ret)); + goto out; + } + +out: + if (fd != -1) + close(fd); + return ret; +} + +int prop_label(enum prop_object_type type, + const char *object, + const char *name, + const char *value) +{ + int ret; + char *label = NULL; + + if (value) { + ret = set_label((char*)object, (char*)value); + } else { + ret = get_label((char*)object, &label); + if (!ret) + fprintf(stdout, "label=%s\n", label); + free(label); + } + + return ret; +} + +const struct prop_handler prop_handlers[] = { + {"read-only", "Set/get read only flag of subvolume", + 0, prop_object_subvol, prop_read_only}, + {"label", "Set/get label of filesystem", + 0, prop_object_dev, prop_label}, + {0, 0, 0, 0, 0} +}; + +static int parse_prop(const char *arg, const struct prop_handler *props, + const struct prop_handler **prop_ret) +{ + const struct prop_handler *prop = props; + const struct prop_handler *abbrev_prop = NULL; + const struct prop_handler *ambiguous_prop = NULL; + + for (; prop->name; prop++) { + const char *rest; + + rest = skip_prefix(arg, prop->name); + if (!rest) { + if (!prefixcmp(prop->name, arg)) { + if (abbrev_prop) { + /* + * If this is abbreviated, it is + * ambiguous. So when there is no + * exact match later, we need to + * error out. + */ + ambiguous_prop = abbrev_prop; + } + abbrev_prop = prop; + } + continue; + } + if (*rest) + continue; + + *prop_ret = prop; + return 0; + } + + if (ambiguous_prop) + return -2; + + if (abbrev_prop) { + *prop_ret = abbrev_prop; + return 0; + } + + return -1; +} + +static int get_fsid(const char *path, u8 *fsid) +{ + int ret; + int fd; + struct btrfs_ioctl_fs_info_args args; + + fd = open(path, O_RDONLY); + if (fd < 0) { + ret = -errno; + fprintf(stderr, "ERROR: open %s failed. %s\n", path, + strerror(-ret)); + goto out; + } + + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args); + if (ret < 0) { + ret = -errno; + goto out; + } + + memcpy(fsid, args.fsid, BTRFS_FSID_SIZE); + ret = 0; + +out: + if (fd != -1) + close(fd); + return ret; +} + +static int check_btrfs_object(const char *object) +{ + int ret; + u8 fsid[BTRFS_FSID_SIZE]; + + ret = get_fsid(object, fsid); + if (ret < 0) + ret = 0; + else + ret = 1; + return ret; +} + +static int check_is_root(const char *object) +{ + int ret; + u8 fsid[BTRFS_FSID_SIZE]; + u8 fsid2[BTRFS_FSID_SIZE]; + char *tmp; + + tmp = malloc(strlen(object) + 5); + strcpy(tmp, object); + if (tmp[strlen(tmp) - 1] != ''/'') + strcat(tmp, "/"); + strcat(tmp, ".."); + + ret = get_fsid(object, fsid); + if (ret < 0) { + fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object, + strerror(-ret)); + goto out; + } + + ret = get_fsid(tmp, fsid2); + if (ret < 0) { + ret = 0; + goto out; + } + + if (!memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) { + ret = 0; + goto out; + } + + ret = 1; + +out: + free(tmp); + return ret; +} + +static int count_bits(int v) +{ + unsigned int tmp = (unsigned int)v; + int cnt = 0; + + while (tmp) { + if (tmp & 1) + cnt++; + tmp >>= 1; + } + return cnt; +} + +static int detect_object_types(const char *object, int *types_out) +{ + int ret; + int is_btrfs_object; + int types = 0; + struct stat st; + + is_btrfs_object = check_btrfs_object(object); + + ret = lstat(object, &st); + if (ret < 0) { + ret = -errno; + goto out; + } + + if (is_btrfs_object) { + types |= prop_object_inode; + if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID) { + types |= prop_object_subvol; + } + + ret = check_is_root(object); + if (ret < 0) + goto out; + if (ret) + types |= prop_object_root; + } + + if (S_ISBLK(st.st_mode)) + types |= prop_object_dev; + + ret = 0; + *types_out = types; + +out: + return ret; +} + +static int dump_prop(const struct prop_handler *prop, + const char *object, + int types, + int type) +{ + int ret = 0; + + if ((types & type) && (prop->types & type)) + ret = prop->handler(type, object, prop->name, NULL); + return ret; +} + +int handle_prop(const char *object_in, const char *name, const char *value) +{ + int ret; + const struct prop_handler *prop = NULL; + char *buf = NULL; + char *object = NULL; + char *type = NULL; + char *tmp; + struct stat st; + int i; + int j; + int types = 0; + + if (!name) { + object = strdup(object_in); + ret = detect_object_types(object, &types); + if (ret < 0) { + fprintf(stderr, "ERROR: failed to detect object " + "type. %s\n", strerror(-ret)); + ret = 46; + goto out; + } + if (!types) { + fprintf(stderr, "ERROR: object is no device and not " + "from a btrfs filesystem.\n"); + ret = 46; + goto out; + } + for (i = 0; prop_handlers[i].name; i++) { + prop = &prop_handlers[i]; + for (j = 1; j < __prop_object_max; j <<= 1) { + ret = dump_prop(&prop_handlers[i], object, + types, j); + if (ret < 0) { + fprintf(stderr, "ERROR: failed to set/" + "get property for " + "object.\n"); + ret = 50; + goto out; + } + } + } + ret = 0; + goto out; + } + + ret = parse_prop(name, prop_handlers, &prop); + if (ret == -1) { + fprintf(stderr, "ERROR: property is unknown\n"); + ret = 40; + goto out; + } else if (ret == -2) { + fprintf(stderr, "ERROR: property is ambigious\n"); + ret = 41; + goto out; + } else if (ret) { + fprintf(stderr, "ERROR: parse_prop reported unknown error\n"); + ret = 42; + goto out; + } + + buf = strdup(object_in); + tmp = buf; + + for (i = 0; buf[i]; i++) { + if (buf[i] != '':'') + continue; + if (i == 0 || (i == 1 && buf[0] == ''\\'')) { + ret = 43; + fprintf(stderr, "ERROR: invalid object\n"); + goto out; + } + + /* escape? */ + if (tmp[i - 1] == ''\\'') { + memmove(buf + i - 1, buf + i, strlen(buf + i) + 1); + i--; + continue; + } + + if (!type) { + type = buf; + object = buf + i + 1; + buf[i] = 0; + } + } + + if (!type) + object = buf; + + if (type) { + if (!strcmp(type, "s") || !strcmp(type, "subvol")) + types = prop_object_subvol; + else if (!strcmp(type, "r") || !strcmp(type, "root")) + types = prop_object_root; + else if (!strcmp(type, "i") || !strcmp(type, "inode")) + types = prop_object_inode; + else if (!strcmp(type, "d") || !strcmp(type, "device")) + types = prop_object_dev; + else { + fprintf(stderr, "ERROR: invalid object type.\n"); + ret = 45; + goto out; + } + } else { + /* try auto detection */ + ret = detect_object_types(object, &types); + if (ret < 0) { + fprintf(stderr, "ERROR: failed to detect object type. " + "%s\n", strerror(-ret)); + ret = 46; + goto out; + } + + if (!(types & prop->types)) { + fprintf(stderr, "ERROR: object is not compatible " + "with property\n"); + ret = 47; + goto out; + } + } + + types &= prop->types; + + if (count_bits(types) > 1) { + fprintf(stderr, "ERROR: type of object is ambiguous. " + "Please specify a type by hand.\n"); + ret = 48; + goto out; + } + + if (!types) { + fprintf(stderr, "ERROR: invalid object type.\n"); + ret = 49; + goto out; + } + + if (value && prop->read_only) { + fprintf(stderr, "ERROR: %s is a read-only property.\n", + prop->name); + ret = 51; + goto out; + } + + ret = prop->handler(types, object, name, value); + + if (ret < 0) { + fprintf(stderr, "ERROR: failed to set/get property for " + "object.\n"); + ret = 50; + } else { + ret = 0; + } + +out: + free(buf); + return ret; + +} + diff --git a/props.h b/props.h new file mode 100644 index 0000000..bd497b7 --- /dev/null +++ b/props.h @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef PROPS_H_ +#define PROPS_H_ + +enum prop_object_type { + prop_object_dev = (1 << 0), + prop_object_root = (1 << 1), + prop_object_subvol = (1 << 2), + prop_object_inode = (1 << 3), + __prop_object_max, +}; + +typedef int (*prop_handler_t)(enum prop_object_type type, + const char *object, + const char *name, + const char *value); + +struct prop_handler { + const char *name; + const char *desc; + int read_only; + int types; + prop_handler_t handler; +}; + +extern const struct prop_handler prop_handlers[]; + +int handle_prop(const char *object, const char *name, const char *value); + +#endif /* PROPS_H_ */ -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-24 22:14 UTC
Re: [PATCH 4/5] Btrfs-progs: make filesystem_cmd_group non const
I''ve removed this patch in the mean time. It was needed to build the usage string for btrfs fi props at runtime but I found a solution to do this at compile time now. On Sun, Jun 24, 2012 at 11:20 PM, Alexander Block <ablock84@googlemail.com> wrote:> Make filesystem_cmd_group non const so that btrfs fi prop can > generate the usage string at runtime. The commands member of > struct cmd_group is also non const now. > > Signed-off-by: Alexander Block <ablock84@googlemail.com> > --- > cmds-filesystem.c | 2 +- > commands.h | 4 ++-- > 2 files changed, 3 insertions(+), 3 deletions(-) > > diff --git a/cmds-filesystem.c b/cmds-filesystem.c > index a8f63b3..4c61233 100644 > --- a/cmds-filesystem.c > +++ b/cmds-filesystem.c > @@ -536,7 +536,7 @@ static int cmd_label(int argc, char **argv) > } > } > > -const struct cmd_group filesystem_cmd_group = { > +struct cmd_group filesystem_cmd_group = { > filesystem_cmd_group_usage, NULL, { > { "df", cmd_df, cmd_df_usage, NULL, 0 }, > { "show", cmd_show, cmd_show_usage, NULL, 0 }, > diff --git a/commands.h b/commands.h > index 64acf17..9405806 100644 > --- a/commands.h > +++ b/commands.h > @@ -54,7 +54,7 @@ struct cmd_group { > const char * const *usagestr; > const char *infostr; > > - const struct cmd_struct commands[]; > + struct cmd_struct commands[]; > }; > > /* btrfs.c */ > @@ -81,7 +81,7 @@ void help_command_group(const struct cmd_group *grp, int argc, char **argv); > int open_file_or_dir(const char *fname); > > extern const struct cmd_group subvolume_cmd_group; > -extern const struct cmd_group filesystem_cmd_group; > +extern struct cmd_group filesystem_cmd_group; > extern const struct cmd_group balance_cmd_group; > extern const struct cmd_group device_cmd_group; > extern const struct cmd_group scrub_cmd_group; > -- > 1.7.10 >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 06/25/2012 05:20 AM, Alexander Block wrote:> This patchset introduces the btrfs filesystem property command. It is the > result of a discussion we had on IRC. I tried to make the properties > interface as generic and extensible as possible. Comments are welcome. > > Currently the command looks like this: > btrfs fi prop /path/to/object [name[=value]] > > Some people may prefer other forms. For example I got suggestions for > these forms: > btrfs set/get /path/to/object [name [value]] > btrfs prop /pach/to/object [name[=value]] (and also without the =) > > I''m open to more suggestions and a discussion on this. I''m definitely > for removing the fi[lesystem] prefix but I''m neutral to the other > suggestions made so far. > > For now, I''ve implemented three properties: > 1. read-only. Usable on subvolumes to toggle the read-only flags. > 2. label. I looked through btrfs to find good examples of things that > could be moved to the new properties interface and the filesystem > label looked like a good one. There are for sure more, but that is > something for later (and maybe for someone else). I would suggest > to move everthing that makes sense over to the props interface and > mark the old interfaces as deprecated. Comments on this are welcome. >Hi Alex, Thanks for doing these! I''m doing something similar to yours, but I prefer keeping these prefixes and making some efforts to enhance original APIs: For subvolume, right now we can have two attributes: readonly and default, and let ''btrfs sub list'' work just like ''ls'' so that we can get their attributes easier: o btrfs subvolume list [-p] path subvol (Default) snap (Readonly) o btrfs subvolume list [-p] path/subvol subvol (Default) o btrfs subvolume list [-p] path/snap snap (Readonly) how about this? thanks, liubo> Alex. > > Alexander Block (5): > Btrfs-progs: add BTRFS_IOC_SUBVOL_GET/SETFLAGS to ioctl.h > Btrfs-progs: move skip_prefix and prefixcmp to utils.c > Btrfs-progs: let get_label return the label instead of of printing it > Btrfs-progs: make filesystem_cmd_group non const > Btrfs-progs: introduce btrfs filesystem property command > > Makefile | 3 +- > btrfs.c | 19 +-- > btrfslabel.c | 13 +- > btrfslabel.h | 4 +- > cmds-filesystem.c | 115 +++++++++++++- > commands.h | 9 +- > help.c | 2 + > ioctl.h | 2 + > props.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > props.h | 45 ++++++ > utils.c | 15 ++ > utils.h | 3 + > 12 files changed, 659 insertions(+), 31 deletions(-) > create mode 100644 props.c > create mode 100644 props.h >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexander Block
2012-Jun-27 11:08 UTC
Re: [PATCH 0/5] introduce btrfs filesystem property command
On Wed, Jun 27, 2012 at 4:25 AM, Liu Bo <liubo2009@cn.fujitsu.com> wrote:> On 06/25/2012 05:20 AM, Alexander Block wrote: > >> This patchset introduces the btrfs filesystem property command. It is the >> result of a discussion we had on IRC. I tried to make the properties >> interface as generic and extensible as possible. Comments are welcome. >> >> Currently the command looks like this: >> btrfs fi prop /path/to/object [name[=value]] >> >> Some people may prefer other forms. For example I got suggestions for >> these forms: >> btrfs set/get /path/to/object [name [value]] >> btrfs prop /pach/to/object [name[=value]] (and also without the =) >> >> I''m open to more suggestions and a discussion on this. I''m definitely >> for removing the fi[lesystem] prefix but I''m neutral to the other >> suggestions made so far. >> >> For now, I''ve implemented three properties: >> 1. read-only. Usable on subvolumes to toggle the read-only flags. >> 2. label. I looked through btrfs to find good examples of things that >> could be moved to the new properties interface and the filesystem >> label looked like a good one. There are for sure more, but that is >> something for later (and maybe for someone else). I would suggest >> to move everthing that makes sense over to the props interface and >> mark the old interfaces as deprecated. Comments on this are welcome. >> > > > Hi Alex, > > Thanks for doing these! > > I''m doing something similar to yours, but I prefer keeping these prefixes and making some > efforts to enhance original APIs:I had some discussions with David and Ilya and we agreen on dropping the filesystem prefix for a filesystem prefix for a simple reason. The property command is not only for filesystems, so the prefix does not make sense here. We can later set/get properties on inodes, subvolumes, filesystems, devices and maybe more later. At the moment, the command has this form (new patchset will follow): btrfs property set [<type>:]<object> <name> <value> btrfs property get [<type>:]<object> [<name>] (no name means dump all) btrfs property list [<type>:]<object> (lists all available properties for the given object/type with a description) The type is a prefix to explicitly specify what type of object you mean. This is necessary in case the object+property combination is ambiguous. For example ''/path/to/fs/root'' could mean the root subvolume, the directory inode or the filesystem itself. Normally, btrfs-progs will try to detect the type automatically.> > For subvolume, right now we can have two attributes: readonly and default, and let ''btrfs sub list'' > work just like ''ls'' so that we can get their attributes easier: > > o btrfs subvolume list [-p] path > subvol (Default) > snap (Readonly) > > o btrfs subvolume list [-p] path/subvol > subvol (Default) > > o btrfs subvolume list [-p] path/snap > snap (Readonly) > > > how about this?This sounds like something that we should handle/discuss separately to the new property command group.> > thanks, > liubo > >> Alex. >> >> Alexander Block (5): >> Btrfs-progs: add BTRFS_IOC_SUBVOL_GET/SETFLAGS to ioctl.h >> Btrfs-progs: move skip_prefix and prefixcmp to utils.c >> Btrfs-progs: let get_label return the label instead of of printing it >> Btrfs-progs: make filesystem_cmd_group non const >> Btrfs-progs: introduce btrfs filesystem property command >> >> Makefile | 3 +- >> btrfs.c | 19 +-- >> btrfslabel.c | 13 +- >> btrfslabel.h | 4 +- >> cmds-filesystem.c | 115 +++++++++++++- >> commands.h | 9 +- >> help.c | 2 + >> ioctl.h | 2 + >> props.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++++ >> props.h | 45 ++++++ >> utils.c | 15 ++ >> utils.h | 3 + >> 12 files changed, 659 insertions(+), 31 deletions(-) >> create mode 100644 props.c >> create mode 100644 props.h >> > >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Martin Steigerwald
2012-Jun-28 13:08 UTC
Re: [PATCH 0/5] introduce btrfs filesystem property command
Am Sonntag, 24. Juni 2012 schrieb Alexander Block:> This patchset introduces the btrfs filesystem property command. It is > the result of a discussion we had on IRC. I tried to make the > properties interface as generic and extensible as possible. Comments > are welcome. > > Currently the command looks like this: > btrfs fi prop /path/to/object [name[=value]] > > Some people may prefer other forms. For example I got suggestions for > these forms: > btrfs set/get /path/to/object [name [value]] > btrfs prop /pach/to/object [name[=value]] (and also without the =) > > I''m open to more suggestions and a discussion on this. I''m definitelyI wonder about a way to find out directly 1) size of node and leaf metadata blocks 2) whether inode cache is active 3) whether space cache is active Would also be nice to be able to set this. I do not know whether this is possible re 1 during a balance for example. Re 2 and 3 it would be nice to be able to skip the mount options in /etc/fstab. AFAIK space cache is permanent anyway, but inode cache isn´t or vice versa. Either way I find the current way BTRFS handles options via mount options a bit confusion. I´d like some way to set attributes / flags permanently like in Ext4 via tune2fs or xfs_admin. Thanks, -- Martin ''Helios'' Steigerwald - http://www.Lichtvoll.de GPG: 03B0 0D6C 0040 0710 4AFA B82F 991B EAAC A599 84C7 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html