btrfs: use feature attribute names to print better error messages
authorJeff Mahoney <jeffm@suse.com>
Fri, 1 Nov 2013 17:07:02 +0000 (13:07 -0400)
committerChris Mason <clm@fb.com>
Tue, 28 Jan 2014 21:19:28 +0000 (13:19 -0800)
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>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/ioctl.c
fs/btrfs/sysfs.c
fs/btrfs/sysfs.h

index d4e105b540917f0475e0f81e7b3d80e31e85d8a5..93b01fe6c73107e84e7283205b95d2faa6a4128d 100644 (file)
@@ -56,6 +56,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);
@@ -4516,17 +4517,27 @@ static int btrfs_ioctl_get_features(struct file *file, void __user *arg)
        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;
@@ -4534,7 +4545,14 @@ static int check_feature_bits(struct btrfs_root *root, const char *type,
 
        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;
@@ -4542,7 +4560,14 @@ static int check_feature_bits(struct btrfs_root *root, const char *type,
 
        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;
@@ -4552,7 +4577,7 @@ static int check_feature_bits(struct btrfs_root *root, const char *type,
 }
 
 #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)
index 7d340f352b7725406ca274386ebbb3e64d17c061..562e346994d93242abcfb69b16af4184eaf97c89 100644 (file)
@@ -254,6 +254,31 @@ const char * const btrfs_feature_set_names[3] = {
 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;
        }
index 58c4b1f689d662a131f46126a7149d622b7705fa..c49fd25c911fffde16157d8a936a13baa5c12bd5 100644 (file)
@@ -51,4 +51,6 @@ static struct btrfs_feature_attr btrfs_attr_##_name = {                            \
 #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_ */