summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-12-29 12:12:23 +0000
committerkib <kib@FreeBSD.org>2008-12-29 12:12:23 +0000
commit7599f93972419797d67fc9b7092799a623fda7ae (patch)
tree8b50efd617595b512be80a45512f54e63cf1b4e5 /sys/fs
parentc3f2d023e878a1a1fcedd705677a7a94826a7555 (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/pseudofs/pseudofs_vnops.c33
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);
}
OpenPOWER on IntegriCloud