tech-kern archive

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

Re: panic ffs_valloc dup_alloc



In article <201712132230.vBDMU37I021442%sdf.org@localhost>,
Stephen M. Jones <martians%sdf.org@localhost> wrote:
>
>I have NetBSD-7 deployed on many systems (the majority being amd64) and
>have noticed that the busy machines (smtpd, imapd, httpd) tend to develop 
>filesystem inconsistencies that get worse with time.  The inconsistencies 
>usually result in a panic: ffs_valloc: dup_alloc.  
>
>Bringing the machine up in single user and doing several fsck -f -y on 
>the file system will clear these problems for a while, but they'll develop
>again.
>
>In some cases the filesystem corruption can only be corrected by a newfs.
>
>I have crash dumps console output with messages like the following:
>
>panic: ffs_valloc: dup alloc
>dmode 8180 mode 8180 dgen 1ee653a5 gen 1ee653a5
>size 0 blocks 0
>ino 9439504 ipref 9439135
>panic: ffs_valloc: dup alloc
>cpu0: Begin traceback...
>vpanic() at netbsd:vpanic+0x13c
>snprintf() at netbsd:snprintf
>ffs_valloc() at netbsd:ffs_valloc+0x889
>ufs_makeinode() at netbsd:ufs_makeinode+0x5e
>ufs_create() at netbsd:ufs_create+0x5b
>VOP_CREATE() at netbsd:VOP_CREATE+0x38
>vn_open() at netbsd:vn_open+0x330
>do_open() at netbsd:do_open+0x111
>do_sys_openat() at netbsd:do_sys_openat+0x68
>sys_open() at netbsd:sys_open+0x24
>syscall() at netbsd:syscall+0x9a
>
>I've seen this problem since NetBSD-6.   Again, this is on busy servers and
>not idle machines. 

I am guessing this is ffs2... Try this:

christos

Index: ffs_alloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_alloc.c,v
retrieving revision 1.146.2.1
diff -u -u -r1.146.2.1 ffs_alloc.c
--- ffs_alloc.c	14 Aug 2015 05:29:14 -0000	1.146.2.1
+++ ffs_alloc.c	14 Dec 2017 20:09:22 -0000
@@ -615,29 +615,21 @@
 	KASSERT((*vpp)->v_type == VNON);
 	ip = VTOI(*vpp);
 	if (ip->i_mode) {
-#if 0
-		printf("mode = 0%o, inum = %d, fs = %s\n",
-		    ip->i_mode, ip->i_number, fs->fs_fsmnt);
-#else
-		printf("dmode %x mode %x dgen %x gen %x\n",
-		    DIP(ip, mode), ip->i_mode,
-		    DIP(ip, gen), ip->i_gen);
-		printf("size %llx blocks %llx\n",
-		    (long long)DIP(ip, size), (long long)DIP(ip, blocks));
-		printf("ino %llu ipref %llu\n", (unsigned long long)ino,
-		    (unsigned long long)ipref);
-#if 0
-		error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
-		    (int)fs->fs_bsize, NOCRED, 0, &bp);
-#endif
-
-#endif
-		panic("ffs_valloc: dup alloc");
-	}
-	if (DIP(ip, blocks)) {				/* XXX */
-		printf("free inode %llu on %s had %" PRId64 " blocks\n",
-		    (unsigned long long)ino, fs->fs_fsmnt, DIP(ip, blocks));
+		panic("%s: dup alloc ino=%" PRId64 " on %s: mode %x/%x "
+		    "gen %x/%x size %" PRIx64 " blocks %" PRIx64,
+		    __func__, ino, fs->fs_fsmnt, DIP(ip, mode), ip->i_mode,
+		    DIP(ip, gen), ip->i_gen, DIP(ip, size), DIP(ip, blocks));
+	}
+	if (DIP(ip, size) || DIP(ip, blocks)) {
+		printf("%s: ino=%" PRId64 " on %s: "
+		    "gen %x/%x has non zero blocks %" PRIx64 " or size %"
+		    PRIx64 "\n",
+		    __func__, ino, fs->fs_fsmnt, DIP(ip, gen), ip->i_gen,
+		    DIP(ip, blocks), DIP(ip, size));
+		if ((ip)->i_ump->um_fstype == UFS1)
+			panic("%s: dirty filesystem?", __func__);
 		DIP_ASSIGN(ip, blocks, 0);
+		DIP_ASSIGN(ip, size, 0);
 	}
 	ip->i_flag &= ~IN_SPACECOUNTED;
 	ip->i_flags = 0;
Index: ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.299.2.4
diff -u -u -r1.299.2.4 ffs_vfsops.c
--- ffs_vfsops.c	27 Aug 2016 15:17:34 -0000	1.299.2.4
+++ ffs_vfsops.c	14 Dec 2017 20:09:22 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_vfsops.c,v 1.299.2.4 2016/08/27 15:17:34 bouyer Exp $	*/
+/*	$NetBSD: ffs_vfsops.c,v 1.339 2016/06/19 22:41:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -182,6 +182,54 @@
 };
 
 static int
+ffs_checkrange(struct mount *mp, uint32_t ino)
+{
+	struct fs *fs = VFSTOUFS(mp)->um_fs;
+
+	if (ino < UFS_ROOTINO || ino >= fs->fs_ncg * fs->fs_ipg) {
+		DPRINTF("out of range %u\n", ino);
+		return ESTALE;
+	}
+
+	/*
+	 * Need to check if inode is initialized because ffsv2 does 
+	 * lazy initialization and we can get here from nfs_fhtovp
+	 */
+	if (fs->fs_magic != FS_UFS2_MAGIC)
+		return 0;
+
+	struct buf *bp;
+	int cg = ino_to_cg(fs, ino);
+	struct ufsmount *ump = VFSTOUFS(mp);
+
+	int error = bread(ump->um_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
+	    (int)fs->fs_cgsize, B_MODIFY, &bp);
+	if (error) {
+		DPRINTF("error %d reading cg %d ino %u\n", error, cg, ino);
+		return error;
+	}
+
+	const int needswap = UFS_FSNEEDSWAP(fs);
+
+	struct cg *cgp = (struct cg *)bp->b_data;
+	if (!cg_chkmagic(cgp, needswap)) {
+		brelse(bp, 0);
+		DPRINTF("bad cylinder group magic cg %d ino %u\n", cg, ino);
+		return ESTALE;
+	}
+
+	int32_t initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
+	brelse(bp, 0);
+
+	if (cg * fs->fs_ipg + initediblk < ino) {
+		DPRINTF("cg=%d fs->fs_ipg=%d initediblk=%d ino=%u\n",
+		    cg, fs->fs_ipg, initediblk, ino);
+		return ESTALE;
+	}
+	return 0;
+}
+
+static int
 ffs_snapshot_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
     void *arg0, void *arg1, void *arg2, void *arg3)
 {
@@ -717,7 +765,7 @@
 	error = vinvalbuf(devvp, 0, cred, l, 0, 0);
 	VOP_UNLOCK(devvp);
 	if (error)
-		panic("ffs_reload: dirty1");
+		panic("%s: dirty1", __func__);
 	/*
 	 * Step 2: re-read superblock from disk.
 	 */
@@ -879,7 +927,7 @@
 			continue;
 		}
 		if (vinvalbuf(vp, 0, cred, l, 0, 0))
-			panic("ffs_reload: dirty2");
+			panic("%s: dirty2", __func__);
 		/*
 		 * Step 6: re-read inode data for all active vnodes.
 		 */
@@ -1748,8 +1796,7 @@
 
 	fs = ump->um_fs;
 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
-		printf("fs = %s\n", fs->fs_fsmnt);
-		panic("update: rofs mod");
+		panic("%s: rofs mod, fs=%s", __func__, fs->fs_fsmnt);
 	}
 
 	fstrans_start(mp, FSTRANS_SHARED);
@@ -1920,16 +1967,15 @@
 ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
 {
 	struct ufid ufh;
-	struct fs *fs;
+	int error;
 
 	if (fhp->fid_len != sizeof(struct ufid))
 		return EINVAL;
 
 	memcpy(&ufh, fhp, sizeof(ufh));
-	fs = VFSTOUFS(mp)->um_fs;
-	if (ufh.ufid_ino < UFS_ROOTINO ||
-	    ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg)
-		return (ESTALE);
+	if ((error = ffs_checkrange(mp, ufh.ufid_ino)) != 0)
+		return error;
+
 	return (ufs_fhtovp(mp, &ufh, vpp));
 }
 



Home | Main Index | Thread Index | Old Index