From dae50f6c50d01003d74bda00c214cb1a050d6db5 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sat, 16 May 1998 17:47:44 +0000 Subject: [PATCH] Don't use "ffs" in an ext2fs sleep message string. Don't forget to clear the inode hash lock before returning from ext2_vget() after getnewvnode() fails. Obtained from: rev.1.24 of ffs_vfsops.c (the original patch for the getnewvnode() race). Forgotten in: rev.1.4 here. Removed a duplicate comment. Duplicated in: rev.1.4 here. Fixed the MALLOC() vs getnewvnode() race in ext2_vget(). Obtained from: rev.1.39 of ffs_vfsops.c. --- sys/gnu/ext2fs/ext2_vfsops.c | 17 ++++++++++++++--- sys/gnu/fs/ext2fs/ext2_vfsops.c | 17 ++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index 8351a3ae78c..3dcabcb7052 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -911,18 +911,30 @@ restart: if (ext2fs_inode_hash_lock) { while (ext2fs_inode_hash_lock) { ext2fs_inode_hash_lock = -1; - tsleep(&ext2fs_inode_hash_lock, PVM, "ffsvgt", 0); + tsleep(&ext2fs_inode_hash_lock, PVM, "e2vget", 0); } goto restart; } ext2fs_inode_hash_lock = 1; + /* + * If this MALLOC() is performed after the getnewvnode() + * it might block, leaving a vnode with a NULL v_data to be + * found by ext2_sync() if a sync happens to fire right then, + * which will cause a panic because ext2_sync() blindly + * dereferences vp->v_data (as well it should). + */ + MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK); + /* Allocate a new vnode/inode. */ if (error = getnewvnode(VT_UFS, mp, ext2_vnodeop_p, &vp)) { + if (ext2fs_inode_hash_lock < 0) + wakeup(&ext2fs_inode_hash_lock); + ext2fs_inode_hash_lock = 0; *vpp = NULL; + FREE(ip, M_EXT2NODE); return (error); } - MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); vp->v_data = ip; ip->i_vnode = vp; @@ -946,7 +958,6 @@ restart: ext2fs_inode_hash_lock = 0; /* Read in the disk contents for the inode, copy into the inode. */ - /* Read in the disk contents for the inode, copy into the inode. */ #if 0 printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); #endif diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index 8351a3ae78c..3dcabcb7052 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -911,18 +911,30 @@ restart: if (ext2fs_inode_hash_lock) { while (ext2fs_inode_hash_lock) { ext2fs_inode_hash_lock = -1; - tsleep(&ext2fs_inode_hash_lock, PVM, "ffsvgt", 0); + tsleep(&ext2fs_inode_hash_lock, PVM, "e2vget", 0); } goto restart; } ext2fs_inode_hash_lock = 1; + /* + * If this MALLOC() is performed after the getnewvnode() + * it might block, leaving a vnode with a NULL v_data to be + * found by ext2_sync() if a sync happens to fire right then, + * which will cause a panic because ext2_sync() blindly + * dereferences vp->v_data (as well it should). + */ + MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK); + /* Allocate a new vnode/inode. */ if (error = getnewvnode(VT_UFS, mp, ext2_vnodeop_p, &vp)) { + if (ext2fs_inode_hash_lock < 0) + wakeup(&ext2fs_inode_hash_lock); + ext2fs_inode_hash_lock = 0; *vpp = NULL; + FREE(ip, M_EXT2NODE); return (error); } - MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2NODE, M_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); vp->v_data = ip; ip->i_vnode = vp; @@ -946,7 +958,6 @@ restart: ext2fs_inode_hash_lock = 0; /* Read in the disk contents for the inode, copy into the inode. */ - /* Read in the disk contents for the inode, copy into the inode. */ #if 0 printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); #endif