dm raid: fix oops on upgrading to extended superblock format
authorHeinz Mauelshagen <heinzm@redhat.com>
Fri, 23 Jun 2017 15:27:01 +0000 (17:27 +0200)
committerMike Snitzer <snitzer@redhat.com>
Fri, 23 Jun 2017 16:16:15 +0000 (12:16 -0400)
When a RAID set was created on dm-raid version < 1.9.0 (old RAID
superblock format), all of the new 1.9.0 members of the superblock are
uninitialized (zero) -- including the device sectors member needed to
support shrinking.

All the other accesses to superblock fields new in 1.9.0 were reviewed
and verified to be properly guarded against invalid use.  The 'sectors'
member was the only one used when the superblock version is < 1.9.

Don't access the superblock's >= 1.9.0 'sectors' member unconditionally.
Also add respective comments.

Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-raid.c

index 7d89322..b4b75da 100644 (file)
@@ -1927,7 +1927,7 @@ struct dm_raid_superblock {
        /********************************************************************
         * BELOW FOLLOW V1.9.0 EXTENSIONS TO THE PRISTINE SUPERBLOCK FORMAT!!!
         *
-        * FEATURE_FLAG_SUPPORTS_V190 in the features member indicates that those exist
+        * FEATURE_FLAG_SUPPORTS_V190 in the compat_features member indicates that those exist
         */
 
        __le32 flags; /* Flags defining array states for reshaping */
@@ -2092,6 +2092,11 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
        sb->layout = cpu_to_le32(mddev->layout);
        sb->stripe_sectors = cpu_to_le32(mddev->chunk_sectors);
 
+       /********************************************************************
+        * BELOW FOLLOW V1.9.0 EXTENSIONS TO THE PRISTINE SUPERBLOCK FORMAT!!!
+        *
+        * FEATURE_FLAG_SUPPORTS_V190 in the compat_features member indicates that those exist
+        */
        sb->new_level = cpu_to_le32(mddev->new_level);
        sb->new_layout = cpu_to_le32(mddev->new_layout);
        sb->new_stripe_sectors = cpu_to_le32(mddev->new_chunk_sectors);
@@ -2438,8 +2443,14 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
        mddev->bitmap_info.default_offset = mddev->bitmap_info.offset;
 
        if (!test_and_clear_bit(FirstUse, &rdev->flags)) {
-               /* Retrieve device size stored in superblock to be prepared for shrink */
-               rdev->sectors = le64_to_cpu(sb->sectors);
+               /*
+                * Retrieve rdev size stored in superblock to be prepared for shrink.
+                * Check extended superblock members are present otherwise the size
+                * will not be set!
+                */
+               if (le32_to_cpu(sb->compat_features) & FEATURE_FLAG_SUPPORTS_V190)
+                       rdev->sectors = le64_to_cpu(sb->sectors);
+
                rdev->recovery_offset = le64_to_cpu(sb->disk_recovery_offset);
                if (rdev->recovery_offset == MaxSector)
                        set_bit(In_sync, &rdev->flags);