Subject: kern/22419: kernel panic if 'mknod x b 0 0' fails 'out of space'
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dsl@netbsd.org>
List: netbsd-bugs
Date: 08/09/2003 19:58:34
>Number:         22419
>Category:       kern
>Synopsis:       kernel panic if 'mknod x b 0 0' fails 'out of space'
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Aug 09 18:55:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     David Laight
>Release:        NetBSD 1.6U
>Organization:
	maybe some day
>Environment:
System: NetBSD snowdrop 1.6U NetBSD 1.6U (GENERIC) #100: Wed Jul 23 11:41:02 BST 2003 dsl@snowdrop:/bsd/obj/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:
	If mknod for a block device fails because there is no space
	(either no inodes or no space to extend the directory) then the
	kernel will panic something like:
	    ffs_full_fsync(c4c9db0c,0,0,4,0) at netbsd:ffs_full_fsync+0x1b
	    ffs_fsync(c4c9db0c,c4b679dc,0,c0345a5f,0) at netbsd:ffs_fsync+0x3c
	    VOP_FSYNC(c4b743e4,ffffffff,5,0,0) at netbsd:VOP_FSYNC+0x58
	    vinvalbuf(c4b743e4,1,ffffffff,c4b679dc,0) at netbsd:vinvalbuf+0x52
	    vclean(c4b743e4,8,c4b679dc,c03524ff,c4b75370) at netbsd:vclean+0x80
	    vgonel(c4b743e4,c4b679dc,c4b743e4,c05654e0,c4b743e4)
		at netbsd:vgonel+0x46
	    vrecycle(c4b743e4,0,c4b679dc,0,c4b7441c) at netbsd:vrecycle+0x20
	    ufs_inactive(c4c9dc64,c095d000,c4c9dc8c,c0565420,c4c47058)
		at netbsd:ufs_inactive+0x180
	    VOP_INACTIVE(c4b743e4,c4b679dc,c4c9dde0,c02f2d2b,c4c9dcd8)
		at netbsd:VOP_INACTIVE+0x2e
	    vput(c4b743e4,c4b55400,ffffffff,2,c4c9de3c) at netbsd:vput+0xa2
	    ufs_makeinode(61a0,c4c47058,c4c9de9c,c4c9deb0,c4c47058)
		at netbsd:ufs_makeinode+0x35e
	    ufs_mknod(c4c9de3c,c4b679dc,c4c9df80,c034a9ea,0)
		at netbsd:ufs_mknod+0x2d
	    VOP_MKNOD(c4c47058,c4c9de9c,c4c9deb0,c4c9ded4,c4b35780)
		at netbsd:VOP_MKNOD+0x3b
	    sys_mknod(c4b35780,c4c9df80,c4c9df78,c03b817b,8064048)
		at netbsd:sys_mknod+0x1dd
	    syscall_plain(1f,1f,1f,1f,804a863) at netbsd:syscall_plain+0xab

	The 'problem' is that vp->v_specinfo is NULL, but is indirected
	as part of v_specmountpoint.

>How-To-Repeat:
	Fill a small filesystem then try no make a block special device file.
>Fix:
	Noting that ufs_makeinode() sets v_type = VNON before releasing
	the vnode in the 'success' path, make ufs_makeinode do the same
	in the failure path.
	(Actually I'm sure it would be better fixed in the code that
	frees/recycles the vnode...)

	The patch below fixes ufs and by symmetry ext2fs.
	I've re-ordered the tidyup in the error paths with the view
	that the compiler might merge them with other error paths.

Index: ext2fs/ext2fs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vnops.c,v
retrieving revision 1.48
diff -u -p -r1.48 ext2fs_vnops.c
--- ext2fs/ext2fs_vnops.c	2003/06/29 22:32:33	1.48
+++ ext2fs/ext2fs_vnops.c	2003/08/09 18:41:25
@@ -1407,11 +1407,12 @@ bad:
 	 * Write error occurred trying to update the inode
 	 * or the directory so must deallocate the inode.
 	 */
-	PNBUF_PUT(cnp->cn_pnbuf);
-	vput(dvp);
+	tvp->v_type = VNON;	/* Stop explosion if VBLK */
 	ip->i_e2fs_nlink = 0;
 	ip->i_flag |= IN_CHANGE;
 	vput(tvp);
+	PNBUF_PUT(cnp->cn_pnbuf);
+	vput(dvp);
 	return (error);
 }
 
Index: ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.102
diff -u -p -r1.102 ufs_vnops.c
--- ufs/ufs_vnops.c	2003/06/29 22:32:48	1.102
+++ ufs/ufs_vnops.c	2003/08/09 18:41:33
@@ -2085,9 +2085,9 @@ ufs_makeinode(int mode, struct vnode *dv
 #ifdef QUOTA
 	if ((error = getinoquota(ip)) ||
 	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
-		PNBUF_PUT(cnp->cn_pnbuf);
 		VOP_VFREE(tvp, ip->i_number, mode);
 		vput(tvp);
+		PNBUF_PUT(cnp->cn_pnbuf);
 		vput(dvp);
 		return (error);
 	}
@@ -2132,8 +2132,6 @@ ufs_makeinode(int mode, struct vnode *dv
 	 * Write error occurred trying to update the inode
 	 * or the directory so must deallocate the inode.
 	 */
-	PNBUF_PUT(cnp->cn_pnbuf);
-	vput(dvp);
 	ip->i_ffs_effnlink = 0;
 	ip->i_nlink = 0;
 	DIP_ASSIGN(ip, nlink, 0);
@@ -2144,7 +2142,10 @@ ufs_makeinode(int mode, struct vnode *dv
 #endif
 	if (DOINGSOFTDEP(tvp))
 		softdep_change_linkcnt(ip);
+	tvp->v_type = VNON;		/* explodes later if VBLK */
 	vput(tvp);
+	PNBUF_PUT(cnp->cn_pnbuf);
+	vput(dvp);
 	return (error);
 }
 
>Release-Note:
>Audit-Trail:
>Unformatted:
 	and probably everything else for a long time