Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/ufs/ffs PR/53990, PR/52380, PR/52102: UFS2 cylinder grou...



details:   https://anonhg.NetBSD.org/src/rev/5757c2975829
branches:  trunk
changeset: 455811:5757c2975829
user:      kardel <kardel%NetBSD.org@localhost>
date:      Sun Apr 14 15:55:24 2019 +0000

description:
PR/53990, PR/52380, PR/52102: UFS2 cylinder group inode allocation botch

Fix rare allocation botch in ffs_nodealloccg().

Conditions:
   a) less than
        #_of_initialized_inodes(cg->cg_initediblk)
        - inodes_per_filesystem_block
      are allocated in the cylinder group
   b) cg->cg_irotor points to a uninterupted run of
      allocated inodes in the inode bitmap up to the
      end of dynamically initialized inodes
      (cg->cg_initediblk)

In this case the next inode after this run was returned
without initializing the respective inode block. As the
block is not initialized these inodes could trigger panics
on inode consistency due to old (uninitialized) disk data.

In very rare cases data loss could occur when
the uninitialized inode block is initialized via the
normal mechanism.
Further conditions to occur after the above:
   c) no panic
   d) no (forced) fsck
   e) and more than cg->cg_initediblk - inodes_per_filesystem_block
      allocated inodes.

Fix:
Always insure allocation always in initialized inode range
extending the initialized inode range as needed.

Add KASSERTMSG() safeguards.

ok hannken@

diffstat:

 sys/ufs/ffs/ffs_alloc.c |  44 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 35 insertions(+), 9 deletions(-)

diffs (107 lines):

diff -r c0f678f18715 -r 5757c2975829 sys/ufs/ffs/ffs_alloc.c
--- a/sys/ufs/ffs/ffs_alloc.c   Sun Apr 14 11:35:54 2019 +0000
+++ b/sys/ufs/ffs/ffs_alloc.c   Sun Apr 14 15:55:24 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffs_alloc.c,v 1.163 2018/12/10 20:48:34 jdolecek Exp $ */
+/*     $NetBSD: ffs_alloc.c,v 1.164 2019/04/14 15:55:24 kardel Exp $   */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.163 2018/12/10 20:48:34 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.164 2019/04/14 15:55:24 kardel Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -1259,7 +1259,7 @@
        struct buf *bp, *ibp;
        u_int8_t *inosused;
        int error, start, len, loc, map, i;
-       int32_t initediblk;
+       int32_t initediblk, maxiblk, irotor;
        daddr_t nalloc;
        struct ufs2_dinode *dp2;
        const int needswap = UFS_FSNEEDSWAP(fs);
@@ -1271,7 +1271,13 @@
                return (0);
        mutex_exit(&ump->um_lock);
        ibp = NULL;
-       initediblk = -1;
+       if (fs->fs_magic == FS_UFS2_MAGIC) {
+               initediblk = -1;
+       } else {
+               initediblk = fs->fs_ipg;
+       }
+       maxiblk = initediblk;
+
 retry:
        error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, B_MODIFY, &bp);
@@ -1291,7 +1297,8 @@
         * Check to see if we need to initialize more inodes.
         */
        if (fs->fs_magic == FS_UFS2_MAGIC && ibp == NULL) {
-               initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
+               initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
+               maxiblk = initediblk;
                nalloc = fs->fs_ipg - ufs_rw32(cgp->cg_cs.cs_nifree, needswap);
                if (nalloc + FFS_INOPB(fs) > initediblk &&
                    initediblk < ufs_rw32(cgp->cg_niblk, needswap)) {
@@ -1307,6 +1314,9 @@
                            FFS_NOBLK, fs->fs_bsize, false, &ibp);
                        if (error)
                                goto fail;
+
+                       maxiblk += FFS_INOPB(fs);
+                       
                        goto retry;
                }
        }
@@ -1316,14 +1326,22 @@
            (fs->fs_old_flags & FS_FLAGS_UPDATED))
                cgp->cg_time = ufs_rw64(time_second, needswap);
        inosused = cg_inosused(cgp, needswap);
+       
        if (ipref) {
                ipref %= fs->fs_ipg;
-               if (isclr(inosused, ipref))
+               /* safeguard to stay in (to be) allocated range */
+               if (ipref < maxiblk && isclr(inosused, ipref))
                        goto gotit;
        }
-       start = ufs_rw32(cgp->cg_irotor, needswap) / NBBY;
-       len = howmany(fs->fs_ipg - ufs_rw32(cgp->cg_irotor, needswap),
-               NBBY);
+
+       irotor = ufs_rw32(cgp->cg_irotor, needswap); 
+
+       KASSERTMSG(irotor < initediblk, "%s: allocation botch: cg=%d, irotor %d"
+                  " out of bounds, initediblk=%d",
+                  __func__, cg, irotor, initediblk);
+
+       start = irotor / NBBY;
+       len = howmany(maxiblk - irotor, NBBY);
        loc = skpc(0xff, len, &inosused[start]);
        if (loc == 0) {
                len = start + 1;
@@ -1341,9 +1359,17 @@
        if (map == 0) {
                panic("%s: block not in map: fs=%s", __func__, fs->fs_fsmnt);
        }
+       
        ipref = i * NBBY + ffs(map) - 1;
+
        cgp->cg_irotor = ufs_rw32(ipref, needswap);
+
 gotit:
+       KASSERTMSG(ipref < maxiblk, "%s: allocation botch: cg=%d attempt to "
+                  "allocate inode index %d beyond max allocated index %d"
+                  " of %d inodes/cg",
+                  __func__, cg, (int)ipref, maxiblk, cgp->cg_niblk);
+
        UFS_WAPBL_REGISTER_INODE(ip->i_ump->um_mountp, cg * fs->fs_ipg + ipref,
            mode);
        /*



Home | Main Index | Thread Index | Old Index