md: fix max sectors calculation for super 1.0
authorXiao Ni <xni@redhat.com>
Tue, 30 Jun 2020 07:55:36 +0000 (15:55 +0800)
committerSong Liu <songliubraving@fb.com>
Mon, 3 Aug 2020 06:03:51 +0000 (23:03 -0700)
To grow size of super 1.0 raid array, it is necessary to check the device
max usable size.

Now it uses rdev->sectors for max usable size. If one disk is 500G and the
raid device only uses the 100GB of this disk. rdev->sectors can't tell the
real max usable size. The max usable size should be

dev_size-(superblock_size+bitmap_size+badblock_size).

Also, remove unnecessary sb_start update in super_1_rdev_size_change().

Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
drivers/md/md.c

index ea48bc2..5e8f772 100644 (file)
@@ -2193,6 +2193,24 @@ retry:
        sb->sb_csum = calc_sb_1_csum(sb);
 }
 
+static sector_t super_1_choose_bm_space(sector_t dev_size)
+{
+       sector_t bm_space;
+
+       /* if the device is bigger than 8Gig, save 64k for bitmap
+        * usage, if bigger than 200Gig, save 128k
+        */
+       if (dev_size < 64*2)
+               bm_space = 0;
+       else if (dev_size - 64*2 >= 200*1024*1024*2)
+               bm_space = 128*2;
+       else if (dev_size - 4*2 > 8*1024*1024*2)
+               bm_space = 64*2;
+       else
+               bm_space = 4*2;
+       return bm_space;
+}
+
 static unsigned long long
 super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
 {
@@ -2213,13 +2231,22 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
                return 0;
        } else {
                /* minor version 0; superblock after data */
-               sector_t sb_start;
-               sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
+               sector_t sb_start, bm_space;
+               sector_t dev_size = i_size_read(rdev->bdev->bd_inode) >> 9;
+
+               /* 8K is for superblock */
+               sb_start = dev_size - 8*2;
                sb_start &= ~(sector_t)(4*2 - 1);
-               max_sectors = rdev->sectors + sb_start - rdev->sb_start;
+
+               bm_space = super_1_choose_bm_space(dev_size);
+
+               /* Space that can be used to store date needs to decrease
+                * superblock bitmap space and bad block space(4K)
+                */
+               max_sectors = sb_start - bm_space - 4*2;
+
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
-               rdev->sb_start = sb_start;
        }
        sb = page_address(rdev->sb_page);
        sb->data_size = cpu_to_le64(num_sectors);