During the mkfs.btrfs -b <blockcount> btrfs_prepare_device() zeros all
the superblock bytenr locations only if the bytenr is below the
blockcount. The problem with this is that if the BTRFS is recreated
with a smaller size then we will leave the stale superblock in the disk
which shall confuse the recovery. As shown in the test case below.

 mkfs.btrfs -qf /dev/mapper/vg-lv
 mkfs.btrfs -qf -b1G /dev/mapper/vg-lv
 btrfs in dump-super -a /dev/mapper/vg-lv | grep '.fsid|superblock:'

 superblock: bytenr=65536, device=/dev/mapper/vg-lv
 dev_item.fsid          ebc67d01-7fc5-43f0-90b4-d1925002551e [match]
 superblock: bytenr=67108864, device=/dev/mapper/vg-lv
 dev_item.fsid          ebc67d01-7fc5-43f0-90b4-d1925002551e [match]
 superblock: bytenr=274877906944, device=/dev/mapper/vg-lv
 dev_item.fsid          b97a9206-593b-4933-a424-c6a6ee23fe7c [match]

So if we find a valid superblock zero it even if it's beyond the
blockcount.

Signed-off-by: Anand Jain <anand.j...@oracle.com>
---
v1->v2: zero only the magic of the alien superblock, instead of whole of
        superblock. And comments updated. Thanks.

 utils.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/utils.c b/utils.c
index 715bab0ebfb5..4e7964962d0e 100644
--- a/utils.c
+++ b/utils.c
@@ -367,6 +367,42 @@ int btrfs_prepare_device(int fd, const char *file, u64 
*block_count_ret,
                return 1;
        }
 
+       /*
+        * Check and wipe alien superblock at bytenr beyond the block_count.
+        */
+       if (block_count != btrfs_device_size(fd, &st)) {
+               for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+                       struct btrfs_super_block *disk_super;
+                       char buf[BTRFS_SUPER_INFO_SIZE];
+                       disk_super = (struct btrfs_super_block *)buf;
+
+                       if (btrfs_sb_offset(i) < block_count)
+                               continue;
+
+                       /* Beyond actual disk size */
+                       if (btrfs_sb_offset(i) >= btrfs_device_size(fd, &st))
+                               continue;
+
+                       /*
+                        * We are reading sperblock at bytenr > block_count, and
+                        * if there is a valid superblock then its an alien
+                        * superblock which should be wiped.
+                        */
+                       if (btrfs_read_dev_super(fd, disk_super,
+                                                btrfs_sb_offset(i), 0))
+                               continue;
+
+                       ret = zero_blocks(fd, btrfs_sb_offset(i) +
+                                     offsetof(struct btrfs_super_block, magic),
+                                     sizeof(u64));
+                       if (ret < 0) {
+                               error("failed to zero device '%s' bytenr %llu: 
%s",
+                                       file, btrfs_sb_offset(i), 
strerror(-ret));
+                               return 1;
+                       }
+               }
+       }
+
        *block_count_ret = block_count;
        return 0;
 }
-- 
2.7.0

--
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