diff options
author | kib <kib@FreeBSD.org> | 2008-12-29 12:12:23 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-12-29 12:12:23 +0000 |
commit | 7599f93972419797d67fc9b7092799a623fda7ae (patch) | |
tree | 8b50efd617595b512be80a45512f54e63cf1b4e5 | |
parent | c3f2d023e878a1a1fcedd705677a7a94826a7555 (diff) | |
download | FreeBSD-src-7599f93972419797d67fc9b7092799a623fda7ae.zip FreeBSD-src-7599f93972419797d67fc9b7092799a623fda7ae.tar.gz |
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
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vnops.c | 33 |
1 files changed, 18 insertions, 15 deletions
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); } |