Jeff Mahoney
2013-Sep-10 04:24 UTC
[patch 0/7] btrfs: Add ability to query/modify feature bits while mounted
The first patch of this series is the ioctl patch I posted before, with the review comments handled. The rest of the series is enabling sysfs access to feature bits, similar to how ext4 publishes that information. Since we already have the online changing ability via the ioctl patch, we can also enable that via sysfs as well. /sys/fs/btrfs/features/ contains attributes for supported features, with the content indicating if the attribute is settable or clearable while mounted. /sys/fs/btrfs/<fsid>/features/ contains the attributes enabled on the file system plus attributes for features that can be changed online. The content indicates whether the feature is currently enabled. The permissions of the file also indicate whether it''s changeable while online. I''ll post updated tools patches separately. -Jeff -- 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
Jeff Mahoney
2013-Sep-10 04:24 UTC
[patch 1/7] [PATCH] btrfs: add ability to query/change feature bits online
There are some feature bits that require no offline setup and can be enabled online. I''ve only reviewed extended irefs, but there will probably be more. We introduce three new ioctls: - BTRFS_IOC_GET_SUPPORTED_FEATURES: query the kernel for supported features. - BTRFS_IOC_GET_FEATURES: query the kernel for enabled features on a per-fs basis, as well as querying for which features are changeable with mounted. - BTRFS_IOC_SET_FEATURES: change features on a per-fs basis. We introduce two new masks per feature set (_SAFE_SET and _SAFE_CLEAR) that allow us to define which features are safe to change at runtime. The failure modes for BTRFS_IOC_SET_FEATURES are as follows: - Enabling a completely unsupported feature: warns and returns -ENOTSUPP - Enabling a feature that can only be done offline: warns and returns -EPERM Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ctree.h | 9 ++ fs/btrfs/ioctl.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 12 +++ 3 files changed, 166 insertions(+) --- a/fs/btrfs/ctree.h 2013-09-09 17:49:10.808003254 -0400 +++ b/fs/btrfs/ctree.h 2013-09-10 00:07:58.415119201 -0400 @@ -512,7 +512,12 @@ struct btrfs_super_block { #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) #define BTRFS_FEATURE_COMPAT_SUPP 0ULL +#define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL +#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL +#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL +#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL + #define BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ @@ -523,6 +528,10 @@ struct btrfs_super_block { BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA) +#define BTRFS_FEATURE_INCOMPAT_SAFE_SET \ + (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) +#define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL + /* * A leaf is full of items. offset and size tell us where to find * the item in the leaf (relative to the start of the data area) --- a/fs/btrfs/ioctl.c 2013-09-09 17:49:10.808003254 -0400 +++ b/fs/btrfs/ioctl.c 2013-09-10 00:08:10.514945219 -0400 @@ -4098,6 +4098,145 @@ out_unlock: return ret; } +static int btrfs_ioctl_get_supported_features(struct file *file, + void __user *arg) +{ + struct btrfs_ioctl_feature_flags features[3]; + + features[0].compat_flags = BTRFS_FEATURE_COMPAT_SUPP; + features[0].compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_SUPP; + features[0].incompat_flags = BTRFS_FEATURE_INCOMPAT_SUPP; + + features[1].compat_flags = BTRFS_FEATURE_COMPAT_SAFE_SET; + features[1].compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; + features[1].incompat_flags = BTRFS_FEATURE_INCOMPAT_SAFE_SET; + + features[2].compat_flags = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; + features[2].compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; + features[2].incompat_flags = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; + + if (copy_to_user(arg, &features, sizeof(features))) + return -EFAULT; + + return 0; +} + +static int btrfs_ioctl_get_features(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_super_block *super_block = root->fs_info->super_copy; + struct btrfs_ioctl_feature_flags features; + + features.compat_flags = btrfs_super_compat_flags(super_block); + features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block); + features.incompat_flags = btrfs_super_incompat_flags(super_block); + + if (copy_to_user(arg, &features, sizeof(features))) + return -EFAULT; + + return 0; +} + +static int check_feature_bits(struct btrfs_root *root, const char *type, + u64 change_mask, u64 flags, u64 supported_flags, + u64 safe_set, u64 safe_clear) +{ + u64 disallowed, unsupported; + u64 set_mask = flags & change_mask; + u64 clear_mask = ~flags & change_mask; + + unsupported = set_mask & ~supported_flags; + if (unsupported) { + btrfs_warn(root->fs_info, + "this kernel does not support %s bits 0x%llx", + type, unsupported); + return -EOPNOTSUPP; + } + + disallowed = set_mask & ~safe_set; + if (disallowed) { + btrfs_warn(root->fs_info, + "can''t set %s bits 0x%llx while mounted", + type, disallowed); + return -EPERM; + } + + disallowed = clear_mask & ~safe_clear; + if (disallowed) { + btrfs_warn(root->fs_info, + "can''t clear %s bits 0x%llx while mounted", + type, disallowed); + return -EPERM; + } + + return 0; +} + +#define check_feature(root, change_mask, flags, mask_base) \ +check_feature_bits(root, # mask_base, change_mask, flags, \ + BTRFS_FEATURE_ ## mask_base ## _SUPP, \ + BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ + BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) + +static int btrfs_ioctl_set_features(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_super_block *super_block = root->fs_info->super_copy; + struct btrfs_ioctl_feature_flags flags[2]; + struct btrfs_trans_handle *trans; + u64 newflags; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(flags, arg, sizeof(flags))) + return -EFAULT; + + /* Nothing to do */ + if (!flags[0].compat_flags && !flags[0].compat_ro_flags && + !flags[0].incompat_flags) + return 0; + + ret = check_feature(root, flags[0].compat_flags, + flags[1].compat_flags, COMPAT); + if (ret) + return ret; + + ret = check_feature(root, flags[0].compat_ro_flags, + flags[1].compat_ro_flags, COMPAT_RO); + if (ret) + return ret; + + ret = check_feature(root, flags[0].incompat_flags, + flags[1].incompat_flags, INCOMPAT); + if (ret) + return ret; + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + spin_lock(&root->fs_info->super_lock); + newflags = btrfs_super_compat_flags(super_block); + newflags |= flags[0].compat_flags & flags[1].compat_flags; + newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); + btrfs_set_super_compat_flags(super_block, newflags); + + newflags = btrfs_super_compat_ro_flags(super_block); + newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; + newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); + btrfs_set_super_compat_ro_flags(super_block, newflags); + + newflags = btrfs_super_incompat_flags(super_block); + newflags |= flags[0].incompat_flags & flags[1].incompat_flags; + newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); + btrfs_set_super_incompat_flags(super_block, newflags); + spin_unlock(&root->fs_info->super_lock); + + return btrfs_end_transaction(trans, root); +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -4208,6 +4347,12 @@ long btrfs_ioctl(struct file *file, unsi return btrfs_ioctl_get_fslabel(file, argp); case BTRFS_IOC_SET_FSLABEL: return btrfs_ioctl_set_fslabel(file, argp); + case BTRFS_IOC_GET_SUPPORTED_FEATURES: + return btrfs_ioctl_get_supported_features(file, argp); + case BTRFS_IOC_GET_FEATURES: + return btrfs_ioctl_get_features(file, argp); + case BTRFS_IOC_SET_FEATURES: + return btrfs_ioctl_set_features(file, argp); } return -ENOTTY; --- a/include/uapi/linux/btrfs.h 2013-09-09 17:49:10.808003254 -0400 +++ b/include/uapi/linux/btrfs.h 2013-09-09 17:49:12.483979430 -0400 @@ -184,6 +184,12 @@ struct btrfs_ioctl_fs_info_args { __u64 reserved[124]; /* pad to 1k */ }; +struct btrfs_ioctl_feature_flags { + __u64 compat_flags; + __u64 compat_ro_flags; + __u64 incompat_flags; +}; + /* balance control ioctl modes */ #define BTRFS_BALANCE_CTL_PAUSE 1 #define BTRFS_BALANCE_CTL_CANCEL 2 @@ -579,4 +585,10 @@ static inline char *btrfs_err_str(enum b struct btrfs_ioctl_get_dev_stats) #define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \ struct btrfs_ioctl_dev_replace_args) +#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ + struct btrfs_ioctl_feature_flags) +#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 54, \ + struct btrfs_ioctl_feature_flags[2]) +#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ + struct btrfs_ioctl_feature_flags[3]) #endif /* _UAPI_LINUX_BTRFS_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
This patch adds the ability to publish supported features to sysfs under /sys/fs/btrfs/features. The files are module-wide and export which features the kernel supports. The content, for now, is just "0\n". Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/sysfs.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 37 +++++++++++++++++++++ 2 files changed, 131 insertions(+) --- a/fs/btrfs/sysfs.c 2013-09-10 00:07:58.567116997 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 00:08:31.714646494 -0400 @@ -26,20 +26,114 @@ #include "ctree.h" #include "disk-io.h" #include "transaction.h" +#include "sysfs.h" /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; +struct btrfs_features { + struct kobject f_kobj; + struct completion f_kobj_unregister; +}; + +struct btrfs_features *btrfs_feat; + +BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); +BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); +BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); +BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); +BTRFS_FEAT_ATTR_INCOMPAT(compress_lzov2, COMPRESS_LZOv2); +BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); +BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); +BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); +BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); + +static struct attribute *btrfs_supp_feature_attrs[] = { + BTRFS_SUPP_FEAT_LIST(mixed_backref) + BTRFS_SUPP_FEAT_LIST(default_subvol) + BTRFS_SUPP_FEAT_LIST(mixed_groups) + BTRFS_SUPP_FEAT_LIST(compress_lzo) + BTRFS_SUPP_FEAT_LIST(compress_lzov2) + BTRFS_SUPP_FEAT_LIST(big_metadata) + BTRFS_SUPP_FEAT_LIST(extended_iref) + BTRFS_SUPP_FEAT_LIST(raid56) + BTRFS_SUPP_FEAT_LIST(skinny_metadata) + NULL +}; + +static void btrfs_supp_feat_release(struct kobject *kobj) +{ + complete(&btrfs_feat->f_kobj_unregister); +} + +static ssize_t btrfs_supp_attr_show(struct kobject *kobj, struct attribute *a, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0\n"); +} + +static const struct sysfs_ops btrfs_supp_attr_ops = { + .show = btrfs_supp_attr_show, +}; + +static struct kobj_type btrfs_supp_feat_ktype = { + .default_attrs = btrfs_supp_feature_attrs, + .sysfs_ops = &btrfs_supp_attr_ops, + .release = btrfs_supp_feat_release, +}; + +static int __init btrfs_init_feat_adverts(void) +{ + struct btrfs_features *bf; + int ret = -ENOMEM; + + bf = kzalloc(sizeof(struct btrfs_features), GFP_KERNEL); + if (!bf) + goto out; + + bf->f_kobj.kset = btrfs_kset; + init_completion(&bf->f_kobj_unregister); + + ret = kobject_init_and_add(&bf->f_kobj, &btrfs_supp_feat_ktype, NULL, + "features"); + if (ret) { + kfree(bf); + goto out; + } + + btrfs_feat = bf; + ret = 0; +out: + return ret; +} + +static void btrfs_exit_feat_adverts(void) +{ + kobject_del(&btrfs_feat->f_kobj); + kobject_put(&btrfs_feat->f_kobj); + wait_for_completion(&btrfs_feat->f_kobj_unregister); + kfree(btrfs_feat); +} + int btrfs_init_sysfs(void) { + int ret; btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); if (!btrfs_kset) return -ENOMEM; + + ret = btrfs_init_feat_adverts(); + if (ret) { + kset_unregister(btrfs_kset); + return ret; + } + return 0; } void btrfs_exit_sysfs(void) { + btrfs_exit_feat_adverts(); kset_unregister(btrfs_kset); } --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/fs/btrfs/sysfs.h 2013-09-10 00:09:00.778250180 -0400 @@ -0,0 +1,37 @@ +#ifndef _BTRFS_SYSFS_H_ +#define _BTRFS_SYSFS_H_ + +enum btrfs_feature_set { + FEAT_COMPAT, + FEAT_COMPAT_RO, + FEAT_INCOMPAT, + FEAT_MAX +}; + +struct btrfs_feature_attr { + struct attribute attr; /* global show, no store */ + enum btrfs_feature_set feature_set; + u64 feature_bit; +}; + +#define BTRFS_FEAT_ATTR(_name, _feature_set, _prefix, _feature_bit) \ +static struct btrfs_feature_attr btrfs_attr_##_name = { \ + .attr = { .name = __stringify(_name), .mode = S_IRUGO, }, \ + .feature_set = _feature_set, \ + .feature_bit = _prefix ##_## _feature_bit, \ +} + +#define BTRFS_FEAT_ATTR_COMPAT(name, feature) \ + BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature) +#define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \ + BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT, feature) +#define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ + BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) + +#define BTRFS_SUPP_FEAT_LIST(_name) (&btrfs_attr_##_name.attr), + +/* convert from attribute */ +#define to_btrfs_feature_attr(a) \ + container_of(a, struct btrfs_feature_attr, attr) + +#endif /* _BTRFS_SYSFS_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
This patch adds per-super attributes to sysfs. It doesn''t publish any attributes yet, but does the proper lifetime handling as well as the basic infrastructure to add new attributes. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ctree.h | 2 + fs/btrfs/super.c | 13 +++++++++++- fs/btrfs/sysfs.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 19 ++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) --- a/fs/btrfs/ctree.h 2013-09-10 00:09:12.990087784 -0400 +++ b/fs/btrfs/ctree.h 2013-09-10 00:09:35.521794520 -0400 @@ -3694,6 +3694,8 @@ int btrfs_defrag_leaves(struct btrfs_tra /* sysfs.c */ int btrfs_init_sysfs(void); void btrfs_exit_sysfs(void); +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info); +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info); /* xattr.c */ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); --- a/fs/btrfs/super.c 2013-09-10 00:09:12.994087730 -0400 +++ b/fs/btrfs/super.c 2013-09-10 00:09:35.525794464 -0400 @@ -301,6 +301,8 @@ void __btrfs_panic(struct btrfs_fs_info static void btrfs_put_super(struct super_block *sb) { + btrfs_sysfs_remove_one(btrfs_sb(sb)); + (void)close_ctree(btrfs_sb(sb)->tree_root); /* FIXME: need to fix VFS to return error? */ /* AV: return it _where_? ->put_super() can be triggered by any number @@ -1143,8 +1145,17 @@ static struct dentry *btrfs_mount(struct } root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error); - if (IS_ERR(root)) + if (IS_ERR(root)) { deactivate_locked_super(s); + return root; + } + + error = btrfs_sysfs_add_one(fs_info); + if (error) { + dput(root); + deactivate_locked_super(s); + return ERR_PTR(error); + } return root; --- a/fs/btrfs/sysfs.c 2013-09-10 00:09:13.002087628 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 00:09:49.501616538 -0400 @@ -61,6 +61,64 @@ static struct attribute *btrfs_supp_feat NULL }; +static struct attribute *btrfs_attrs[] = { + NULL, +}; + +static void btrfs_fs_info_release(struct kobject *kobj) +{ + struct btrfs_fs_info *fs_info; + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); + complete(&fs_info->kobj_unregister); +} + +static ssize_t btrfs_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); + struct btrfs_fs_info *fs_info; + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); + + return a->show ? a->show(a, fs_info, buf) : 0; +} + +static ssize_t btrfs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t len) +{ + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); + struct btrfs_fs_info *fs_info; + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); + + return a->store ? a->store(a, fs_info, buf, len) : 0; +} + +static const struct sysfs_ops btrfs_attr_ops = { + .show = btrfs_attr_show, + .store = btrfs_attr_store, +}; + +static struct kobj_type btrfs_ktype = { + .default_attrs = btrfs_attrs, + .sysfs_ops = &btrfs_attr_ops, + .release = btrfs_fs_info_release, +}; + +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) +{ + init_completion(&fs_info->kobj_unregister); + fs_info->super_kobj.kset = btrfs_kset; + return kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, + "%pU", fs_info->fsid); +} + +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) +{ + kobject_del(&fs_info->super_kobj); + kobject_put(&fs_info->super_kobj); + wait_for_completion(&fs_info->kobj_unregister); +} + static void btrfs_supp_feat_release(struct kobject *kobj) { complete(&btrfs_feat->f_kobj_unregister); --- a/fs/btrfs/sysfs.h 2013-09-10 00:09:13.002087628 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-10 00:09:35.525794464 -0400 @@ -8,6 +8,24 @@ enum btrfs_feature_set { FEAT_MAX }; +struct btrfs_attr { + struct attribute attr; + ssize_t (*show)(struct btrfs_attr *, struct btrfs_fs_info *, char *); + ssize_t (*store)(struct btrfs_attr *, struct btrfs_fs_info *, + const char *, size_t); +}; + +#define __INIT_BTRFS_ATTR(_name, _mode, _show, _store) \ +{ \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +#define BTRFS_ATTR(_name, _mode, _show, _store) \ +static struct btrfs_attr btrfs_attr_##_name = \ + __INIT_BTRFS_ATTR(_name, _mode, _show, _store) + struct btrfs_feature_attr { struct attribute attr; /* global show, no store */ enum btrfs_feature_set feature_set; @@ -31,6 +49,7 @@ static struct btrfs_feature_attr btrfs_a #define BTRFS_SUPP_FEAT_LIST(_name) (&btrfs_attr_##_name.attr), /* convert from attribute */ +#define to_btrfs_attr(a) container_of(a, struct btrfs_attr, attr) #define to_btrfs_feature_attr(a) \ container_of(a, struct btrfs_feature_attr, attr) -- 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
This patch publishes information on which features are enabled in the file system on a per-super basis. At this point, it only publishes information on features supported by the file system implementation. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ctree.h | 6 +++ fs/btrfs/sysfs.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/sysfs.h | 2 - 3 files changed, 110 insertions(+), 8 deletions(-) --- a/fs/btrfs/ctree.h 2013-09-09 21:33:17.560730541 -0400 +++ b/fs/btrfs/ctree.h 2013-09-09 21:34:19.067859674 -0400 @@ -1295,6 +1295,11 @@ struct btrfs_stripe_hash_table { #define BTRFS_STRIPE_HASH_TABLE_BITS 11 +struct btrfs_features { + struct kobject f_kobj; + struct completion f_kobj_unregister; +}; + /* fs_info */ struct reloc_control; struct btrfs_device; @@ -1513,6 +1518,7 @@ struct btrfs_fs_info { struct kobject super_kobj; struct completion kobj_unregister; + struct btrfs_features features; int do_barriers; int closing; int log_root_recovering; --- a/fs/btrfs/sysfs.c 2013-09-09 21:33:17.560730541 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-09 23:03:36.030266481 -0400 @@ -31,11 +31,6 @@ /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; -struct btrfs_features { - struct kobject f_kobj; - struct completion f_kobj_unregister; -}; - struct btrfs_features *btrfs_feat; BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); @@ -61,6 +56,43 @@ static struct attribute *btrfs_supp_feat NULL }; +static void btrfs_feature_release(struct kobject *kobj) +{ + struct btrfs_features *feat; + feat = container_of(kobj, struct btrfs_features, f_kobj); + complete(&feat->f_kobj_unregister); +} + +static ssize_t btrfs_feat_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_super_block *disk_super; + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + u64 features; + + fs_info = container_of(kobj, struct btrfs_fs_info, features.f_kobj); + disk_super = fs_info->super_copy; + + if (fa->feature_set == FEAT_COMPAT) + features = btrfs_super_compat_flags(disk_super); + else if (fa->feature_set == FEAT_COMPAT_RO) + features = btrfs_super_compat_ro_flags(disk_super); + else + features = btrfs_super_incompat_flags(disk_super); + + return snprintf(buf, PAGE_SIZE, "%u\n", !!(features & fa->feature_bit)); +} + +static const struct sysfs_ops btrfs_feat_attr_ops = { + .show = btrfs_feat_show, +}; + +static struct kobj_type btrfs_feat_ktype = { + .sysfs_ops = &btrfs_feat_attr_ops, + .release = btrfs_feature_release, +}; + static struct attribute *btrfs_attrs[] = { NULL, }; @@ -104,16 +136,80 @@ static struct kobj_type btrfs_ktype = { .release = btrfs_fs_info_release, }; +static u64 get_features(struct btrfs_fs_info *fs_info, + enum btrfs_feature_set set) +{ + struct btrfs_super_block *disk_super = fs_info->super_copy; + if (set == FEAT_COMPAT) + return btrfs_super_compat_flags(disk_super); + else if (set == FEAT_COMPAT_RO) + return btrfs_super_compat_ro_flags(disk_super); + else + return btrfs_super_incompat_flags(disk_super); +} + +static int add_per_fs_features(struct btrfs_fs_info *fs_info) +{ + int i; + for (i = 0; btrfs_supp_feature_attrs[i]; i++) { + struct attribute *attr = btrfs_supp_feature_attrs[i]; + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + u64 features = get_features(fs_info, fa->feature_set); + int error; + + if (features & fa->feature_bit) { + error = sysfs_create_file(&fs_info->features.f_kobj, + &fa->attr); + if (error) + return error; + } + } + return 0; +} + int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) { + int error; + init_completion(&fs_info->kobj_unregister); fs_info->super_kobj.kset = btrfs_kset; - return kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, - "%pU", fs_info->fsid); + error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, + "%pU", fs_info->fsid); + if (error) + return error; + + init_completion(&fs_info->features.f_kobj_unregister); + error = kobject_init_and_add(&fs_info->features.f_kobj, + &btrfs_feat_ktype, + &fs_info->super_kobj, + "features"); + if (error) + goto out_super; + + error = add_per_fs_features(fs_info); + if (error) + goto out_features; + + return 0; + +out_features: + kobject_del(&fs_info->features.f_kobj); + kobject_put(&fs_info->features.f_kobj); + wait_for_completion(&fs_info->features.f_kobj_unregister); +out_super: + kobject_del(&fs_info->super_kobj); + kobject_put(&fs_info->super_kobj); + wait_for_completion(&fs_info->kobj_unregister); + + return error; } void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { + kobject_del(&fs_info->features.f_kobj); + kobject_put(&fs_info->features.f_kobj); + wait_for_completion(&fs_info->features.f_kobj_unregister); + kobject_del(&fs_info->super_kobj); kobject_put(&fs_info->super_kobj); wait_for_completion(&fs_info->kobj_unregister); --- a/fs/btrfs/sysfs.h 2013-09-09 21:33:17.560730541 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-09 22:48:51.634164572 -0400 @@ -27,7 +27,7 @@ static struct btrfs_attr btrfs_attr_##_n __INIT_BTRFS_ATTR(_name, _mode, _show, _store) struct btrfs_feature_attr { - struct attribute attr; /* global show, no store */ + struct attribute attr; /* per-fs/global show, no store */ enum btrfs_feature_set feature_set; u64 feature_bit; }; -- 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
Jeff Mahoney
2013-Sep-10 04:24 UTC
[patch 5/7] btrfs: Add publishing of unknown features in sysfs
With the compat and compat-ro bits, it''s possible for file systems to exist that have features that aren''t supported by the kernel''s file system implementation yet still be mountable. This patch publishes read-only info on those features using a prefix:number format, where the number is the bit number rather than the shifted value. e.g. "compat:12" Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/sysfs.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) --- a/fs/btrfs/sysfs.c 2013-09-10 00:10:02.549453084 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 00:17:01.813242796 -0400 @@ -56,6 +56,58 @@ static struct attribute *btrfs_supp_feat NULL }; +const char * const btrfs_feature_set_names[FEAT_MAX] = { + [FEAT_COMPAT] = "compat", + [FEAT_COMPAT_RO] = "compat_ro", + [FEAT_INCOMPAT] = "incompat", +}; + +static char btrfs_feature_names[FEAT_MAX][64][13]; +static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][64]; + +static void init_feature_set_attrs(enum btrfs_feature_set set) +{ + int i; + int len = strlen(btrfs_feature_set_names[set]) + 4; + + for (i = 0; i < 64; i++) { + char *name = btrfs_feature_names[set][i]; + struct btrfs_feature_attr *fa; + + snprintf(name, len, "%s:%u", btrfs_feature_set_names[set], i); + + fa = &btrfs_feature_attrs[set][i]; + fa->attr.name = name; + fa->attr.mode = S_IRUGO; + fa->feature_set = set; + fa->feature_bit = (1ULL << i); + } +} + +static void init_feature_attrs(void) +{ + int i; + + init_feature_set_attrs(FEAT_COMPAT); + init_feature_set_attrs(FEAT_COMPAT_RO); + init_feature_set_attrs(FEAT_INCOMPAT); + + /* Copy the names over for supported features */ + for (i = 0; btrfs_supp_feature_attrs[i]; i++) { + struct btrfs_feature_attr *fa; + struct attribute *attr; + int n; + + fa = to_btrfs_feature_attr(btrfs_supp_feature_attrs[i]); + n = ilog2(fa->feature_bit); + + attr = &btrfs_feature_attrs[fa->feature_set][n].attr; + attr->name = fa->attr.name; + + btrfs_feature_names[fa->feature_set][n][0] = ''\0''; + } +} + static void btrfs_feature_release(struct kobject *kobj) { struct btrfs_features *feat; @@ -148,12 +200,12 @@ static u64 get_features(struct btrfs_fs_ return btrfs_super_incompat_flags(disk_super); } -static int add_per_fs_features(struct btrfs_fs_info *fs_info) +static int add_per_fs_feature_set(struct btrfs_fs_info *fs_info, + enum btrfs_feature_set set) { int i; - for (i = 0; btrfs_supp_feature_attrs[i]; i++) { - struct attribute *attr = btrfs_supp_feature_attrs[i]; - struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[0]); i++) { + struct btrfs_feature_attr *fa = &btrfs_feature_attrs[set][i]; u64 features = get_features(fs_info, fa->feature_set); int error; @@ -167,6 +219,21 @@ static int add_per_fs_features(struct bt return 0; } +static int add_per_fs_features(struct btrfs_fs_info *fs_info) +{ + enum btrfs_feature_set set; + int error; + + for (set = FEAT_COMPAT; set < FEAT_MAX; set++) { + error = add_per_fs_feature_set(fs_info, set); + if (error) + return error; + } + + return 0; +} + + int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) { int error; @@ -276,6 +343,7 @@ int btrfs_init_sysfs(void) if (!btrfs_kset) return -ENOMEM; + init_feature_attrs(); ret = btrfs_init_feat_adverts(); if (ret) { kset_unregister(btrfs_kset); -- 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
Jeff Mahoney
2013-Sep-10 04:24 UTC
[patch 6/7] btrfs: Add ability to change features via sysfs
This patch adds the ability to change (set/clear) features while the file system is mounted. A bitmask is added for each feature set for the support to set and clear the bits. A message indicating which bit has been set or cleared is issued when it''s been changed and also when permission or support for a particular bit has been denied. Since the the attributes can now be writable, we need to introduce another struct attribute to hold the different permissions. If neither set or clear is supported, the file will have 0444 permissions. If either set or clear is supported, the file will have 0644 permissions and the store handler will filter out the write based on the bitmask. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/sysfs.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) --- a/fs/btrfs/sysfs.c 2013-09-10 00:10:13.909312817 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 00:12:30.447761188 -0400 @@ -84,6 +84,23 @@ static void init_feature_set_attrs(enum } } +static u64 writeable_mask[FEAT_MAX] = { + [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SAFE_SET | + BTRFS_FEATURE_COMPAT_SAFE_CLEAR, + [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SAFE_SET | + BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR, + [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SAFE_SET | + BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR, +}; + +static inline umode_t fa_mode(struct btrfs_feature_attr *fa) +{ + umode_t mode = S_IRUGO; + if (writeable_mask[fa->feature_set] & fa->feature_bit) + mode |= S_IWUSR; + return mode; +} + static void init_feature_attrs(void) { int i; @@ -103,6 +120,7 @@ static void init_feature_attrs(void) attr = &btrfs_feature_attrs[fa->feature_set][n].attr; attr->name = fa->attr.name; + attr->mode = fa_mode(fa); btrfs_feature_names[fa->feature_set][n][0] = ''\0''; } @@ -136,8 +154,92 @@ static ssize_t btrfs_feat_show(struct ko return snprintf(buf, PAGE_SIZE, "%u\n", !!(features & fa->feature_bit)); } +static ssize_t btrfs_feat_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_super_block *disk_super; + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + struct btrfs_trans_handle *trans; + u64 features, set, clear; + unsigned long val; + int ret; + + fs_info = container_of(kobj, struct btrfs_fs_info, features.f_kobj); + disk_super = fs_info->super_copy; + ret = kstrtoul(skip_spaces(buf), 0, &val); + if (ret) + return ret; + + if (fa->feature_set == FEAT_COMPAT) { + set = BTRFS_FEATURE_COMPAT_SAFE_SET; + clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; + } else if (fa->feature_set == FEAT_COMPAT_RO) { + set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; + clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; + } else { + set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; + clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; + } + + if (fa->feature_set == FEAT_COMPAT) + features = btrfs_super_compat_flags(disk_super); + else if (fa->feature_set == FEAT_COMPAT_RO) + features = btrfs_super_compat_ro_flags(disk_super); + else + features = btrfs_super_incompat_flags(disk_super); + + /* Nothing to do */ + if ((val && (features & fa->feature_bit)) || + (!val && !(features & fa->feature_bit))) + return count; + + if ((val && !(set & fa->feature_bit)) || + (!val && !(clear & fa->feature_bit))) { + btrfs_info(fs_info, + "%sabling feature %s on mounted fs is not supported.", + val ? "En" : "Dis", fa->attr.name); + return -EPERM; + } + + btrfs_info(fs_info, "%s %s feature flag", + val ? "Setting" : "Clearing", fa->attr.name); + + trans = btrfs_start_transaction(fs_info->fs_root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + spin_lock(&fs_info->super_lock); + if (fa->feature_set == FEAT_COMPAT) + features = btrfs_super_compat_flags(disk_super); + else if (fa->feature_set == FEAT_COMPAT_RO) + features = btrfs_super_compat_ro_flags(disk_super); + else + features = btrfs_super_incompat_flags(disk_super); + + if (val) + features |= fa->feature_bit; + else + features &= ~fa->feature_bit; + + if (fa->feature_set == FEAT_COMPAT) + btrfs_set_super_compat_flags(disk_super, features); + else if (fa->feature_set == FEAT_COMPAT_RO) + btrfs_set_super_compat_ro_flags(disk_super, features); + else + btrfs_set_super_incompat_flags(disk_super, features); + spin_unlock(&fs_info->super_lock); + + ret = btrfs_end_transaction(trans, fs_info->fs_root); + if (ret) + return ret; + + return count; +} + static const struct sysfs_ops btrfs_feat_attr_ops = { .show = btrfs_feat_show, + .store = btrfs_feat_store, }; static struct kobj_type btrfs_feat_ktype = { @@ -209,7 +311,8 @@ static int add_per_fs_feature_set(struct u64 features = get_features(fs_info, fa->feature_set); int error; - if (features & fa->feature_bit) { + if ((features & fa->feature_bit) || + (fa->attr.mode & S_IWUSR)) { error = sysfs_create_file(&fs_info->features.f_kobj, &fa->attr); if (error) -- 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
Jeff Mahoney
2013-Sep-10 04:24 UTC
[patch 7/7] btrfs: use feature attribute names to print better error messages
Now that we have the feature name strings available in the kernel via the sysfs attributes, we can use them for printing better failure messages from the ioctl path. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ioctl.c | 35 ++++++++++++++++++++++++++++++----- fs/btrfs/sysfs.c | 25 +++++++++++++++++++++++++ fs/btrfs/sysfs.h | 3 +++ 3 files changed, 58 insertions(+), 5 deletions(-) --- a/fs/btrfs/ioctl.c 2013-09-09 23:23:34.794883859 -0400 +++ b/fs/btrfs/ioctl.c 2013-09-09 23:24:03.019073609 -0400 @@ -56,6 +56,7 @@ #include "rcu-string.h" #include "send.h" #include "dev-replace.h" +#include "sysfs.h" /* Mask out flags that are inappropriate for the given type of inode. */ static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) @@ -4143,17 +4144,27 @@ static int btrfs_ioctl_get_features(stru return 0; } -static int check_feature_bits(struct btrfs_root *root, const char *type, +static int check_feature_bits(struct btrfs_root *root, + enum btrfs_feature_set set, u64 change_mask, u64 flags, u64 supported_flags, u64 safe_set, u64 safe_clear) { + const char *type = btrfs_feature_set_names[set]; + char *names; u64 disallowed, unsupported; u64 set_mask = flags & change_mask; u64 clear_mask = ~flags & change_mask; unsupported = set_mask & ~supported_flags; if (unsupported) { - btrfs_warn(root->fs_info, + names = btrfs_printable_features(set, unsupported); + if (names) { + btrfs_warn(root->fs_info, + "this kernel does not support the %s feature bit%s", + names, strchr(names, '','') ? "s" : ""); + kfree(names); + } else + btrfs_warn(root->fs_info, "this kernel does not support %s bits 0x%llx", type, unsupported); return -EOPNOTSUPP; @@ -4161,7 +4172,14 @@ static int check_feature_bits(struct btr disallowed = set_mask & ~safe_set; if (disallowed) { - btrfs_warn(root->fs_info, + names = btrfs_printable_features(set, disallowed); + if (names) { + btrfs_warn(root->fs_info, + "can''t set the %s feature bit%s while mounted", + names, strchr(names, '','') ? "s" : ""); + kfree(names); + } else + btrfs_warn(root->fs_info, "can''t set %s bits 0x%llx while mounted", type, disallowed); return -EPERM; @@ -4169,7 +4187,14 @@ static int check_feature_bits(struct btr disallowed = clear_mask & ~safe_clear; if (disallowed) { - btrfs_warn(root->fs_info, + names = btrfs_printable_features(set, disallowed); + if (names) { + btrfs_warn(root->fs_info, + "can''t clear the %s feature bit%s while mounted", + names, strchr(names, '','') ? "s" : ""); + kfree(names); + } else + btrfs_warn(root->fs_info, "can''t clear %s bits 0x%llx while mounted", type, disallowed); return -EPERM; @@ -4179,7 +4204,7 @@ static int check_feature_bits(struct btr } #define check_feature(root, change_mask, flags, mask_base) \ -check_feature_bits(root, # mask_base, change_mask, flags, \ +check_feature_bits(root, FEAT_##mask_base, change_mask, flags, \ BTRFS_FEATURE_ ## mask_base ## _SUPP, \ BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) --- a/fs/btrfs/sysfs.c 2013-09-09 23:24:02.991073420 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-09 23:24:03.019073609 -0400 @@ -65,6 +65,31 @@ const char *btrfs_feature_set_names[FEAT static char btrfs_feature_names[FEAT_MAX][64][13]; static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][64]; +char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) +{ + size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ + int len = 0; + int i; + char *str; + + str = kmalloc(bufsize, GFP_KERNEL); + if (!str) + return str; + + for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { + if (!(flags & (1ULL << i))) + continue; + + flags &= ~(1ULL << i); + + len += snprintf(str + len, bufsize - len, + "%s%s", len ? "," : "", + btrfs_feature_attrs[set][i].attr.name); + } + + return str; +} + static void init_feature_set_attrs(enum btrfs_feature_set set) { int i; --- a/fs/btrfs/sysfs.h 2013-09-09 23:23:34.794883859 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-09 23:24:03.019073609 -0400 @@ -53,4 +53,7 @@ static struct btrfs_feature_attr btrfs_a #define to_btrfs_feature_attr(a) \ container_of(a, struct btrfs_feature_attr, attr) +char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); +extern const char *btrfs_feature_set_names[FEAT_MAX]; + #endif /* _BTRFS_SYSFS_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
David Sterba
2013-Sep-16 17:26 UTC
Re: [patch 1/7] [PATCH] btrfs: add ability to query/change feature bits online
On Tue, Sep 10, 2013 at 12:24:09AM -0400, Jeff Mahoney wrote:> +static int btrfs_ioctl_set_features(struct file *file, void __user *arg) > +{ > + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; > + struct btrfs_super_block *super_block = root->fs_info->super_copy; > + struct btrfs_ioctl_feature_flags flags[2]; > + struct btrfs_trans_handle *trans; > + u64 newflags; > + int ret; > + > + if (!capable(CAP_SYS_ADMIN)) > + return -EPERM; > + > + if (copy_from_user(flags, arg, sizeof(flags))) > + return -EFAULT; > + > + /* Nothing to do */ > + if (!flags[0].compat_flags && !flags[0].compat_ro_flags && > + !flags[0].incompat_flags) > + return 0; > + > + ret = check_feature(root, flags[0].compat_flags, > + flags[1].compat_flags, COMPAT); > + if (ret) > + return ret; > + > + ret = check_feature(root, flags[0].compat_ro_flags, > + flags[1].compat_ro_flags, COMPAT_RO); > + if (ret) > + return ret; > + > + ret = check_feature(root, flags[0].incompat_flags, > + flags[1].incompat_flags, INCOMPAT); > + if (ret) > + return ret; > + > + trans = btrfs_start_transaction(root, 1);It''s ok to use 0 here, it''s a superblock change and not related the the metadata (similar to changing the label).> + if (IS_ERR(trans)) > + return PTR_ERR(trans); > + > + spin_lock(&root->fs_info->super_lock); > + newflags = btrfs_super_compat_flags(super_block); > + newflags |= flags[0].compat_flags & flags[1].compat_flags; > + newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); > + btrfs_set_super_compat_flags(super_block, newflags); > + > + newflags = btrfs_super_compat_ro_flags(super_block); > + newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; > + newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); > + btrfs_set_super_compat_ro_flags(super_block, newflags); > + > + newflags = btrfs_super_incompat_flags(super_block); > + newflags |= flags[0].incompat_flags & flags[1].incompat_flags; > + newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); > + btrfs_set_super_incompat_flags(super_block, newflags); > + spin_unlock(&root->fs_info->super_lock); > + > + return btrfs_end_transaction(trans, root);I think it''s better to use btrfs_commit_transaction. The ioctl is about to do a permanent change, any crash between ioctl and full commit will revert to previous state of the features. This is not IMO desirable from administrators POV. (Sidenote, IOC_SET_FSLABEL needs the same update.)> +} > + > --- a/include/uapi/linux/btrfs.h 2013-09-09 17:49:10.808003254 -0400 > +++ b/include/uapi/linux/btrfs.h 2013-09-09 17:49:12.483979430 -0400 > @@ -184,6 +184,12 @@ struct btrfs_ioctl_fs_info_args { > __u64 reserved[124]; /* pad to 1k */ > }; > > +struct btrfs_ioctl_feature_flags { > + __u64 compat_flags; > + __u64 compat_ro_flags; > + __u64 incompat_flags;I wonder if it makes sense to add spare bytes here, but does not seem necessary.> +}; > @@ -579,4 +585,10 @@ static inline char *btrfs_err_str(enum b > +#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ > + struct btrfs_ioctl_feature_flags) > +#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 54, \ > + struct btrfs_ioctl_feature_flags[2]) > +#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ > + struct btrfs_ioctl_feature_flags[3])The ioctl number 54 clashes with the OOB dedup merged into 3.12, 55 is for the in-bound dedup and Anand has claimed 56. I''ve allocated 57 for you and updated th wiki page: https://btrfs.wiki.kernel.org/index.php/Project_ideas#Development_notes.2C_please_read Stefan''s trick to reuse the same number is really neat. -- 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
Jeff Mahoney
2013-Sep-16 18:13 UTC
Re: [patch 1/7] [PATCH] btrfs: add ability to query/change feature bits online
On 9/16/13 1:26 PM, David Sterba wrote:> On Tue, Sep 10, 2013 at 12:24:09AM -0400, Jeff Mahoney wrote: >> +static int btrfs_ioctl_set_features(struct file *file, void __user *arg) >> +{ >> + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; >> + struct btrfs_super_block *super_block = root->fs_info->super_copy; >> + struct btrfs_ioctl_feature_flags flags[2]; >> + struct btrfs_trans_handle *trans; >> + u64 newflags; >> + int ret; >> + >> + if (!capable(CAP_SYS_ADMIN)) >> + return -EPERM; >> + >> + if (copy_from_user(flags, arg, sizeof(flags))) >> + return -EFAULT; >> + >> + /* Nothing to do */ >> + if (!flags[0].compat_flags && !flags[0].compat_ro_flags && >> + !flags[0].incompat_flags) >> + return 0; >> + >> + ret = check_feature(root, flags[0].compat_flags, >> + flags[1].compat_flags, COMPAT); >> + if (ret) >> + return ret; >> + >> + ret = check_feature(root, flags[0].compat_ro_flags, >> + flags[1].compat_ro_flags, COMPAT_RO); >> + if (ret) >> + return ret; >> + >> + ret = check_feature(root, flags[0].incompat_flags, >> + flags[1].incompat_flags, INCOMPAT); >> + if (ret) >> + return ret; >> + >> + trans = btrfs_start_transaction(root, 1); > > It''s ok to use 0 here, it''s a superblock change and not related the the > metadata (similar to changing the label). > >> + if (IS_ERR(trans)) >> + return PTR_ERR(trans); >> + >> + spin_lock(&root->fs_info->super_lock); >> + newflags = btrfs_super_compat_flags(super_block); >> + newflags |= flags[0].compat_flags & flags[1].compat_flags; >> + newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); >> + btrfs_set_super_compat_flags(super_block, newflags); >> + >> + newflags = btrfs_super_compat_ro_flags(super_block); >> + newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; >> + newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); >> + btrfs_set_super_compat_ro_flags(super_block, newflags); >> + >> + newflags = btrfs_super_incompat_flags(super_block); >> + newflags |= flags[0].incompat_flags & flags[1].incompat_flags; >> + newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); >> + btrfs_set_super_incompat_flags(super_block, newflags); >> + spin_unlock(&root->fs_info->super_lock); >> + >> + return btrfs_end_transaction(trans, root); > > I think it''s better to use btrfs_commit_transaction. The ioctl is about > to do a permanent change, any crash between ioctl and full commit will > revert to previous state of the features. This is not IMO desirable from > administrators POV. > > (Sidenote, IOC_SET_FSLABEL needs the same update.)Done, and I have a patch to fix the setlabel case as well.>> +} >> + >> --- a/include/uapi/linux/btrfs.h 2013-09-09 17:49:10.808003254 -0400 >> +++ b/include/uapi/linux/btrfs.h 2013-09-09 17:49:12.483979430 -0400 >> @@ -184,6 +184,12 @@ struct btrfs_ioctl_fs_info_args { >> __u64 reserved[124]; /* pad to 1k */ >> }; >> >> +struct btrfs_ioctl_feature_flags { >> + __u64 compat_flags; >> + __u64 compat_ro_flags; >> + __u64 incompat_flags; > > I wonder if it makes sense to add spare bytes here, but does not seem > necessary.We could double the size to allow for expansion, but I think it''d probably make more sense to add another ioctl later if we end up getting up to 64 features in a field.>> +}; >> @@ -579,4 +585,10 @@ static inline char *btrfs_err_str(enum b >> +#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ >> + struct btrfs_ioctl_feature_flags) >> +#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 54, \ >> + struct btrfs_ioctl_feature_flags[2]) >> +#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 54, \ >> + struct btrfs_ioctl_feature_flags[3]) > > The ioctl number 54 clashes with the OOB dedup merged into 3.12, 55 is > for the in-bound dedup and Anand has claimed 56. I''ve allocated 57 for > you and updated th wiki page: > > https://btrfs.wiki.kernel.org/index.php/Project_ideas#Development_notes.2C_please_read > > Stefan''s trick to reuse the same number is really neat.Thanks, changed. -Jeff -- Jeff Mahoney SUSE Labs
Alex Lyakas
2013-Oct-26 19:00 UTC
Re: [patch 3/7] btrfs: Add per-super attributes to sysfs
Hi Jeff, On Tue, Sep 10, 2013 at 7:24 AM, Jeff Mahoney <jeffm@suse.com> wrote:> This patch adds per-super attributes to sysfs. > > It doesn''t publish any attributes yet, but does the proper lifetime > handling as well as the basic infrastructure to add new attributes. > > Signed-off-by: Jeff Mahoney <jeffm@suse.com> > --- > fs/btrfs/ctree.h | 2 + > fs/btrfs/super.c | 13 +++++++++++- > fs/btrfs/sysfs.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fs/btrfs/sysfs.h | 19 ++++++++++++++++++ > 4 files changed, 91 insertions(+), 1 deletion(-) > > --- a/fs/btrfs/ctree.h 2013-09-10 00:09:12.990087784 -0400 > +++ b/fs/btrfs/ctree.h 2013-09-10 00:09:35.521794520 -0400 > @@ -3694,6 +3694,8 @@ int btrfs_defrag_leaves(struct btrfs_tra > /* sysfs.c */ > int btrfs_init_sysfs(void); > void btrfs_exit_sysfs(void); > +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info); > +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info); > > /* xattr.c */ > ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); > --- a/fs/btrfs/super.c 2013-09-10 00:09:12.994087730 -0400 > +++ b/fs/btrfs/super.c 2013-09-10 00:09:35.525794464 -0400 > @@ -301,6 +301,8 @@ void __btrfs_panic(struct btrfs_fs_info > > static void btrfs_put_super(struct super_block *sb) > { > + btrfs_sysfs_remove_one(btrfs_sb(sb)); > + > (void)close_ctree(btrfs_sb(sb)->tree_root); > /* FIXME: need to fix VFS to return error? */ > /* AV: return it _where_? ->put_super() can be triggered by any number > @@ -1143,8 +1145,17 @@ static struct dentry *btrfs_mount(struct > } > > root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error); > - if (IS_ERR(root)) > + if (IS_ERR(root)) { > deactivate_locked_super(s); > + return root; > + } > + > + error = btrfs_sysfs_add_one(fs_info); > + if (error) { > + dput(root); > + deactivate_locked_super(s); > + return ERR_PTR(error); > + } > > return root; > > --- a/fs/btrfs/sysfs.c 2013-09-10 00:09:13.002087628 -0400 > +++ b/fs/btrfs/sysfs.c 2013-09-10 00:09:49.501616538 -0400 > @@ -61,6 +61,64 @@ static struct attribute *btrfs_supp_feat > NULL > }; > > +static struct attribute *btrfs_attrs[] = { > + NULL, > +}; > + > +static void btrfs_fs_info_release(struct kobject *kobj) > +{ > + struct btrfs_fs_info *fs_info; > + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); > + complete(&fs_info->kobj_unregister); > +} > + > +static ssize_t btrfs_attr_show(struct kobject *kobj, > + struct attribute *attr, char *buf) > +{ > + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); > + struct btrfs_fs_info *fs_info; > + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); > + > + return a->show ? a->show(a, fs_info, buf) : 0; > +} > + > +static ssize_t btrfs_attr_store(struct kobject *kobj, > + struct attribute *attr, > + const char *buf, size_t len) > +{ > + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); > + struct btrfs_fs_info *fs_info; > + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); > + > + return a->store ? a->store(a, fs_info, buf, len) : 0; > +} > + > +static const struct sysfs_ops btrfs_attr_ops = { > + .show = btrfs_attr_show, > + .store = btrfs_attr_store, > +}; > + > +static struct kobj_type btrfs_ktype = { > + .default_attrs = btrfs_attrs, > + .sysfs_ops = &btrfs_attr_ops, > + .release = btrfs_fs_info_release, > +}; > + > +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) > +{ > + init_completion(&fs_info->kobj_unregister); > + fs_info->super_kobj.kset = btrfs_kset; > + return kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, > + "%pU", fs_info->fsid); > +} > + > +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) > +{ > + kobject_del(&fs_info->super_kobj);Is there a reason for this explicit call? The last kobject_put will do this automatically, no?> + kobject_put(&fs_info->super_kobj); > + wait_for_completion(&fs_info->kobj_unregister); > +} > + > static void btrfs_supp_feat_release(struct kobject *kobj) > { > complete(&btrfs_feat->f_kobj_unregister); > --- a/fs/btrfs/sysfs.h 2013-09-10 00:09:13.002087628 -0400 > +++ b/fs/btrfs/sysfs.h 2013-09-10 00:09:35.525794464 -0400 > @@ -8,6 +8,24 @@ enum btrfs_feature_set { > FEAT_MAX > }; > > +struct btrfs_attr { > + struct attribute attr; > + ssize_t (*show)(struct btrfs_attr *, struct btrfs_fs_info *, char *); > + ssize_t (*store)(struct btrfs_attr *, struct btrfs_fs_info *, > + const char *, size_t); > +}; > + > +#define __INIT_BTRFS_ATTR(_name, _mode, _show, _store) \ > +{ \ > + .attr = { .name = __stringify(_name), .mode = _mode }, \ > + .show = _show, \ > + .store = _store, \ > +} > + > +#define BTRFS_ATTR(_name, _mode, _show, _store) \ > +static struct btrfs_attr btrfs_attr_##_name = \ > + __INIT_BTRFS_ATTR(_name, _mode, _show, _store) > + > struct btrfs_feature_attr { > struct attribute attr; /* global show, no store */ > enum btrfs_feature_set feature_set; > @@ -31,6 +49,7 @@ static struct btrfs_feature_attr btrfs_a > #define BTRFS_SUPP_FEAT_LIST(_name) (&btrfs_attr_##_name.attr), > > /* convert from attribute */ > +#define to_btrfs_attr(a) container_of(a, struct btrfs_attr, attr) > #define to_btrfs_feature_attr(a) \ > container_of(a, struct btrfs_feature_attr, attr) > > > > -- > 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.htmlThanks, Alex, -- 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
Jeff Mahoney
2013-Oct-26 19:24 UTC
Re: [patch 3/7] btrfs: Add per-super attributes to sysfs
On 10/26/13, 3:00 PM, Alex Lyakas wrote:> Hi Jeff, > > On Tue, Sep 10, 2013 at 7:24 AM, Jeff Mahoney <jeffm@suse.com> wrote: >> This patch adds per-super attributes to sysfs. >> >> It doesn''t publish any attributes yet, but does the proper lifetime >> handling as well as the basic infrastructure to add new attributes. >> >> Signed-off-by: Jeff Mahoney <jeffm@suse.com> >> --- >> fs/btrfs/ctree.h | 2 + >> fs/btrfs/super.c | 13 +++++++++++- >> fs/btrfs/sysfs.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> fs/btrfs/sysfs.h | 19 ++++++++++++++++++ >> 4 files changed, 91 insertions(+), 1 deletion(-) >> >> --- a/fs/btrfs/ctree.h 2013-09-10 00:09:12.990087784 -0400 >> +++ b/fs/btrfs/ctree.h 2013-09-10 00:09:35.521794520 -0400 >> @@ -3694,6 +3694,8 @@ int btrfs_defrag_leaves(struct btrfs_tra >> /* sysfs.c */ >> int btrfs_init_sysfs(void); >> void btrfs_exit_sysfs(void); >> +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info); >> +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info); >> >> /* xattr.c */ >> ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); >> --- a/fs/btrfs/super.c 2013-09-10 00:09:12.994087730 -0400 >> +++ b/fs/btrfs/super.c 2013-09-10 00:09:35.525794464 -0400 >> @@ -301,6 +301,8 @@ void __btrfs_panic(struct btrfs_fs_info >> >> static void btrfs_put_super(struct super_block *sb) >> { >> + btrfs_sysfs_remove_one(btrfs_sb(sb)); >> + >> (void)close_ctree(btrfs_sb(sb)->tree_root); >> /* FIXME: need to fix VFS to return error? */ >> /* AV: return it _where_? ->put_super() can be triggered by any number >> @@ -1143,8 +1145,17 @@ static struct dentry *btrfs_mount(struct >> } >> >> root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error); >> - if (IS_ERR(root)) >> + if (IS_ERR(root)) { >> deactivate_locked_super(s); >> + return root; >> + } >> + >> + error = btrfs_sysfs_add_one(fs_info); >> + if (error) { >> + dput(root); >> + deactivate_locked_super(s); >> + return ERR_PTR(error); >> + } >> >> return root; >> >> --- a/fs/btrfs/sysfs.c 2013-09-10 00:09:13.002087628 -0400 >> +++ b/fs/btrfs/sysfs.c 2013-09-10 00:09:49.501616538 -0400 >> @@ -61,6 +61,64 @@ static struct attribute *btrfs_supp_feat >> NULL >> }; >> >> +static struct attribute *btrfs_attrs[] = { >> + NULL, >> +}; >> + >> +static void btrfs_fs_info_release(struct kobject *kobj) >> +{ >> + struct btrfs_fs_info *fs_info; >> + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); >> + complete(&fs_info->kobj_unregister); >> +} >> + >> +static ssize_t btrfs_attr_show(struct kobject *kobj, >> + struct attribute *attr, char *buf) >> +{ >> + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); >> + struct btrfs_fs_info *fs_info; >> + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); >> + >> + return a->show ? a->show(a, fs_info, buf) : 0; >> +} >> + >> +static ssize_t btrfs_attr_store(struct kobject *kobj, >> + struct attribute *attr, >> + const char *buf, size_t len) >> +{ >> + struct btrfs_attr *a = container_of(attr, struct btrfs_attr, attr); >> + struct btrfs_fs_info *fs_info; >> + fs_info = container_of(kobj, struct btrfs_fs_info, super_kobj); >> + >> + return a->store ? a->store(a, fs_info, buf, len) : 0; >> +} >> + >> +static const struct sysfs_ops btrfs_attr_ops = { >> + .show = btrfs_attr_show, >> + .store = btrfs_attr_store, >> +}; >> + >> +static struct kobj_type btrfs_ktype = { >> + .default_attrs = btrfs_attrs, >> + .sysfs_ops = &btrfs_attr_ops, >> + .release = btrfs_fs_info_release, >> +}; >> + >> +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) >> +{ >> + init_completion(&fs_info->kobj_unregister); >> + fs_info->super_kobj.kset = btrfs_kset; >> + return kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, >> + "%pU", fs_info->fsid); >> +} >> + >> +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) >> +{ >> + kobject_del(&fs_info->super_kobj); > Is there a reason for this explicit call? The last kobject_put will do > this automatically, no?This should be the last reference, but even if it''s not, it should be removed from sysfs here. Otherwise, I suppose it''s personal preference. The call to kobject_del in kobject_release will also drop a debugging message if kobject debugging is enabled. -Jeff>> + kobject_put(&fs_info->super_kobj); >> + wait_for_completion(&fs_info->kobj_unregister); >> +} >> + >> static void btrfs_supp_feat_release(struct kobject *kobj) >> { >> complete(&btrfs_feat->f_kobj_unregister); >> --- a/fs/btrfs/sysfs.h 2013-09-10 00:09:13.002087628 -0400 >> +++ b/fs/btrfs/sysfs.h 2013-09-10 00:09:35.525794464 -0400 >> @@ -8,6 +8,24 @@ enum btrfs_feature_set { >> FEAT_MAX >> }; >> >> +struct btrfs_attr { >> + struct attribute attr; >> + ssize_t (*show)(struct btrfs_attr *, struct btrfs_fs_info *, char *); >> + ssize_t (*store)(struct btrfs_attr *, struct btrfs_fs_info *, >> + const char *, size_t); >> +}; >> + >> +#define __INIT_BTRFS_ATTR(_name, _mode, _show, _store) \ >> +{ \ >> + .attr = { .name = __stringify(_name), .mode = _mode }, \ >> + .show = _show, \ >> + .store = _store, \ >> +} >> + >> +#define BTRFS_ATTR(_name, _mode, _show, _store) \ >> +static struct btrfs_attr btrfs_attr_##_name = \ >> + __INIT_BTRFS_ATTR(_name, _mode, _show, _store) >> + >> struct btrfs_feature_attr { >> struct attribute attr; /* global show, no store */ >> enum btrfs_feature_set feature_set; >> @@ -31,6 +49,7 @@ static struct btrfs_feature_attr btrfs_a >> #define BTRFS_SUPP_FEAT_LIST(_name) (&btrfs_attr_##_name.attr), >> >> /* convert from attribute */ >> +#define to_btrfs_attr(a) container_of(a, struct btrfs_attr, attr) >> #define to_btrfs_feature_attr(a) \ >> container_of(a, struct btrfs_feature_attr, attr) >> >> >> >> -- >> 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 > > Thanks, > Alex, > -- > 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 >-- Jeff Mahoney SUSE Labs -- 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