Module Name: src Committed By: hannken Date: Mon Jul 19 08:17:44 UTC 2010
Modified Files: src/sys/fs/ntfs: ntfs_vfsops.c Log Message: Lock the ntnode and recheck the fnode after calling getnewvnode(). Take v_interlock while the ntnode is locked. To generate a diff of this commit: cvs rdiff -u -r1.82 -r1.83 src/sys/fs/ntfs/ntfs_vfsops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/ntfs/ntfs_vfsops.c diff -u src/sys/fs/ntfs/ntfs_vfsops.c:1.82 src/sys/fs/ntfs/ntfs_vfsops.c:1.83 --- src/sys/fs/ntfs/ntfs_vfsops.c:1.82 Thu Jul 1 13:00:55 2010 +++ src/sys/fs/ntfs/ntfs_vfsops.c Mon Jul 19 08:17:44 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ntfs_vfsops.c,v 1.82 2010/07/01 13:00:55 hannken Exp $ */ +/* $NetBSD: ntfs_vfsops.c,v 1.83 2010/07/19 08:17:44 hannken Exp $ */ /*- * Copyright (c) 1998, 1999 Semen Ustimenko @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.82 2010/07/01 13:00:55 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.83 2010/07/19 08:17:44 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -726,6 +726,7 @@ ntmp = VFSTONTFS(mp); *vpp = NULL; +loop: /* Get ntnode */ error = ntfs_ntlookup(ntmp, ino, &ip); if (error) { @@ -778,23 +779,41 @@ * lock has to be acquired first. * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled * prematurely. + * Take v_interlock before releasing ntnode lock to avoid races. */ - ntfs_ntput(ip); - - if (FTOV(fp)) { - /* vget() returns error if the vnode has been recycled */ - if (vget(FTOV(fp), lkflags) == 0) { - *vpp = FTOV(fp); - return (0); - } + vp = FTOV(fp); + if (vp) { + mutex_enter(&vp->v_interlock); + ntfs_ntput(ip); + if (vget(vp, LK_INTERLOCK | lkflags) != 0) + goto loop; + *vpp = vp; + return 0; } + ntfs_ntput(ip); error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp); + ntfs_ntget(ip); if(error) { ntfs_frele(fp); ntfs_ntput(ip); return (error); } + error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); + if (error) { + printf("ntfs_vget: ntfs_fget failed\n"); + ntfs_ntput(ip); + return (error); + } + if (FTOV(fp)) { + /* + * Another thread beat us, put back freshly allocated + * vnode and retry. + */ + ntfs_ntput(ip); + ungetnewvnode(vp); + goto loop; + } dprintf(("ntfs_vget: vnode: %p for ntnode: %llu\n", vp, (unsigned long long)ino)); @@ -807,6 +826,8 @@ if (ino == NTFS_ROOTINO) vp->v_vflag |= VV_ROOT; + ntfs_ntput(ip); + if (lkflags & (LK_EXCLUSIVE | LK_SHARED)) { error = vn_lock(vp, lkflags); if (error) {