summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ioctl.c35
-rw-r--r--fs/btrfs/sysfs.c33
-rw-r--r--fs/btrfs/sysfs.h2
3 files changed, 64 insertions, 6 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d4e105b..93b01fe 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -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)
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 7d340f3..562e346 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -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;
}
diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h
index 58c4b1f..c49fd25 100644
--- a/fs/btrfs/sysfs.h
+++ b/fs/btrfs/sysfs.h
@@ -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_ */
OpenPOWER on IntegriCloud