Jeff Mahoney
2013-Sep-16 18:19 UTC
[patch 0/9 v3] add ability to query/change feature bits online
The first patch of this series is the ioctl patch I posted before, with the review comments handled. It now uses the reserved 57 ioctl. 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. The kobj_completion patch is not intended to be applied with this set. It should be accepted via Greg KH but is needed for testing until then. 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-16 18:19 UTC
[patch 1/9] btrfs: add ioctls 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-11 21:40:48.939758689 -0400 +++ b/fs/btrfs/ctree.h 2013-09-16 13:37:13.020197254 -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-11 21:40:48.991757905 -0400 +++ b/fs/btrfs/ioctl.c 2013-09-16 13:37:09.720237996 -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-10 12:36:31.643763746 -0400 +++ b/include/uapi/linux/btrfs.h 2013-09-16 13:38:03.251588809 -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, 57, \ + struct btrfs_ioctl_feature_flags) +#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ + struct btrfs_ioctl_feature_flags[2]) +#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ + 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
Jeff Mahoney
2013-Sep-16 18:19 UTC
[patch 2/9] btrfs: use btrfs_commit_transaction when setting fslabel
The set_fslabel ioctl uses btrfs_end_transaction, which means it''s possible that the change will be lost if the system crashes. Let''s use btrfs_commit_transaction instead. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/fs/btrfs/ioctl.c 2013-09-16 13:50:56.131324074 -0400 +++ b/fs/btrfs/ioctl.c 2013-09-16 13:56:46.415235886 -0400 @@ -4091,7 +4091,7 @@ static int btrfs_ioctl_set_fslabel(struc } strcpy(super_block->label, label); - ret = btrfs_end_transaction(trans, root); + ret = btrfs_commit_transaction(trans, root); out_unlock: mutex_unlock(&root->fs_info->volume_mutex); -- 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
A common way to handle kobject lifetimes in embedded in objects with different lifetime rules is to pair the kobject with a struct completion. This introduces a kobj_completion structure that can be used in place of the pairing, along with several convenience functions for initialization, release, and put-and-wait. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- include/linux/kobj_completion.h | 18 ++++++++++++++ lib/kobject.c | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/include/linux/kobj_completion.h 2013-09-10 12:58:03.530554144 -0400 @@ -0,0 +1,18 @@ +#ifndef _KOBJ_COMPLETION_H_ +#define _KOBJ_COMPLETION_H_ + +#include <linux/kobject.h> +#include <linux/completion.h> + +struct kobj_completion { + struct kobject kc_kobj; + struct completion kc_unregister; +}; + +#define kobj_to_kobj_completion(kobj) \ + container_of(kobj, struct kobj_completion, kc_kobj) + +void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype); +void kobj_completion_release(struct kobject *kobj); +void kobj_completion_del_and_wait(struct kobj_completion *kc); +#endif /* _KOBJ_COMPLETION_H_ */ --- a/lib/kobject.c 2013-09-10 12:57:54.198666613 -0400 +++ b/lib/kobject.c 2013-09-10 15:22:15.122724060 -0400 @@ -13,6 +13,7 @@ */ #include <linux/kobject.h> +#include <linux/kobj_completion.h> #include <linux/string.h> #include <linux/export.h> #include <linux/stat.h> @@ -711,6 +712,55 @@ const struct sysfs_ops kobj_sysfs_ops }; /** + * kobj_completion_init - initialize a kobj_completion object. + * @kc: kobj_completion + * @ktype: type of kobject to initialize + * + * kobj_completion structures can be embedded within structures with different + * lifetime rules. During the release of the enclosing object, we can + * wait on the release of the kobject so that we don''t free it while it''s + * still busy. + */ +void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype) +{ + init_completion(&kc->kc_unregister); + kobject_init(&kc->kc_kobj, ktype); +} +EXPORT_SYMBOL_GPL(kobj_completion_init); + +/** + * kobj_completion_release - release a kobj_completion object + * @kobj: kobject embedded in kobj_completion + * + * Used with kobject_release to notify waiters that the kobject has been + * released. + */ +void kobj_completion_release(struct kobject *kobj) +{ + struct kobj_completion *kc = kobj_to_kobj_completion(kobj); + complete(&kc->kc_unregister); +} +EXPORT_SYMBOL_GPL(kobj_completion_release); + +/** + * kobj_completion_del_and_wait - release the kobject and wait for it + * @kc: kobj_completion object to release + * + * Delete the kobject from sysfs and drop the reference count. Then wait + * until any other outstanding references are also dropped. This routine + * is only necessary once other references may have been taken on the + * kobject. Typically this happens when the kobject has been published + * to sysfs via kobject_add. + */ +void kobj_completion_del_and_wait(struct kobj_completion *kc) +{ + kobject_del(&kc->kc_kobj); + kobject_put(&kc->kc_kobj); + wait_for_completion(&kc->kc_unregister); +} +EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait); + +/** * kset_register - initialize and add a kset. * @k: 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
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/ctree.h | 4 ++-- fs/btrfs/disk-io.c | 1 - fs/btrfs/sysfs.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) --- a/fs/btrfs/ctree.h 2013-09-16 13:46:30.875025162 -0400 +++ b/fs/btrfs/ctree.h 2013-09-16 13:48:53.252952421 -0400 @@ -32,6 +32,7 @@ #include <asm/kmap_types.h> #include <linux/pagemap.h> #include <linux/btrfs.h> +#include <linux/kobj_completion.h> #include "extent_io.h" #include "extent_map.h" #include "async-thread.h" @@ -1511,8 +1512,7 @@ struct btrfs_fs_info { struct task_struct *cleaner_kthread; int thread_pool_size; - struct kobject super_kobj; - struct completion kobj_unregister; + struct kobj_completion super_kc; int do_barriers; int closing; int log_root_recovering; --- a/fs/btrfs/disk-io.c 2013-09-16 13:46:30.875025162 -0400 +++ b/fs/btrfs/disk-io.c 2013-09-16 13:46:32.970992936 -0400 @@ -2163,7 +2163,6 @@ int open_ctree(struct super_block *sb, mutex_init(&fs_info->reloc_mutex); seqlock_init(&fs_info->profiles_lock); - init_completion(&fs_info->kobj_unregister); INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); INIT_LIST_HEAD(&fs_info->space_info); INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); --- a/fs/btrfs/sysfs.c 2013-09-16 13:46:30.875025162 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-16 13:48:53.252952421 -0400 @@ -22,24 +22,76 @@ #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/kobject.h> +#include <linux/kobj_completion.h> #include "ctree.h" #include "disk-io.h" #include "transaction.h" +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_FEAT_ATTR_LIST(mixed_backref) + BTRFS_FEAT_ATTR_LIST(default_subvol) + BTRFS_FEAT_ATTR_LIST(mixed_groups) + BTRFS_FEAT_ATTR_LIST(compress_lzo) + BTRFS_FEAT_ATTR_LIST(compress_lzov2) + BTRFS_FEAT_ATTR_LIST(big_metadata) + BTRFS_FEAT_ATTR_LIST(extended_iref) + BTRFS_FEAT_ATTR_LIST(raid56) + BTRFS_FEAT_ATTR_LIST(skinny_metadata) + NULL +}; + +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 = kobj_completion_release, +}; + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; +static struct kobj_completion btrfs_features; int btrfs_init_sysfs(void) { + int ret; btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); if (!btrfs_kset) return -ENOMEM; + + kobj_completion_init(&btrfs_features, &btrfs_supp_feat_ktype); + btrfs_features.kc_kobj.kset = btrfs_kset; + ret = kobject_add(&btrfs_features.kc_kobj, NULL, "features"); + if (ret) { + kset_unregister(btrfs_kset); + return ret; + } + return 0; } void btrfs_exit_sysfs(void) { + kobj_completion_del_and_wait(&btrfs_features); kset_unregister(btrfs_kset); } --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/fs/btrfs/sysfs.h 2013-09-16 13:49:01.064844933 -0400 @@ -0,0 +1,35 @@ +#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_LIST(_name) (&btrfs_attr_##_name.attr), + +#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) + +/* 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 | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 20 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) --- a/fs/btrfs/ctree.h 2013-09-16 13:49:06.656768298 -0400 +++ b/fs/btrfs/ctree.h 2013-09-16 13:49:25.464512784 -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-16 13:49:06.660768245 -0400 +++ b/fs/btrfs/super.c 2013-09-16 13:49:25.464512784 -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-16 13:49:06.668768135 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-16 13:49:25.464512784 -0400 @@ -27,6 +27,7 @@ #include "ctree.h" #include "disk-io.h" #include "transaction.h" +#include "sysfs.h" BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); @@ -67,8 +68,63 @@ static struct kobj_type btrfs_supp_feat_ .release = kobj_completion_release, }; +static struct attribute *btrfs_attrs[] = { + NULL, +}; + +#define super_kobj_to_fs_info(kobj) \ + container_of(kobj, struct btrfs_fs_info, super_kc.kc_kobj) + +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 = super_kobj_to_fs_info(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 = super_kobj_to_fs_info(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 = kobj_completion_release, +}; + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; + +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) +{ + int error; + + kobj_completion_init(&fs_info->super_kc, &btrfs_ktype); + fs_info->super_kc.kc_kobj.kset = btrfs_kset; + error = kobject_add(&fs_info->super_kc.kc_kobj, NULL, + "%pU", fs_info->fsid); + + return error; +} + +void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) +{ + kobj_completion_del_and_wait(&fs_info->super_kc); +} + static struct kobj_completion btrfs_features; int btrfs_init_sysfs(void) --- a/fs/btrfs/sysfs.h 2013-09-16 13:49:06.668768135 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-16 13:49:25.464512784 -0400 @@ -8,6 +8,25 @@ 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) +#define BTRFS_ATTR_LIST(_name) (&btrfs_attr_##_name.attr), + struct btrfs_feature_attr { struct attribute attr; /* global show, no store */ enum btrfs_feature_set feature_set; @@ -30,6 +49,7 @@ static struct btrfs_feature_attr btrfs_a BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) /* 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) #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 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 | 1 fs/btrfs/sysfs.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 2 - 3 files changed, 75 insertions(+), 1 deletion(-) --- a/fs/btrfs/ctree.h 2013-09-16 13:49:28.960465646 -0400 +++ b/fs/btrfs/ctree.h 2013-09-16 13:49:47.688214995 -0400 @@ -1513,6 +1513,7 @@ struct btrfs_fs_info { int thread_pool_size; struct kobj_completion super_kc; + struct kobj_completion features_kc; int do_barriers; int closing; int log_root_recovering; --- a/fs/btrfs/sysfs.c 2013-09-16 13:49:28.960465646 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-16 13:49:47.688214995 -0400 @@ -68,6 +68,39 @@ static struct kobj_type btrfs_supp_feat_ .release = kobj_completion_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); +} + +#define feat_kobj_to_fs_info(kobj) \ + container_of(kobj, struct btrfs_fs_info, features_kc.kc_kobj) +static ssize_t btrfs_feat_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct btrfs_fs_info *fs_info = feat_kobj_to_fs_info(kobj); + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + u64 features = get_features(fs_info, fa->feature_set); + + 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 = kobj_completion_release, +}; + static struct attribute *btrfs_attrs[] = { NULL, }; @@ -105,6 +138,26 @@ static struct kobj_type btrfs_ktype = { .release = kobj_completion_release, }; +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)) + continue; + + error = sysfs_create_file(&fs_info->features_kc.kc_kobj, + &fa->attr); + if (error) + return error; + } + return 0; +} + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; @@ -116,12 +169,32 @@ int btrfs_sysfs_add_one(struct btrfs_fs_ fs_info->super_kc.kc_kobj.kset = btrfs_kset; error = kobject_add(&fs_info->super_kc.kc_kobj, NULL, "%pU", fs_info->fsid); + if (error) + return error; + + kobj_completion_init(&fs_info->features_kc, &btrfs_feat_ktype); + error = kobject_add(&fs_info->features_kc.kc_kobj, + &fs_info->super_kc.kc_kobj, "features"); + if (error) + goto out_super; + + error = add_per_fs_features(fs_info); + if (error) + goto out_features; + + return 0; + +out_features: + kobj_completion_del_and_wait(&fs_info->features_kc); +out_super: + kobj_completion_del_and_wait(&fs_info->super_kc); return error; } void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { + kobj_completion_del_and_wait(&fs_info->features_kc); kobj_completion_del_and_wait(&fs_info->super_kc); } --- a/fs/btrfs/sysfs.h 2013-09-16 13:49:28.964465592 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-16 13:49:47.688214995 -0400 @@ -28,7 +28,7 @@ static struct btrfs_attr btrfs_attr_##_n #define BTRFS_ATTR_LIST(_name) (&btrfs_attr_##_name.attr), 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-16 18:19 UTC
[patch 7/9] 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 | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) --- a/fs/btrfs/sysfs.c 2013-09-10 15:58:32.209384497 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 15:58:32.645377839 -0400 @@ -68,6 +68,58 @@ static struct kobj_type btrfs_supp_feat_ .release = kobj_completion_release, }; +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 u64 get_features(struct btrfs_fs_info *fs_info, enum btrfs_feature_set set) { @@ -138,12 +190,12 @@ static struct kobj_type btrfs_ktype = { .release = kobj_completion_release, }; -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; @@ -158,6 +210,20 @@ 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; +} + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; @@ -207,6 +273,7 @@ int btrfs_init_sysfs(void) if (!btrfs_kset) return -ENOMEM; + init_feature_attrs(); kobj_completion_init(&btrfs_features, &btrfs_supp_feat_ktype); btrfs_features.kc_kobj.kset = btrfs_kset; ret = kobject_add(&btrfs_features.kc_kobj, NULL, "features"); -- 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:19 UTC
[patch 8/9] 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 | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) --- a/fs/btrfs/sysfs.c 2013-09-16 13:49:50.904172261 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-16 13:50:53.635355898 -0400 @@ -96,6 +96,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; @@ -115,6 +132,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''; } @@ -132,6 +150,18 @@ static u64 get_features(struct btrfs_fs_ return btrfs_super_incompat_flags(disk_super); } +static void set_features(struct btrfs_fs_info *fs_info, + enum btrfs_feature_set set, u64 features) +{ + struct btrfs_super_block *disk_super = fs_info->super_copy; + if (set == FEAT_COMPAT) + btrfs_set_super_compat_flags(disk_super, features); + else if (set == FEAT_COMPAT_RO) + btrfs_set_super_compat_ro_flags(disk_super, features); + else + btrfs_set_super_incompat_flags(disk_super, features); +} + #define feat_kobj_to_fs_info(kobj) \ container_of(kobj, struct btrfs_fs_info, features_kc.kc_kobj) static ssize_t btrfs_feat_show(struct kobject *kobj, struct attribute *attr, @@ -144,8 +174,72 @@ 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 = feat_kobj_to_fs_info(kobj); + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(attr); + struct btrfs_trans_handle *trans; + u64 features, set, clear; + unsigned long val; + int ret; + + 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; + } + + features = get_features(fs_info, fa->feature_set); + + /* 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); + features = get_features(fs_info, fa->feature_set); + if (val) + features |= fa->feature_bit; + else + features &= ~fa->feature_bit; + set_features(fs_info, fa->feature_set, features); + spin_unlock(&fs_info->super_lock); + + ret = btrfs_commit_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 = { @@ -199,7 +293,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)) continue; error = sysfs_create_file(&fs_info->features_kc.kc_kobj, -- 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:19 UTC
[patch 9/9] 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 | 2 ++ 3 files changed, 57 insertions(+), 5 deletions(-) --- a/fs/btrfs/ioctl.c 2013-09-10 16:04:57.067448432 -0400 +++ b/fs/btrfs/ioctl.c 2013-09-10 16:04:59.411411939 -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) @@ -4137,17 +4138,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; @@ -4155,7 +4166,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; @@ -4163,7 +4181,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; @@ -4173,7 +4198,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-10 16:04:57.067448432 -0400 +++ b/fs/btrfs/sysfs.c 2013-09-10 16:04:59.411411939 -0400 @@ -77,6 +77,31 @@ const char * const btrfs_feature_set_nam 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-10 16:04:57.067448432 -0400 +++ b/fs/btrfs/sysfs.h 2013-09-10 16:04:59.411411939 -0400 @@ -52,4 +52,6 @@ static struct btrfs_feature_attr btrfs_a #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) +char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); +extern const char * const 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-18 14:05 UTC
Re: [patch 1/9] btrfs: add ioctls to query/change feature bits online
On Mon, Sep 16, 2013 at 02:19:11PM -0400, Jeff Mahoney wrote:> +static int btrfs_ioctl_set_features(struct file *file, void __user *arg) > +{...> + trans = btrfs_start_transaction(root, 1);trans = btrfs_start_transaction(root, 0);> + if (IS_ERR(trans)) > + return PTR_ERR(trans);-- 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-18 14:14 UTC
Re: [patch 1/9] btrfs: add ioctls to query/change feature bits online
On Mon, Sep 16, 2013 at 02:19:11PM -0400, Jeff Mahoney wrote:> 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.Each feature bit being set online has to be treated separately regarding safety of the data in flight. You can set extended irefs online, there''s only one place where the bit is checked (if the hadlink count overflows the leaf), it''s ok to set the bit anytime before or after and it will not break anything. Skinny metadata bit is checked all over the place and I''m not sure it''s ok to set it on after some portion of data has been processed in the non-skinny mode. ''default_subvol'', lzo are ok, the rest depends on mkfs and can''t be modified online at all. So, for skinny metadata it''s most likely required to set the bit in a delayed manner and schedule it eg. to post-commit time. The sysfs and ioctl interface looks ok to me. david -- 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-18 14:29 UTC
Re: [patch 1/9] btrfs: add ioctls to query/change feature bits online
On 9/18/13 10:14 AM, David Sterba wrote:> On Mon, Sep 16, 2013 at 02:19:11PM -0400, Jeff Mahoney wrote: >> 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. > > Each feature bit being set online has to be treated separately regarding > safety of the data in flight. > > You can set extended irefs online, there''s only one place where the bit > is checked (if the hadlink count overflows the leaf), it''s ok to set the > bit anytime before or after and it will not break anything. > > Skinny metadata bit is checked all over the place and I''m not sure it''s > ok to set it on after some portion of data has been processed in the > non-skinny mode. > > ''default_subvol'', lzo are ok, the rest depends on mkfs and can''t be > modified online at all. > > So, for skinny metadata it''s most likely required to set the bit in a > delayed manner and schedule it eg. to post-commit time.Yep, that''s why extended_iref is the only one I''ve enabled so far. Other features with harder requirements are going to need to be handled explicitly.> The sysfs and ioctl interface looks ok to me.Great, thanks. -Jeff -- Jeff Mahoney SUSE Labs