diff options
Diffstat (limited to 'sys/dev/md/md.c')
-rw-r--r-- | sys/dev/md/md.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index d3e3da8..48d48fd 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -924,12 +924,20 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_vp->v_type != VREG || - (error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred))) { - VOP_UNLOCK(nd.ni_vp, 0); - (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); - return (error ? error : EINVAL); + if (nd.ni_vp->v_type != VREG) { + error = EINVAL; + goto bad; + } + error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred); + if (error != 0) + goto bad; + if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) { + vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY); + if (nd.ni_vp->v_iflag & VI_DOOMED) { + /* Forced unmount. */ + error = EBADF; + goto bad; + } } nd.ni_vp->v_vflag |= VV_MD; VOP_UNLOCK(nd.ni_vp, 0); @@ -948,13 +956,15 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td) sc->vnode = NULL; vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); nd.ni_vp->v_vflag &= ~VV_MD; - VOP_UNLOCK(nd.ni_vp, 0); - (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); - return (error); + goto bad; } VFS_UNLOCK_GIANT(vfslocked); return (0); +bad: + VOP_UNLOCK(nd.ni_vp, 0); + (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); + return (error); } static int |