fs/ntfs3: Improve alternative boot processing
authorKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Fri, 24 Nov 2023 08:04:53 +0000 (11:04 +0300)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Wed, 6 Dec 2023 14:46:06 +0000 (17:46 +0300)
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3/super.c

index 9153dffde950c2a396291bea88e3e6d31169f568..09d61c6c90aaf3c746fa23fa25335906921a4b61 100644 (file)
@@ -866,6 +866,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
        u16 fn, ao;
        u8 cluster_bits;
        u32 boot_off = 0;
+       sector_t boot_block = 0;
        const char *hint = "Primary boot";
 
        /* Save original dev_size. Used with alternative boot. */
@@ -873,11 +874,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
        sbi->volume.blocks = dev_size >> PAGE_SHIFT;
 
-       bh = ntfs_bread(sb, 0);
+read_boot:
+       bh = ntfs_bread(sb, boot_block);
        if (!bh)
-               return -EIO;
+               return boot_block ? -EINVAL : -EIO;
 
-check_boot:
        err = -EINVAL;
 
        /* Corrupted image; do not read OOB */
@@ -1108,26 +1109,24 @@ check_boot:
        }
 
 out:
-       if (err == -EINVAL && !bh->b_blocknr && dev_size0 > PAGE_SHIFT) {
+       brelse(bh);
+
+       if (err == -EINVAL && !boot_block && dev_size0 > PAGE_SHIFT) {
                u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
                u64 lbo = dev_size0 - sizeof(*boot);
 
-               /*
-                * Try alternative boot (last sector)
-                */
-               brelse(bh);
-
-               sb_set_blocksize(sb, block_size);
-               bh = ntfs_bread(sb, lbo >> blksize_bits(block_size));
-               if (!bh)
-                       return -EINVAL;
-
+               boot_block = lbo >> blksize_bits(block_size);
                boot_off = lbo & (block_size - 1);
-               hint = "Alternative boot";
-               dev_size = dev_size0; /* restore original size. */
-               goto check_boot;
+               if (boot_block && block_size >= boot_off + sizeof(*boot)) {
+                       /*
+                        * Try alternative boot (last sector)
+                        */
+                       sb_set_blocksize(sb, block_size);
+                       hint = "Alternative boot";
+                       dev_size = dev_size0; /* restore original size. */
+                       goto read_boot;
+               }
        }
-       brelse(bh);
 
        return err;
 }