Anand Jain
2014-Mar-31 14:13 UTC
[PATCH 1/2 v2] btrfs: btrfs_rm_device() should zero mirror SB as well
From: Anand Jain <anand.jain@oracle.com> This fix will ensure all SB copies on the disk is zeroed when the disk is intentionally removed. This helps to better manage disks in the user land. Signed-off-by: Anand Jain <anand.jain@oracle.com> btrfs: don't double brelse on device rm Device removal currently causes bdev removal to try to double free a bh in the bdev: [ 55.714833] WARNING: at fs/buffer.c:1160 __brelse+0x36/0x40() [ 55.714833] VFS: brelse: Trying to free free buffer Commit 7e3d9ebb1 added a double release of the bh for a device being removed when all the supers don't fit in the device. In that case it releases the bh assuming that it's going to read a new one, finds that it won't read, and goes to a label that releases the bh again. All it needed to do was only brelse() right before overwriting the current bh with __bread(). Signed-off-by: Zach Brown <zab@redhat.com> --- v1->v2: merge with Zach fix, commit update fs/btrfs/volumes.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b4660c4..7243196 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1681,12 +1681,43 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) * remove it from the devices list and zero out the old super */ if (clear_super && disk_super) { + u64 bytenr; + int i; + /* make sure this device isn't detected as part of * the FS anymore */ memset(&disk_super->magic, 0, sizeof(disk_super->magic)); set_buffer_dirty(bh); sync_dirty_buffer(bh); + + /* clear the mirror copies of super block on the disk + * being removed, 0th copy is been taken care above and + * the below would take of the rest + */ + for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + if (bytenr + BTRFS_SUPER_INFO_SIZE >+ i_size_read(bdev->bd_inode)) + break; + + brelse(bh); + bh = __bread(bdev, bytenr / 4096, + BTRFS_SUPER_INFO_SIZE); + if (!bh) + continue; + + disk_super = (struct btrfs_super_block *)bh->b_data; + + if (btrfs_super_bytenr(disk_super) != bytenr || + btrfs_super_magic(disk_super) != BTRFS_MAGIC) { + continue; + } + memset(&disk_super->magic, 0, + sizeof(disk_super->magic)); + set_buffer_dirty(bh); + sync_dirty_buffer(bh); + } } ret = 0; -- 1.8.5.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html