Blob Blame History Raw
From: David Sterba <dsterba@suse.cz>
Date: Fri, 18 Jan 2013 00:28:40 +0100
Patch-mainline: Never, SLES-specific
References: fate#314697
Subject: [PATCH] btrfs: add allow_unsupported module parameter

Disallow access to filesystem with unsupported features by default but
leave a chance to access the filesystem via module parameter override
(taints kernel).

The status can be toggled during runtime by changing the exported module
parameter in /sys/module/btrfs/parameters/allow_unsupported.

Current:
- mount: inode_cache - deny mount
- mount: autodefrag - deny mount
- mount: raid56 - remount RO
- mount: seeding device - deny mount
- balance: use of raid56 taints kernel

fate#325563 - allow device replace

Signed-off-by: David Sterba <dsterba@suse.cz>
---

 fs/btrfs/ctree.h   |    8 ++++++++
 fs/btrfs/disk-io.c |   15 +++++++++++++++
 fs/btrfs/super.c   |   20 ++++++++++++++++++++
 3 files changed, 43 insertions(+)

--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -37,6 +37,7 @@
 #include <linux/sizes.h>
 #include <linux/dynamic_debug.h>
 #include <linux/refcount.h>
+#include <linux/unsupported-feature.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
@@ -3555,4 +3556,11 @@ static inline int btrfs_test_is_dummy_ro
 #endif
 	return 0;
 }
+
+/*
+ * Module parameter
+ */
+DECLARE_SUSE_UNSUPPORTED_FEATURE(btrfs)
+#define btrfs_allow_unsupported btrfs_allow_unsupported()
+
 #endif
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2797,6 +2797,14 @@ int open_ctree(struct super_block *sb,
 	if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
 		set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
 
+	if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING) {
+		if (!btrfs_allow_unsupported) {
+			printk(KERN_WARNING "btrfs: seeding mode is not supported, load module with allow_unsupported=1\n");
+			ret = -EOPNOTSUPP;
+			goto fail_alloc;
+		}
+	}
+
 	/*
 	 * run through our array of backup supers and setup
 	 * our ring pointer to the oldest one
@@ -2863,6 +2871,13 @@ int open_ctree(struct super_block *sb,
 		goto fail_alloc;
 	}
 
+	if (features & BTRFS_FEATURE_INCOMPAT_RAID56) {
+		if (!btrfs_allow_unsupported) {
+			printk(KERN_WARNING "btrfs: RAID56 is supported read-only, load module with allow_unsupported=1\n");
+			sb->s_flags |= MS_RDONLY;
+		}
+	}
+
 	/*
 	 * Needn't use the lock because there is no other task which will
 	 * update the flag.
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -18,6 +18,7 @@
 
 #include <linux/blkdev.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
@@ -64,6 +65,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
 
+DEFINE_SUSE_UNSUPPORTED_FEATURE(btrfs)
+
 static const struct super_operations btrfs_super_ops;
 static struct file_system_type btrfs_fs_type;
 
@@ -663,6 +666,11 @@ int btrfs_parse_options(struct btrfs_roo
 			}
 			break;
 		case Opt_inode_cache:
+			if (!btrfs_allow_unsupported) {
+				printk(KERN_WARNING "btrfs: inode_cache is not supported, load module with allow_unsupported=1\n");
+				ret = -EOPNOTSUPP;
+				break;
+			}
 			btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
 					   "enabling inode map caching");
 			break;
@@ -684,6 +692,11 @@ int btrfs_parse_options(struct btrfs_roo
 			btrfs_clear_opt(info->mount_opt, ENOSPC_DEBUG);
 			break;
 		case Opt_defrag:
+			if (!btrfs_allow_unsupported) {
+				printk(KERN_WARNING "btrfs: autodefrag is not supported, load module with allow_unsupported=1\n");
+				ret = -EOPNOTSUPP;
+				break;
+			}
 			btrfs_set_and_info(info, AUTO_DEFRAG,
 					   "enabling auto defrag");
 			break;
@@ -1758,6 +1771,13 @@ static int btrfs_remount(struct super_bl
 			ret = -EACCES;
 			goto restore;
 		}
+		if ((btrfs_super_incompat_flags(fs_info->super_copy)
+					& BTRFS_FEATURE_INCOMPAT_RAID56)
+				&& !btrfs_allow_unsupported) {
+			printk(KERN_WARNING "btrfs: cannot remount RW, RAID56 is supported read-only, load module with allow_unsupported=1\n");
+			ret = -EINVAL;
+			goto restore;
+		}
 
 		if (btrfs_super_log_root(fs_info->super_copy) != 0) {
 			ret = -EINVAL;