]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ufs: fix ufs_read_cylinder() failure handling
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 13 Dec 2023 16:20:44 +0000 (11:20 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 18 Oct 2024 21:35:31 +0000 (17:35 -0400)
1) ufs_load_cylinder() should return NULL on ufs_read_cylinder() failures.
ufs_error() is not enough.  As it is, IO failure on attempt to read a part
of cylinder group metadata is likely to end up with an oops.

2) we drop the wrong buffer heads when undoing sb_bread() on IO failure
halfway through the read - we need to brelse() what we've got from
sb_bread(), TYVM...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ufs/cylinder.c

index 1abe5454de479ddb2af40515eab0506f854b2e6e..a2813270c303ed48d9e7eab68eecf5e6a5eeaac4 100644 (file)
@@ -26,7 +26,7 @@
  * Read cylinder group into cache. The memory space for ufs_cg_private_info
  * structure is already allocated during ufs_read_super.
  */
-static void ufs_read_cylinder (struct super_block * sb,
+static bool ufs_read_cylinder(struct super_block *sb,
        unsigned cgno, unsigned bitmap_nr)
 {
        struct ufs_sb_info * sbi = UFS_SB(sb);
@@ -46,9 +46,11 @@ static void ufs_read_cylinder (struct super_block * sb,
         * We have already the first fragment of cylinder group block in buffer
         */
        UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno];
-       for (i = 1; i < UCPI_UBH(ucpi)->count; i++)
-               if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i)))
+       for (i = 1; i < UCPI_UBH(ucpi)->count; i++) {
+               UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i);
+               if (!UCPI_UBH(ucpi)->bh[i])
                        goto failed;
+       }
        sbi->s_cgno[bitmap_nr] = cgno;
                        
        ucpi->c_cgx     = fs32_to_cpu(sb, ucg->cg_cgx);
@@ -67,13 +69,14 @@ static void ufs_read_cylinder (struct super_block * sb,
        ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff);
        ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks);
        UFSD("EXIT\n");
-       return
+       return true;
        
 failed:
        for (j = 1; j < i; j++)
-               brelse (sbi->s_ucg[j]);
+               brelse(UCPI_UBH(ucpi)->bh[j]);
        sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
        ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno);
+       return false;
 }
 
 /*
@@ -156,15 +159,14 @@ struct ufs_cg_private_info * ufs_load_cylinder (
                                UFSD("EXIT (FAILED)\n");
                                return NULL;
                        }
-                       else {
-                               UFSD("EXIT\n");
-                               return sbi->s_ucpi[cgno];
-                       }
                } else {
-                       ufs_read_cylinder (sb, cgno, cgno);
-                       UFSD("EXIT\n");
-                       return sbi->s_ucpi[cgno];
+                       if (unlikely(!ufs_read_cylinder (sb, cgno, cgno))) {
+                               UFSD("EXIT (FAILED)\n");
+                               return NULL;
+                       }
                }
+               UFSD("EXIT\n");
+               return sbi->s_ucpi[cgno];
        }
        /*
         * Cylinder group number cg is in cache but it was not last used, 
@@ -195,7 +197,10 @@ struct ufs_cg_private_info * ufs_load_cylinder (
                        sbi->s_ucpi[j] = sbi->s_ucpi[j-1];
                }
                sbi->s_ucpi[0] = ucpi;
-               ufs_read_cylinder (sb, cgno, 0);
+               if (unlikely(!ufs_read_cylinder (sb, cgno, 0))) {
+                       UFSD("EXIT (FAILED)\n");
+                       return NULL;
+               }
        }
        UFSD("EXIT\n");
        return sbi->s_ucpi[0];