From: Anand Jain <anand.j...@oracle.com>

When FS in unmounted we need to check generation number as well
since devid+uuid combination could match with the missing replaced
disk when it reappears, and without this patch it might pair with
the replaced disk again.

 device_list_add() function is called in the following threads,
        mount device option
        mount argument
        ioctl BTRFS_IOC_SCAN_DEV (btrfs dev scan)
        ioctl BTRFS_IOC_DEVICES_READY (btrfs dev ready <dev>)
 they have been unit tested to work fine with this patch.

 If the user knows what he is doing and really want to pair with
 replaced disk (which is not a standard operation), then he should
 first clear the kernel btrfs device list in the memory by doing
 the module unload/load and followed with the mount -o device option.

Signed-off-by: Anand Jain <anand.j...@oracle.com>
Signed-off-by: Wang Shilong <wangsl.f...@cn.fujitsu.com>
Signed-off-by: Miao Xie <mi...@cn.fujitsu.com>
---
Changelog v1->v2:
- Fix the over-80-charactor problem and unreasonable error number
---
 fs/btrfs/volumes.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 16e71a1..1891541 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -532,8 +532,19 @@ static noinline int device_list_add(const char *path,
                 * As of now don't allow update to btrfs_fs_device through
                 * the btrfs dev scan cli, after FS has been mounted.
                 */
-               if (fs_devices->opened)
+               if (fs_devices->opened) {
                        return -EBUSY;
+               } else {
+                       /*
+                        * That is if the FS is _not_ mounted and if you
+                        * are here, that means there is more than one
+                        * disk with same uuid and devid.We keep the one
+                        * with larger generation number or the last-in if
+                        * generation are equal.
+                        */
+                       if (found_transid < device->generation)
+                               return -EEXIST;
+               }
 
                name = rcu_string_strdup(path, GFP_NOFS);
                if (!name)
@@ -546,6 +557,15 @@ static noinline int device_list_add(const char *path,
                }
        }
 
+       /*
+        * Unmount does not free the btrfs_device struct but would zero
+        * generation along with most of the other members. So just update
+        * it back. We need it to pick the disk with largest generation
+        * (as above).
+        */
+       if (!fs_devices->opened)
+               device->generation = found_transid;
+
        if (found_transid > fs_devices->latest_trans) {
                fs_devices->latest_devid = devid;
                fs_devices->latest_trans = found_transid;
-- 
1.9.3

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

Reply via email to