This patchset implements the stubbed-out sysfs interface for btrfs. Or at least begins to do so. We publish: - Features supported by the file system implementation - Features enabled on the file system, including features unknown to the implemenation. These attributes can also be used to enable or disable features at runtime, subjecting to a safety mask. - Uses the attribute names to print feature names when declining to mount a file system. - The allocation data: global metadata reservation size and reserved, space_infos, and sums of the block groups total and used bytes. - Device membership via links to the block devices. - FS label, which is writeable. - I''ve also added matching ioctls for some of the functionality here so that btrfsprogs can use the information without jumping through hoops to read/parse the sysfs files. There are ioctls to query the supported features and to query/set features on a particular file system. There''s also one to export the size of the global metadata reservation. I have a patch for btrfs-progs that uses this to print useful info in ''btrfs fi df'' output. Ultimately, the tree structure looks like the following, under /sys/fs/btrfs. This is from a test file system, using two devices in raid1. You''ll notice the ''single'' and ''raid1'' directories under the {data,metadata,system} dirs. The raid profiles are created and removed as the first/last block group of a certain profile is added and removed. v2: An earlier version had a chunk intended for fs/btrfs/extent-tree.c added as part of patch 13 instead of patch 10, causing build failures. v3: use static initialization for the GET_SUPPORTED_FEATURES ioctl. <fsid>/devices/sdc1 <fsid>/devices/sdd1 <fsid>/label <fsid>/allocation/data/flags <fsid>/allocation/data/raid1/used_bytes <fsid>/allocation/data/raid1/total_bytes <fsid>/allocation/data/bytes_pinned <fsid>/allocation/data/bytes_may_use <fsid>/allocation/data/total_bytes_pinned <fsid>/allocation/data/bytes_reserved <fsid>/allocation/data/bytes_used <fsid>/allocation/data/single/used_bytes <fsid>/allocation/data/single/total_bytes <fsid>/allocation/data/total_bytes <fsid>/allocation/data/disk_total <fsid>/allocation/data/disk_used <fsid>/allocation/metadata/flags <fsid>/allocation/metadata/raid1/used_bytes <fsid>/allocation/metadata/raid1/total_bytes <fsid>/allocation/metadata/bytes_pinned <fsid>/allocation/metadata/bytes_may_use <fsid>/allocation/metadata/total_bytes_pinned <fsid>/allocation/metadata/bytes_reserved <fsid>/allocation/metadata/bytes_used <fsid>/allocation/metadata/single/used_bytes <fsid>/allocation/metadata/single/total_bytes <fsid>/allocation/metadata/total_bytes <fsid>/allocation/metadata/disk_total <fsid>/allocation/metadata/disk_used <fsid>/allocation/global_rsv_size <fsid>/allocation/global_rsv_reserved <fsid>/allocation/system/flags <fsid>/allocation/system/raid1/used_bytes <fsid>/allocation/system/raid1/total_bytes <fsid>/allocation/system/bytes_pinned <fsid>/allocation/system/bytes_may_use <fsid>/allocation/system/total_bytes_pinned <fsid>/allocation/system/bytes_reserved <fsid>/allocation/system/bytes_used <fsid>/allocation/system/single/used_bytes <fsid>/allocation/system/single/total_bytes <fsid>/allocation/system/total_bytes <fsid>/allocation/system/disk_total <fsid>/allocation/system/disk_used <fsid>/features/mixed_backref <fsid>/features/extended_iref features/compress_lzo features/big_metadata features/compress_lzov2 features/default_subvol features/mixed_backref features/raid56 features/mixed_groups features/skinny_metadata features/extended_iref -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-Nov-15 20:33 UTC
[PATCH 01/13] 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 | 143 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 12 +++ 3 files changed, 164 insertions(+) --- a/fs/btrfs/ctree.h 2013-11-03 16:50:38.800686715 -0500 +++ b/fs/btrfs/ctree.h 2013-11-03 16:51:24.715977991 -0500 @@ -517,7 +517,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 | \ @@ -528,6 +533,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-11-03 16:50:43.464615049 -0500 +++ b/fs/btrfs/ioctl.c 2013-11-03 16:51:56.811492378 -0500 @@ -4492,6 +4492,142 @@ out_unlock: return ret; } +#define INIT_FEATURE_FLAGS(suffix) \ + { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \ + .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \ + .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix } + +static int btrfs_ioctl_get_supported_features(struct file *file, + void __user *arg) +{ + static struct btrfs_ioctl_feature_flags features[3] = { + INIT_FEATURE_FLAGS(SUPP), + INIT_FEATURE_FLAGS(SAFE_SET), + INIT_FEATURE_FLAGS(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) { @@ -4604,6 +4741,12 @@ long btrfs_ioctl(struct file *file, unsi return btrfs_ioctl_set_fslabel(file, argp); case BTRFS_IOC_FILE_EXTENT_SAME: return btrfs_ioctl_file_extent_same(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-11-03 16:50:38.800686715 -0500 +++ b/include/uapi/linux/btrfs.h 2013-11-03 16:51:23.563995855 -0500 @@ -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 @@ -606,5 +612,11 @@ static inline char *btrfs_err_str(enum b struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_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
struct kobj_attribute implements the baseline attribute functionality that can be used all over the place. We should export the ops associated with it. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- lib/kobject.c | 1 + 1 file changed, 1 insertion(+) --- a/lib/kobject.c 2013-10-21 16:09:51.868220920 -0400 +++ b/lib/kobject.c 2013-10-21 16:10:00.216037635 -0400 @@ -726,6 +726,7 @@ const struct sysfs_ops kobj_sysfs_ops .show = kobj_attr_show, .store = kobj_attr_store, }; +EXPORT_SYMBOL_GPL(kobj_sysfs_ops); /** * kset_register - initialize and add a 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-Nov-15 20:33 UTC
[PATCH 03/13] btrfs: publish supported featured in sysfs
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 | 44 ++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) --- a/fs/btrfs/sysfs.c 2013-10-21 16:09:52.760201346 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:09:59.816046422 -0400 @@ -26,20 +26,64 @@ #include "ctree.h" #include "disk-io.h" #include "transaction.h" +#include "sysfs.h" + +static ssize_t btrfs_feature_attr_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0\n"); +} + +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_supported_feature_attrs[] = { + BTRFS_FEAT_ATTR_PTR(mixed_backref), + BTRFS_FEAT_ATTR_PTR(default_subvol), + BTRFS_FEAT_ATTR_PTR(mixed_groups), + BTRFS_FEAT_ATTR_PTR(compress_lzo), + BTRFS_FEAT_ATTR_PTR(compress_lzov2), + BTRFS_FEAT_ATTR_PTR(big_metadata), + BTRFS_FEAT_ATTR_PTR(extended_iref), + BTRFS_FEAT_ATTR_PTR(raid56), + BTRFS_FEAT_ATTR_PTR(skinny_metadata), + NULL +}; + +static const struct attribute_group btrfs_feature_attr_group = { + .name = "features", + .attrs = btrfs_supported_feature_attrs, +}; /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; int btrfs_init_sysfs(void) { + int ret; btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); if (!btrfs_kset) return -ENOMEM; + + ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); + if (ret) { + kset_unregister(btrfs_kset); + return ret; + } + return 0; } void btrfs_exit_sysfs(void) { + sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); kset_unregister(btrfs_kset); } --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/fs/btrfs/sysfs.h 2013-10-21 16:09:59.816046422 -0400 @@ -0,0 +1,43 @@ +#ifndef _BTRFS_SYSFS_H_ +#define _BTRFS_SYSFS_H_ + +enum btrfs_feature_set { + FEAT_COMPAT, + FEAT_COMPAT_RO, + FEAT_INCOMPAT, + FEAT_MAX +}; + +#define __INIT_KOBJ_ATTR(_name, _mode, _show, _store) \ +{ \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +struct btrfs_feature_attr { + struct kobj_attribute kobj_attr; + 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 = { \ + .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ + btrfs_feature_attr_show, NULL), \ + .feature_set = _feature_set, \ + .feature_bit = _prefix ##_## _feature_bit, \ +} +#define BTRFS_FEAT_ATTR_PTR(_name) (&btrfs_attr_##_name.kobj_attr.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, kobj_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
Jeff Mahoney
2013-Nov-15 20:33 UTC
[PATCH 04/13] btrfs: publish per-super attributes in sysfs
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/disk-io.c | 9 +++++++++ fs/btrfs/sysfs.c | 36 ++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 10 ++++++++++ 4 files changed, 57 insertions(+) --- a/fs/btrfs/ctree.h 2013-10-21 16:30:27.122204722 -0400 +++ b/fs/btrfs/ctree.h 2013-10-21 16:30:39.390053476 -0400 @@ -3771,6 +3771,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/disk-io.c 2013-10-21 16:30:27.126204673 -0400 +++ b/fs/btrfs/disk-io.c 2013-10-21 16:30:39.394053427 -0400 @@ -49,6 +49,7 @@ #include "rcu-string.h" #include "dev-replace.h" #include "raid56.h" +#include "sysfs.h" #ifdef CONFIG_X86 #include <asm/cpufeature.h> @@ -2751,6 +2752,12 @@ retry_root_backup: btrfs_close_extra_devices(fs_info, fs_devices, 1); + ret = btrfs_sysfs_add_one(fs_info); + if (ret) { + pr_err("btrfs: failed to init sysfs interface: %d\n", ret); + goto fail_block_groups; + } + ret = btrfs_init_space_info(fs_info); if (ret) { printk(KERN_ERR "Failed to initial space info: %d\n", ret); @@ -3618,6 +3625,8 @@ int close_ctree(struct btrfs_root *root) btrfs_stop_all_workers(fs_info); + btrfs_sysfs_remove_one(fs_info); + del_fs_roots(fs_info); free_root_pointers(fs_info, 1); --- a/fs/btrfs/sysfs.c 2013-10-21 16:30:27.126204673 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:30:39.394053427 -0400 @@ -28,6 +28,25 @@ #include "transaction.h" #include "sysfs.h" +static void btrfs_release_super_kobj(struct kobject *kobj); +static struct kobj_type btrfs_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = btrfs_release_super_kobj, +}; + +static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) +{ + if (kobj->ktype != &btrfs_ktype) + return NULL; + return container_of(kobj, struct btrfs_fs_info, super_kobj); +} + +static void btrfs_release_super_kobj(struct kobject *kobj) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + complete(&fs_info->kobj_unregister); +} + static ssize_t btrfs_feature_attr_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { @@ -65,6 +84,23 @@ static const struct attribute_group btrf /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; +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); +} + +int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) +{ + int error; + + init_completion(&fs_info->kobj_unregister); + error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, + "%pU", fs_info->fsid); + return error; +} + int btrfs_init_sysfs(void) { int ret; --- a/fs/btrfs/sysfs.h 2013-10-21 16:30:27.126204673 -0400 +++ b/fs/btrfs/sysfs.h 2013-10-21 16:30:39.394053427 -0400 @@ -15,6 +15,13 @@ enum btrfs_feature_set { .store = _store, \ } +#define BTRFS_ATTR_RW(_name, _mode, _show, _store) \ +static struct kobj_attribute btrfs_attr_##_name = \ + __INIT_KOBJ_ATTR(_name, _mode, _show, _store) +#define BTRFS_ATTR(_name, _mode, _show) \ + BTRFS_ATTR_RW(_name, _mode, _show, NULL) +#define BTRFS_ATTR_PTR(_name) (&btrfs_attr_##_name.attr) + struct btrfs_feature_attr { struct kobj_attribute kobj_attr; enum btrfs_feature_set feature_set; @@ -40,4 +47,7 @@ static struct btrfs_feature_attr btrfs_a /* convert from attribute */ #define to_btrfs_feature_attr(a) \ container_of(a, struct btrfs_feature_attr, kobj_attr) +#define attr_to_btrfs_attr(a) container_of(a, struct kobj_attribute, attr) +#define attr_to_btrfs_feature_attr(a) \ + to_btrfs_feature_attr(attr_to_btrfs_attr(a)) #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
Jeff Mahoney
2013-Nov-15 20:33 UTC
[PATCH 05/13] btrfs: publish per-super features in sysfs
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/sysfs.c | 81 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 16 deletions(-) --- a/fs/btrfs/sysfs.c 2013-10-21 16:10:00.216037635 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:10:00.700027002 -0400 @@ -28,29 +28,53 @@ #include "transaction.h" #include "sysfs.h" -static void btrfs_release_super_kobj(struct kobject *kobj); -static struct kobj_type btrfs_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .release = btrfs_release_super_kobj, -}; +static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); -static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) +static u64 get_features(struct btrfs_fs_info *fs_info, + enum btrfs_feature_set set) { - if (kobj->ktype != &btrfs_ktype) - return NULL; - return container_of(kobj, struct btrfs_fs_info, super_kobj); + 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 void btrfs_release_super_kobj(struct kobject *kobj) +static ssize_t btrfs_feature_attr_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) { + int val = 0; struct btrfs_fs_info *fs_info = to_fs_info(kobj); - complete(&fs_info->kobj_unregister); + if (fs_info) { + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); + u64 features = get_features(fs_info, fa->feature_set); + if (features & fa->feature_bit) + val = 1; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", val); } -static ssize_t btrfs_feature_attr_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) +static umode_t btrfs_feature_visible(struct kobject *kobj, + struct attribute *attr, int unused) { - return snprintf(buf, PAGE_SIZE, "0\n"); + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + umode_t mode = attr->mode; + + if (fs_info) { + struct btrfs_feature_attr *fa; + u64 features; + + fa = attr_to_btrfs_feature_attr(attr); + features = get_features(fs_info, fa->feature_set); + + if (!(features & fa->feature_bit)) + mode = 0; + } + + return mode; } BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); @@ -78,11 +102,27 @@ static struct attribute *btrfs_supported static const struct attribute_group btrfs_feature_attr_group = { .name = "features", + .is_visible = btrfs_feature_visible, .attrs = btrfs_supported_feature_attrs, }; -/* /sys/fs/btrfs/ entry */ -static struct kset *btrfs_kset; +static void btrfs_release_super_kobj(struct kobject *kobj) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + complete(&fs_info->kobj_unregister); +} + +static struct kobj_type btrfs_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = btrfs_release_super_kobj, +}; + +static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) +{ + if (kobj->ktype != &btrfs_ktype) + return NULL; + return container_of(kobj, struct btrfs_fs_info, super_kobj); +} void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { @@ -91,13 +131,22 @@ void btrfs_sysfs_remove_one(struct btrfs wait_for_completion(&fs_info->kobj_unregister); } +/* /sys/fs/btrfs/ entry */ +static struct kset *btrfs_kset; + 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; error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, "%pU", fs_info->fsid); + + error = sysfs_create_group(&fs_info->super_kobj, + &btrfs_feature_attr_group); + if (error) + btrfs_sysfs_remove_one(fs_info); return 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-Nov-15 20:34 UTC
[PATCH 06/13] btrfs: publish unknown feature bits 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 | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) --- a/fs/btrfs/sysfs.c 2013-10-21 16:10:00.700027002 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:10:01.076018741 -0400 @@ -22,6 +22,7 @@ #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/kobject.h> +#include <linux/bug.h> #include "ctree.h" #include "disk-io.h" @@ -131,6 +132,101 @@ void btrfs_sysfs_remove_one(struct btrfs wait_for_completion(&fs_info->kobj_unregister); } +const char * const btrfs_feature_set_names[3] = { + [FEAT_COMPAT] = "compat", + [FEAT_COMPAT_RO] = "compat_ro", + [FEAT_INCOMPAT] = "incompat", +}; + +#define NUM_FEATURE_BITS 64 +static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13]; +static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS]; + +static void init_feature_attrs(void) +{ + struct btrfs_feature_attr *fa; + int set, i; + + BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !+ ARRAY_SIZE(btrfs_feature_attrs)); + BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !+ ARRAY_SIZE(btrfs_feature_attrs[0])); + + for (i = 0; btrfs_supported_feature_attrs[i]; i++) { + struct btrfs_feature_attr *sfa; + struct attribute *a = btrfs_supported_feature_attrs[i]; + sfa = attr_to_btrfs_feature_attr(a); + fa = &btrfs_feature_attrs[sfa->feature_set][sfa->feature_bit]; + + fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; + } + + for (set = 0; set < FEAT_MAX; set++) { + for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { + char *name = btrfs_unknown_feature_names[set][i]; + fa = &btrfs_feature_attrs[set][i]; + + if (fa->kobj_attr.attr.name) + continue; + + snprintf(name, 13, "%s:%u", + btrfs_feature_set_names[set], i); + + fa->kobj_attr.attr.name = name; + fa->kobj_attr.attr.mode = S_IRUGO; + fa->feature_set = set; + fa->feature_bit = 1ULL << i; + } + } +} + +static u64 supported_feature_masks[3] = { + [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP, + [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, + [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP, +}; + +static int add_unknown_feature_attrs(struct btrfs_fs_info *fs_info) +{ + int set; + + for (set = 0; set < FEAT_MAX; set++) { + int i, count, ret, index = 0; + struct attribute **attrs; + struct attribute_group agroup = { + .name = "features", + }; + u64 features = get_features(fs_info, set); + features &= ~supported_feature_masks[set]; + + count = hweight64(features); + + if (!count) + continue; + + attrs = kcalloc(count + 1, sizeof(void *), GFP_KERNEL); + + for (i = 0; i < NUM_FEATURE_BITS; i++) { + struct btrfs_feature_attr *fa; + + if (!(features & (1ULL << i))) + continue; + + fa = &btrfs_feature_attrs[set][i]; + attrs[index++] = &fa->kobj_attr.attr; + } + + attrs[index] = NULL; + agroup.attrs = attrs; + + ret = sysfs_merge_group(&fs_info->super_kobj, &agroup); + kfree(attrs); + if (ret) + return ret; + } + return 0; +} + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; @@ -146,7 +242,15 @@ int btrfs_sysfs_add_one(struct btrfs_fs_ error = sysfs_create_group(&fs_info->super_kobj, &btrfs_feature_attr_group); if (error) - btrfs_sysfs_remove_one(fs_info); + goto failure; + + error = add_unknown_feature_attrs(fs_info); + if (error) + goto failure; + + return 0; +failure: + btrfs_sysfs_remove_one(fs_info); return error; } @@ -157,6 +261,8 @@ int btrfs_init_sysfs(void) if (!btrfs_kset) return -ENOMEM; + init_feature_attrs(); + ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); 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-Nov-15 20:34 UTC
[PATCH 07/13] 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 | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- fs/btrfs/sysfs.h | 3 - 2 files changed, 117 insertions(+), 4 deletions(-) --- a/fs/btrfs/sysfs.c 2013-10-21 16:10:01.076018741 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:10:01.456010390 -0400 @@ -43,21 +43,131 @@ 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); +} + +static int can_modify_feature(struct btrfs_feature_attr *fa) +{ + int val = 0; + u64 set, clear; + switch (fa->feature_set) { + case FEAT_COMPAT: + set = BTRFS_FEATURE_COMPAT_SAFE_SET; + clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; + break; + case FEAT_COMPAT_RO: + set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; + clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; + break; + case FEAT_INCOMPAT: + set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; + clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; + break; + default: + BUG(); + } + + if (set & fa->feature_bit) + val |= 1; + if (clear & fa->feature_bit) + val |= 2; + + return val; +} + static ssize_t btrfs_feature_attr_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { int val = 0; struct btrfs_fs_info *fs_info = to_fs_info(kobj); + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); if (fs_info) { - struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); u64 features = get_features(fs_info, fa->feature_set); if (features & fa->feature_bit) val = 1; - } + } else + val = can_modify_feature(fa); return snprintf(buf, PAGE_SIZE, "%d\n", val); } +static ssize_t btrfs_feature_attr_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t count) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); + struct btrfs_trans_handle *trans; + u64 features, set, clear; + unsigned long val; + int ret; + + fs_info = to_fs_info(kobj); + if (!fs_info) + return -EPERM; + + 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->kobj_attr.attr.name); + return -EPERM; + } + + btrfs_info(fs_info, "%s %s feature flag", + val ? "Setting" : "Clearing", fa->kobj_attr.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 umode_t btrfs_feature_visible(struct kobject *kobj, struct attribute *attr, int unused) { @@ -71,7 +181,9 @@ static umode_t btrfs_feature_visible(str fa = attr_to_btrfs_feature_attr(attr); features = get_features(fs_info, fa->feature_set); - if (!(features & fa->feature_bit)) + if (can_modify_feature(fa)) + mode |= S_IWUSR; + else if (!(features & fa->feature_bit)) mode = 0; } --- a/fs/btrfs/sysfs.h 2013-10-21 16:10:00.216037635 -0400 +++ b/fs/btrfs/sysfs.h 2013-10-21 16:10:01.460010303 -0400 @@ -31,7 +31,8 @@ struct btrfs_feature_attr { #define BTRFS_FEAT_ATTR(_name, _feature_set, _prefix, _feature_bit) \ static struct btrfs_feature_attr btrfs_attr_##_name = { \ .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ - btrfs_feature_attr_show, NULL), \ + btrfs_feature_attr_show, \ + btrfs_feature_attr_store), \ .feature_set = _feature_set, \ .feature_bit = _prefix ##_## _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-Nov-15 20:34 UTC
[PATCH 08/13] 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 | 33 ++++++++++++++++++++++++++++++++- fs/btrfs/sysfs.h | 2 ++ 3 files changed, 64 insertions(+), 6 deletions(-) --- a/fs/btrfs/ioctl.c 2013-10-21 16:09:48.844287259 -0400 +++ b/fs/btrfs/ioctl.c 2013-10-21 16:10:01.856001602 -0400 @@ -57,6 +57,7 @@ #include "rcu-string.h" #include "send.h" #include "dev-replace.h" +#include "sysfs.h" static int btrfs_clone(struct inode *src, struct inode *inode, u64 off, u64 olen, u64 olen_aligned, u64 destoff); @@ -4531,17 +4532,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; @@ -4549,7 +4560,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; @@ -4557,7 +4575,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; @@ -4567,7 +4592,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-10-21 16:10:01.456010390 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:10:01.856001602 -0400 @@ -254,6 +254,31 @@ const char * const btrfs_feature_set_nam static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13]; static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS]; +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++) { + const char *name; + + if (!(flags & (1ULL << i))) + continue; + + name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; + len += snprintf(str + len, bufsize - len, "%s%s", + len ? "," : "", name); + } + + return str; +} + static void init_feature_attrs(void) { struct btrfs_feature_attr *fa; @@ -264,11 +289,17 @@ static void init_feature_attrs(void) BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) ! ARRAY_SIZE(btrfs_feature_attrs[0])); + memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); + memset(btrfs_unknown_feature_names, 0, + sizeof(btrfs_unknown_feature_names)); + for (i = 0; btrfs_supported_feature_attrs[i]; i++) { struct btrfs_feature_attr *sfa; struct attribute *a = btrfs_supported_feature_attrs[i]; + int bit; sfa = attr_to_btrfs_feature_attr(a); - fa = &btrfs_feature_attrs[sfa->feature_set][sfa->feature_bit]; + bit = ilog2(sfa->feature_bit); + fa = &btrfs_feature_attrs[sfa->feature_set][bit]; fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; } --- a/fs/btrfs/sysfs.h 2013-10-21 16:10:01.460010303 -0400 +++ b/fs/btrfs/sysfs.h 2013-10-21 16:10:01.860001514 -0400 @@ -51,4 +51,6 @@ static struct btrfs_feature_attr btrfs_a #define attr_to_btrfs_attr(a) container_of(a, struct kobj_attribute, attr) #define attr_to_btrfs_feature_attr(a) \ to_btrfs_feature_attr(attr_to_btrfs_attr(a)) +char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); +extern const char * const btrfs_feature_set_names[3]; #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
Jeff Mahoney
2013-Nov-15 20:34 UTC
[PATCH 09/13] btrfs: add ioctl to export size of global metadata reservation
btrfs filesystem df output will show the size of the metadata space and how much of it is used, and the user assumes that the difference is all usable space. Since that''s not actually the case due to the global metadata reservation, we should provide the full picture to the user. This patch adds an ioctl that exports the size of the global metadata reservation so that btrfs filesystem df can report it. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ioctl.c | 16 ++++++++++++++++ include/uapi/linux/btrfs.h | 1 + 2 files changed, 17 insertions(+) --- a/fs/btrfs/ioctl.c 2013-10-21 16:10:01.856001602 -0400 +++ b/fs/btrfs/ioctl.c 2013-10-21 16:10:02.295991933 -0400 @@ -3511,6 +3511,20 @@ out: return ret; } +static long btrfs_ioctl_global_rsv(struct btrfs_root *root, void __user *arg) +{ + struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv; + u64 reserved; + + spin_lock(&block_rsv->lock); + reserved = block_rsv->reserved; + spin_unlock(&block_rsv->lock); + + if (arg && copy_to_user(arg, &reserved, sizeof(reserved))) + return -EFAULT; + return 0; +} + /* * there are many ways the trans_start and trans_end ioctls can lead * to deadlocks. They should only be used by applications that @@ -4721,6 +4735,8 @@ long btrfs_ioctl(struct file *file, unsi return btrfs_ioctl_logical_to_ino(root, argp); case BTRFS_IOC_SPACE_INFO: return btrfs_ioctl_space_info(root, argp); + case BTRFS_IOC_GLOBAL_RSV: + return btrfs_ioctl_global_rsv(root, argp); case BTRFS_IOC_SYNC: btrfs_sync_fs(file->f_dentry->d_sb, 1); return 0; --- a/include/uapi/linux/btrfs.h 2013-10-21 16:09:44.804375840 -0400 +++ b/include/uapi/linux/btrfs.h 2013-10-21 16:10:02.343990878 -0400 @@ -558,6 +558,7 @@ static inline char *btrfs_err_str(enum b #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ struct btrfs_ioctl_space_args) +#define BTRFS_IOC_GLOBAL_RSV _IOR(BTRFS_IOCTL_MAGIC, 20, __u64) #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ -- 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
While trying to debug ENOSPC issues, it''s helpful to understand what the kernel''s view of the available space is. We export this information via ioctl, but sysfs files are more easily used. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ctree.h | 5 + fs/btrfs/extent-tree.c | 82 +++++++++++++++++++++++++-- fs/btrfs/sysfs.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/sysfs.h | 8 ++ 4 files changed, 238 insertions(+), 5 deletions(-) --- a/fs/btrfs/ctree.h 2013-10-22 15:18:47.556418952 -0400 +++ b/fs/btrfs/ctree.h 2013-10-29 14:50:39.900733692 -0400 @@ -1143,6 +1143,9 @@ struct btrfs_space_info { spinlock_t lock; struct rw_semaphore groups_sem; wait_queue_head_t wait; + + struct kobject kobj; + struct kobject block_group_kobjs[BTRFS_NR_RAID_TYPES]; }; #define BTRFS_BLOCK_RSV_GLOBAL 1 @@ -1518,6 +1521,7 @@ struct btrfs_fs_info { int thread_pool_size; struct kobject super_kobj; + struct kobject *space_info_kobj; struct completion kobj_unregister; int do_barriers; int closing; @@ -3171,6 +3175,7 @@ struct btrfs_block_group_cache *btrfs_lo struct btrfs_fs_info *info, u64 bytenr); void btrfs_put_block_group(struct btrfs_block_group_cache *cache); +int get_block_group_index(struct btrfs_block_group_cache *cache); struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 blocksize, u64 parent, u64 root_objectid, --- a/fs/btrfs/extent-tree.c 2013-10-19 15:28:15.000000000 -0400 +++ b/fs/btrfs/extent-tree.c 2013-10-29 14:50:42.884608970 -0400 @@ -36,6 +36,7 @@ #include "locking.h" #include "free-space-cache.h" #include "math.h" +#include "sysfs.h" #undef SCRAMBLE_DELAYED_REFS @@ -3389,6 +3390,23 @@ int btrfs_extent_readonly(struct btrfs_r return readonly; } +static const char *alloc_name(u64 flags) +{ + switch (flags) { + case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA: + return "mixed"; + case BTRFS_BLOCK_GROUP_METADATA: + return "metadata"; + case BTRFS_BLOCK_GROUP_DATA: + return "data"; + case BTRFS_BLOCK_GROUP_SYSTEM: + return "system"; + default: + WARN_ON(1); + return "invalid-combination"; + }; +} + static int update_space_info(struct btrfs_fs_info *info, u64 flags, u64 total_bytes, u64 bytes_used, struct btrfs_space_info **space_info) @@ -3444,11 +3462,21 @@ static int update_space_info(struct btrf found->chunk_alloc = 0; found->flush = 0; init_waitqueue_head(&found->wait); + + ret = kobject_init_and_add(&found->kobj, &space_info_ktype, + info->space_info_kobj, "%s", + alloc_name(found->flags)); + if (ret) { + kfree(found); + return ret; + } + *space_info = found; list_add_rcu(&found->list, &info->space_info); if (flags & BTRFS_BLOCK_GROUP_DATA) info->data_sinfo = found; - return 0; + + return ret; } static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) @@ -6090,11 +6118,29 @@ int __get_raid_index(u64 flags) return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */ } -static int get_block_group_index(struct btrfs_block_group_cache *cache) +int get_block_group_index(struct btrfs_block_group_cache *cache) { return __get_raid_index(cache->flags); } +static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = { + [BTRFS_RAID_RAID10] = "raid10", + [BTRFS_RAID_RAID1] = "raid1", + [BTRFS_RAID_DUP] = "dup", + [BTRFS_RAID_RAID0] = "raid0", + [BTRFS_RAID_SINGLE] = "single", + [BTRFS_RAID_RAID5] = "raid5", + [BTRFS_RAID_RAID6] = "raid6", +}; + +const char *get_raid_name(enum btrfs_raid_types type) +{ + if (type >= BTRFS_NR_RAID_TYPES) + return NULL; + + return btrfs_raid_type_names[type]; +} + enum btrfs_loop_type { LOOP_CACHING_NOWAIT = 0, LOOP_CACHING_WAIT = 1, @@ -8272,6 +8318,8 @@ int btrfs_free_block_groups(struct btrfs release_global_block_rsv(info); while(!list_empty(&info->space_info)) { + int i; + space_info = list_entry(info->space_info.next, struct btrfs_space_info, list); @@ -8283,9 +8331,17 @@ int btrfs_free_block_groups(struct btrfs dump_space_info(space_info, 0, 0); } } - percpu_counter_destroy(&space_info->total_bytes_pinned); list_del(&space_info->list); - kfree(space_info); + for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { + struct kobject *kobj; + kobj = &space_info->block_group_kobjs[i]; + if (kobj->parent) { + kobject_del(kobj); + kobject_put(kobj); + } + } + kobject_del(&space_info->kobj); + kobject_put(&space_info->kobj); } return 0; } @@ -8296,6 +8352,19 @@ static void __link_block_group(struct bt int index = get_block_group_index(cache); down_write(&space_info->groups_sem); + if (list_empty(&space_info->block_groups[index])) { + struct kobject *kobj = &space_info->block_group_kobjs[index]; + int ret; + + kobject_get(&space_info->kobj); /* put in release */ + ret = kobject_init_and_add(kobj, &btrfs_raid_ktype, + &space_info->kobj, + get_raid_name(index)); + if (ret) { + pr_warn("btrfs: failed to add kobject for block cache. ignoring.\n"); + kobject_put(&space_info->kobj); + } + } list_add_tail(&cache->list, &space_info->block_groups[index]); up_write(&space_info->groups_sem); } @@ -8736,8 +8805,11 @@ int btrfs_remove_block_group(struct btrf * are still on the list after taking the semaphore */ list_del_init(&block_group->list); - if (list_empty(&block_group->space_info->block_groups[index])) + if (list_empty(&block_group->space_info->block_groups[index])) { + kobject_del(&block_group->space_info->block_group_kobjs[index]); + kobject_put(&block_group->space_info->block_group_kobjs[index]); clear_avail_alloc_bits(root->fs_info, block_group->flags); + } up_write(&block_group->space_info->groups_sem); if (block_group->cached == BTRFS_CACHE_STARTED) --- a/fs/btrfs/sysfs.c 2013-10-22 15:18:47.708416558 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-29 14:50:39.900733692 -0400 @@ -219,6 +219,140 @@ static const struct attribute_group btrf .attrs = btrfs_supported_feature_attrs, }; +static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) +{ + u64 val; + if (lock) + spin_lock(lock); + val = *value_ptr; + if (lock) + spin_unlock(lock); + return snprintf(buf, PAGE_SIZE, "%llu\n", val); +} + +static ssize_t global_rsv_size_show(struct kobject *kobj, + struct kobj_attribute *ka, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; + return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); +} +BTRFS_ATTR(global_rsv_size, 0444, global_rsv_size_show); + +static ssize_t global_rsv_reserved_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; + return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); +} +BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show); + +#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) + +static ssize_t raid_bytes_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +BTRFS_RAID_ATTR(total_bytes, raid_bytes_show); +BTRFS_RAID_ATTR(used_bytes, raid_bytes_show); + +static ssize_t raid_bytes_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) + +{ + struct btrfs_space_info *sinfo = to_space_info(kobj->parent); + struct btrfs_block_group_cache *block_group; + int index = kobj - sinfo->block_group_kobjs; + u64 val = 0; + + down_read(&sinfo->groups_sem); + list_for_each_entry(block_group, &sinfo->block_groups[index], list) { + if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes)) + val += block_group->key.offset; + else + val += btrfs_block_group_used(&block_group->item); + } + up_read(&sinfo->groups_sem); + return snprintf(buf, PAGE_SIZE, "%llu\n", val); +} + +static struct attribute *raid_attributes[] = { + BTRFS_RAID_ATTR_PTR(total_bytes), + BTRFS_RAID_ATTR_PTR(used_bytes), + NULL +}; + +static void release_raid_kobj(struct kobject *kobj) +{ + kobject_put(kobj->parent); +} + +struct kobj_type btrfs_raid_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = release_raid_kobj, + .default_attrs = raid_attributes, +}; + +#define SPACE_INFO_ATTR(field) \ +static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \ + struct kobj_attribute *a, \ + char *buf) \ +{ \ + struct btrfs_space_info *sinfo = to_space_info(kobj); \ + return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \ +} \ +BTRFS_ATTR(field, 0444, btrfs_space_info_show_##field) + +static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_space_info *sinfo = to_space_info(kobj); + s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); + return snprintf(buf, PAGE_SIZE, "%lld\n", val); +} + +SPACE_INFO_ATTR(flags); +SPACE_INFO_ATTR(total_bytes); +SPACE_INFO_ATTR(bytes_used); +SPACE_INFO_ATTR(bytes_pinned); +SPACE_INFO_ATTR(bytes_reserved); +SPACE_INFO_ATTR(bytes_may_use); +SPACE_INFO_ATTR(disk_used); +SPACE_INFO_ATTR(disk_total); +BTRFS_ATTR(total_bytes_pinned, 0444, btrfs_space_info_show_total_bytes_pinned); + +static struct attribute *space_info_attrs[] = { + BTRFS_ATTR_PTR(flags), + BTRFS_ATTR_PTR(total_bytes), + BTRFS_ATTR_PTR(bytes_used), + BTRFS_ATTR_PTR(bytes_pinned), + BTRFS_ATTR_PTR(bytes_reserved), + BTRFS_ATTR_PTR(bytes_may_use), + BTRFS_ATTR_PTR(disk_used), + BTRFS_ATTR_PTR(disk_total), + BTRFS_ATTR_PTR(total_bytes_pinned), + NULL, +}; + +static void space_info_release(struct kobject *kobj) +{ + struct btrfs_space_info *sinfo = to_space_info(kobj); + percpu_counter_destroy(&sinfo->total_bytes_pinned); + kfree(sinfo); +} + +struct kobj_type space_info_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = space_info_release, + .default_attrs = space_info_attrs, +}; + +static const struct attribute *allocation_attrs[] = { + BTRFS_ATTR_PTR(global_rsv_reserved), + BTRFS_ATTR_PTR(global_rsv_size), + NULL, +}; + static void btrfs_release_super_kobj(struct kobject *kobj) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); @@ -239,6 +373,9 @@ static inline struct btrfs_fs_info *to_f void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { + sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); + kobject_del(fs_info->space_info_kobj); + kobject_put(fs_info->space_info_kobj); kobject_del(&fs_info->super_kobj); kobject_put(&fs_info->super_kobj); wait_for_completion(&fs_info->kobj_unregister); @@ -391,6 +528,17 @@ int btrfs_sysfs_add_one(struct btrfs_fs_ if (error) goto failure; + fs_info->space_info_kobj = kobject_create_and_add("allocation", + &fs_info->super_kobj); + if (!fs_info->space_info_kobj) { + error = -ENOMEM; + goto failure; + } + + error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); + if (error) + goto failure; + return 0; failure: btrfs_sysfs_remove_one(fs_info); --- a/fs/btrfs/sysfs.h 2013-10-22 15:18:47.708416558 -0400 +++ b/fs/btrfs/sysfs.h 2013-10-22 15:18:47.916413282 -0400 @@ -22,6 +22,12 @@ static struct kobj_attribute btrfs_attr_ BTRFS_ATTR_RW(_name, _mode, _show, NULL) #define BTRFS_ATTR_PTR(_name) (&btrfs_attr_##_name.attr) +#define BTRFS_RAID_ATTR(_name, _show) \ +static struct kobj_attribute btrfs_raid_attr_##_name = \ + __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) +#define BTRFS_RAID_ATTR_PTR(_name) (&btrfs_raid_attr_##_name.attr) + + struct btrfs_feature_attr { struct kobj_attribute kobj_attr; enum btrfs_feature_set feature_set; @@ -53,4 +59,6 @@ static struct btrfs_feature_attr btrfs_a to_btrfs_feature_attr(attr_to_btrfs_attr(a)) char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); extern const char * const btrfs_feature_set_names[3]; +extern struct kobj_type space_info_ktype; +extern struct kobj_type btrfs_raid_ktype; #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
Jeff Mahoney
2013-Nov-15 20:34 UTC
[PATCH 11/13] btrfs: publish device membership in sysfs
Now that we have the infrastructure for per-super attributes, we can publish device membership in /sys/fs/btrfs/<fsid>/devices. The information is published as symlinks to the block devices. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/ctree.h | 1 + fs/btrfs/sysfs.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) --- a/fs/btrfs/ctree.h 2013-10-21 16:10:02.743982088 -0400 +++ b/fs/btrfs/ctree.h 2013-10-21 16:10:03.223971538 -0400 @@ -1522,6 +1522,7 @@ struct btrfs_fs_info { struct kobject super_kobj; struct kobject *space_info_kobj; + struct kobject *device_dir_kobj; struct completion kobj_unregister; int do_barriers; int closing; --- a/fs/btrfs/sysfs.c 2013-10-21 16:10:02.751981911 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:10:03.227971451 -0400 @@ -23,11 +23,13 @@ #include <linux/buffer_head.h> #include <linux/kobject.h> #include <linux/bug.h> +#include <linux/genhd.h> #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "sysfs.h" +#include "volumes.h" static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); @@ -374,6 +376,8 @@ static inline struct btrfs_fs_info *to_f void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) { sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); + kobject_del(fs_info->device_dir_kobj); + kobject_put(fs_info->device_dir_kobj); kobject_del(fs_info->space_info_kobj); kobject_put(fs_info->space_info_kobj); kobject_del(&fs_info->super_kobj); @@ -507,6 +511,30 @@ static int add_unknown_feature_attrs(str return 0; } +static int add_device_membership(struct btrfs_fs_info *fs_info) +{ + int error = 0; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + struct btrfs_device *dev; + + fs_info->device_dir_kobj = kobject_create_and_add("devices", + &fs_info->super_kobj); + if (!fs_info->device_dir_kobj) + return -ENOMEM; + + list_for_each_entry(dev, &fs_devices->devices, dev_list) { + struct hd_struct *disk = dev->bdev->bd_part; + struct kobject *disk_kobj = &part_to_dev(disk)->kobj; + + error = sysfs_create_link(fs_info->device_dir_kobj, + disk_kobj, disk_kobj->name); + if (error) + break; + } + + return error; +} + /* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; @@ -528,6 +556,10 @@ int btrfs_sysfs_add_one(struct btrfs_fs_ if (error) goto failure; + error = add_device_membership(fs_info); + if (error) + goto failure; + fs_info->space_info_kobj = kobject_create_and_add("allocation", &fs_info->super_kobj); if (!fs_info->space_info_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
This adds a writeable attribute which describes the label. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/sysfs.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) --- a/fs/btrfs/sysfs.c 2013-10-21 16:20:06.395804741 -0400 +++ b/fs/btrfs/sysfs.c 2013-10-21 16:23:57.402255196 -0400 @@ -355,6 +355,49 @@ static const struct attribute *allocatio NULL, }; +static ssize_t btrfs_label_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%s\n", fs_info->super_copy->label); +} + +static ssize_t btrfs_label_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + struct btrfs_trans_handle *trans; + struct btrfs_root *root = fs_info->fs_root; + int ret; + + if (len >= BTRFS_LABEL_SIZE) { + pr_err("btrfs: unable to set label with more than %d bytes\n", + BTRFS_LABEL_SIZE - 1); + return -EINVAL; + } + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + spin_lock(&root->fs_info->super_lock); + strcpy(fs_info->super_copy->label, buf); + spin_unlock(&root->fs_info->super_lock); + ret = btrfs_commit_transaction(trans, root); + + if (!ret) + return len; + + return ret; +} +BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store); + +static struct attribute *btrfs_attrs[] = { + BTRFS_ATTR_PTR(label), + NULL, +}; + static void btrfs_release_super_kobj(struct kobject *kobj) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); @@ -364,6 +407,7 @@ static void btrfs_release_super_kobj(str static struct kobj_type btrfs_ktype = { .sysfs_ops = &kobj_sysfs_ops, .release = btrfs_release_super_kobj, + .default_attrs = btrfs_attrs, }; static inline struct btrfs_fs_info *to_fs_info(struct kobject *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-Nov-15 20:34 UTC
[PATCH 13/13] btrfs: add tracing for failed reservations
When debugging ENOSPC issues, it''s nice to be able to see which reservations failed as well as the ones which succeeded. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/extent-tree.c | 7 +++++++ 1 file changed, 7 insertions(+) --- a/fs/btrfs/extent-tree.c 2013-11-03 16:53:15.466324826 -0500 +++ b/fs/btrfs/extent-tree.c 2013-11-03 16:53:15.550323570 -0500 @@ -3709,6 +3709,9 @@ commit_trans: goto again; } + trace_btrfs_space_reservation(root->fs_info, + "space_info:enospc", + data_sinfo->flags, bytes, 1); return -ENOSPC; } data_sinfo->bytes_may_use += bytes; @@ -4360,6 +4363,10 @@ out: !block_rsv_use_bytes(global_rsv, orig_bytes)) ret = 0; } + if (ret == -ENOSPC) + trace_btrfs_space_reservation(root->fs_info, + "space_info:enospc", + space_info->flags, orig_bytes, 1); if (flushing) { spin_lock(&space_info->lock); space_info->flush = 0; -- 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