@@ -2722,6 +2722,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
INIT_LIST_HEAD(&fs_info->allocated_roots);
INIT_LIST_HEAD(&fs_info->allocated_ebs);
spin_lock_init(&fs_info->eb_leak_lock);
+ fs_info->allow_backup_super_failure = true;
#endif
extent_map_tree_init(&fs_info->mapping_tree);
btrfs_init_block_rsv(&fs_info->global_block_rsv,
@@ -3841,8 +3842,10 @@ static int write_dev_supers(struct btrfs_device *device,
*/
static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
{
+ struct btrfs_fs_info *fs_info = device->fs_info;
int i;
int errors = 0;
+ bool allow_super_failure = READ_ONCE(fs_info->allow_backup_super_failure);
bool primary_failed = false;
int ret;
u64 bytenr;
@@ -3890,8 +3893,8 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
}
/* log error, force error return */
- if (primary_failed) {
- btrfs_err(device->fs_info, "error writing primary super block to device %llu",
+ if (primary_failed || (!allow_super_failure && errors)) {
+ btrfs_err(device->fs_info, "error writing super block to device %llu",
device->devid);
return -1;
}
@@ -685,6 +685,9 @@ struct btrfs_fs_info {
struct btrfs_work qgroup_rescan_work;
/* Protected by qgroup_rescan_lock */
bool qgroup_rescan_running;
+
+ /* If we allow backup superblocks writeback to fail. */
+ bool allow_backup_super_failure;
u8 qgroup_drop_subtree_thres;
/*
@@ -614,12 +614,49 @@ static const struct attribute *discard_attrs[] = {
#ifdef CONFIG_BTRFS_DEBUG
+static ssize_t allow_backup_super_failure_show(struct kobject *debug_kobj,
+ struct kobj_attribute *a,
+ char *buf)
+{
+ struct btrfs_fs_info *fs_info = to_fs_info(debug_kobj->parent);
+
+ ASSERT(fs_info);
+ return sysfs_emit(buf, "%d\n",
+ READ_ONCE(fs_info->allow_backup_super_failure));
+}
+
+static ssize_t allow_backup_super_failure_store(struct kobject *debug_kobj,
+ struct kobj_attribute *a,
+ const char *buf, size_t len)
+{
+ struct btrfs_fs_info *fs_info = to_fs_info(debug_kobj->parent);
+ u8 new_number;
+ int ret;
+
+ ASSERT(fs_info);
+
+ ret = kstrtos8(buf, 10, &new_number);
+ if (ret)
+ return -EINVAL;
+ WRITE_ONCE(fs_info->allow_backup_super_failure, !!new_number);
+ return len;
+}
+BTRFS_ATTR_RW(debug, allow_backup_super_failure, allow_backup_super_failure_show,
+ allow_backup_super_failure_store);
+
/*
* Per-filesystem runtime debugging exported via sysfs.
*
* Path: /sys/fs/btrfs/UUID/debug/
+ *
+ * - allow_backup_super_failure
+ * RW, binary (0/1), determins if we allow backup superblock writeback to fail.
+ *
+ * NOTE: Even with this set to 1, btrfs may still allow some errors to
+ * happen as btrfs can tolerate up to "rw_devs - 1" failures.
*/
static const struct attribute *btrfs_debug_mount_attrs[] = {
+ BTRFS_ATTR_PTR(debug, allow_backup_super_failure),
NULL,
};
Currently btrfs allows the backup super block to fail its writeback, as long as the primary one is still fine. This tolerance may be a little too loose for some debug purposes, thus this patch would introduce the following sysfs interface: /sys/fs/btrfs/<uuid>/debug/allow_backup_super_failure Which is a read-write entry, its content is 0/1, indicating if we allow backup super blocks to fail its writeback. The default value is 1, meaning we allow backup super blocks to fail its writeback. Writing anything but 0 would set the value to 1. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/disk-io.c | 7 +++++-- fs/btrfs/fs.h | 3 +++ fs/btrfs/sysfs.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-)