From 7599f93972419797d67fc9b7092799a623fda7ae Mon Sep 17 00:00:00 2001 From: kib Date: Mon, 29 Dec 2008 12:12:23 +0000 Subject: Drop the pseudofs vnode lock around call to pfs_read handler. The handler may need to lock arbitrary vnodes, causing either lock order reversal or recursive vnode lock acquisition. Tested by: pho Approved by: des MFC after: 2 weeks --- sys/fs/pseudofs/pseudofs_vnops.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'sys/fs') diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index ef91bfd..840123c 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -476,7 +476,7 @@ pfs_read(struct vop_read_args *va) struct uio *uio = va->a_uio; struct proc *proc; struct sbuf *sb = NULL; - int error; + int error, locked; unsigned int buflen, offset, resid; PFS_TRACE(("%s", pn->pn_name)); @@ -502,13 +502,15 @@ pfs_read(struct vop_read_args *va) PROC_UNLOCK(proc); } + vhold(vn); + locked = VOP_ISLOCKED(vn); + VOP_UNLOCK(vn, 0); + if (pn->pn_flags & PFS_RAWRD) { PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid)); error = pn_fill(curthread, proc, pn, NULL, uio); PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid)); - if (proc != NULL) - PRELE(proc); - PFS_RETURN (error); + goto ret; } /* beaucoup sanity checks so we don't ask for bogus allocation */ @@ -518,34 +520,35 @@ pfs_read(struct vop_read_args *va) (buflen = offset + resid + 1) < offset || buflen > INT_MAX) { if (proc != NULL) PRELE(proc); - PFS_RETURN (EINVAL); + error = EINVAL; + goto ret; } if (buflen > MAXPHYS + 1) { - if (proc != NULL) - PRELE(proc); - PFS_RETURN (EIO); + error = EIO; + goto ret; } sb = sbuf_new(sb, NULL, buflen, 0); if (sb == NULL) { - if (proc != NULL) - PRELE(proc); - PFS_RETURN (EIO); + error = EIO; + goto ret; } error = pn_fill(curthread, proc, pn, sb, uio); - if (proc != NULL) - PRELE(proc); - if (error) { sbuf_delete(sb); - PFS_RETURN (error); + goto ret; } sbuf_finish(sb); error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio); sbuf_delete(sb); +ret: + vn_lock(vn, locked | LK_RETRY); + vdrop(vn); + if (proc != NULL) + PRELE(proc); PFS_RETURN (error); } -- cgit v1.1