Introduce a new structure, extra_rw_degrade_errors, to record
devid<->error mapping.

This strucutre will have a array to record runtime error, which affects
degraded mount, like failure to flush or wait one device.

Also allow btrfs_check_rw_degradable() to accept such structure as
another error source other than btrfs_device->missing.

Signed-off-by: Qu Wenruo <[email protected]>
Tested-by: Austin S. Hemmelgarn <[email protected]>
Tested-by: Adam Borowski <[email protected]>
Tested-by: Dmitrii Tcvetkov <[email protected]>
---
 fs/btrfs/disk-io.c |  3 ++-
 fs/btrfs/super.c   |  2 +-
 fs/btrfs/volumes.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/btrfs/volumes.h | 36 ++++++++++++++++++++++++++++-
 4 files changed, 102 insertions(+), 5 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 3de89283d400..658b8fab1d39 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3058,7 +3058,8 @@ int open_ctree(struct super_block *sb,
                goto fail_sysfs;
        }
 
-       if (!(sb->s_flags & MS_RDONLY) && !btrfs_check_rw_degradable(fs_info)) {
+       if (!(sb->s_flags & MS_RDONLY) &&
+           !btrfs_check_rw_degradable(fs_info, NULL)) {
                btrfs_warn(fs_info,
                "writeable mount is not allowed due to too many missing 
devices");
                goto fail_sysfs;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 1f5772501c92..06bd9b332e18 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1785,7 +1785,7 @@ static int btrfs_remount(struct super_block *sb, int 
*flags, char *data)
                }
 
                if (!(*flags & MS_RDONLY) &&
-                   !btrfs_check_rw_degradable(fs_info)) {
+                   !btrfs_check_rw_degradable(fs_info, NULL)) {
                        btrfs_warn(fs_info,
                                "too many missing devices, writeable remount is 
not allowed");
                        ret = -EACCES;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 83613955e3c2..46cf676be15a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6765,13 +6765,72 @@ int btrfs_read_sys_array(struct btrfs_fs_info *fs_info)
        return -EIO;
 }
 
+void record_extra_rw_degrade_error(struct extra_rw_degrade_errors *errors,
+                                  u64 devid)
+{
+       int i;
+       bool inserted = false;
+
+       if (!errors)
+               return;
+
+       spin_lock(&errors->lock);
+       for (i = 0; i < errors->nr_devs; i++) {
+               struct rw_degrade_error *error = &errors->errors[i];
+
+               if (!error->initialized) {
+                       error->devid = devid;
+                       error->initialized = true;
+                       error->err = true;
+                       inserted = true;
+                       break;
+               }
+               if (error->devid == devid) {
+                       error->err = true;
+                       inserted = true;
+                       break;
+               }
+       }
+       spin_unlock(&errors->lock);
+       /*
+        * We iterate all the error records but still found no empty slot
+        * This means errors->nr_devs is not correct.
+        */
+       WARN_ON(!inserted);
+}
+
+static bool device_has_rw_degrade_error(struct extra_rw_degrade_errors *errors,
+                                       u64 devid)
+{
+       int i;
+       bool ret = false;
+
+       if (!errors)
+               return ret;
+
+       spin_lock(&errors->lock);
+       for (i = 0; i < errors->nr_devs; i++) {
+               struct rw_degrade_error *error = &errors->errors[i];
+
+               if (!error->initialized)
+                       break;
+               if (error->devid == devid) {
+                       ret = true;
+                       break;
+               }
+       }
+       spin_unlock(&errors->lock);
+       return ret;
+}
+
 /*
  * Check if all chunks in the fs is OK for read-write degraded mount
  *
  * Return true if the fs is OK to be mounted degraded read-write
  * Return false if the fs is not OK to be mounted degraded
  */
-bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info)
+bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
+                              struct extra_rw_degrade_errors *errors)
 {
        struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
        struct extent_map *em;
@@ -6797,7 +6856,10 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info 
*fs_info)
                        btrfs_get_num_tolerated_disk_barrier_failures(
                                        map->type);
                for (i = 0; i < map->num_stripes; i++) {
-                       if (map->stripes[i].dev->missing)
+                       struct btrfs_device *device = map->stripes[i].dev;
+
+                       if (device->missing ||
+                           device_has_rw_degrade_error(errors, device->devid))
                                missing++;
                }
                if (missing > max_tolerated) {
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index db1b5ef479cf..67d7474e42a3 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -538,5 +538,39 @@ struct list_head *btrfs_get_fs_uuids(void);
 void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
 void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
 
-bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info);
+/*
+ * For btrfs_check_rw_degradable() to check extra error from
+ * barrier_all_devices()
+ */
+struct rw_degrade_error {
+       u64 devid;
+       bool initialized;
+       bool err;
+};
+
+struct extra_rw_degrade_errors {
+       int nr_devs;
+       spinlock_t lock;
+       struct rw_degrade_error errors[];
+};
+
+static inline struct extra_rw_degrade_errors *alloc_extra_rw_degrade_errors(
+               int nr_devs)
+{
+       struct extra_rw_degrade_errors *ret;
+
+       ret = kzalloc(sizeof(struct extra_rw_degrade_errors) + nr_devs *
+                     sizeof(struct rw_degrade_error), GFP_NOFS);
+       if (!ret)
+               return ret;
+       spin_lock_init(&ret->lock);
+       ret->nr_devs = nr_devs;
+       return ret;
+}
+
+void record_extra_rw_degrade_error(struct extra_rw_degrade_errors *errors,
+                                  u64 devid);
+
+bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
+                              struct extra_rw_degrade_errors *errors);
 #endif
-- 
2.12.0



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to