summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2014-09-13 18:26:13 +0000
committeralc <alc@FreeBSD.org>2014-09-13 18:26:13 +0000
commite169525bb8bf99d439947a14544f261295aa4731 (patch)
treec6fecd2d028f499d428c002526db85f000d42981 /sys/ufs
parent5630fccbd418933428669ff406733a2f798f63b4 (diff)
downloadFreeBSD-src-e169525bb8bf99d439947a14544f261295aa4731.zip
FreeBSD-src-e169525bb8bf99d439947a14544f261295aa4731.tar.gz
We don't need an exclusive object lock on the expected execution path
through {ext2,ffs}_getpages(). Reviewed by: kib, pfg MFC after: 6 weeks Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_vnops.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 423d811..b6f255e 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -857,19 +857,25 @@ ffs_getpages(ap)
vm_page_t mreq;
int pcount;
- pcount = round_page(ap->a_count) / PAGE_SIZE;
mreq = ap->a_m[ap->a_reqpage];
/*
+ * Since the caller has busied the requested page, that page's valid
+ * field will not be changed by other threads.
+ */
+ vm_page_assert_xbusied(mreq);
+
+ /*
* if ANY DEV_BSIZE blocks are valid on a large filesystem block,
* then the entire page is valid. Since the page may be mapped,
* user programs might reference data beyond the actual end of file
* occuring within the page. We have to zero that data.
*/
- VM_OBJECT_WLOCK(mreq->object);
if (mreq->valid) {
+ VM_OBJECT_WLOCK(mreq->object);
if (mreq->valid != VM_PAGE_BITS_ALL)
vm_page_zero_invalid(mreq, TRUE);
+ pcount = round_page(ap->a_count) / PAGE_SIZE;
for (i = 0; i < pcount; i++) {
if (i != ap->a_reqpage) {
vm_page_lock(ap->a_m[i]);
@@ -880,7 +886,6 @@ ffs_getpages(ap)
VM_OBJECT_WUNLOCK(mreq->object);
return VM_PAGER_OK;
}
- VM_OBJECT_WUNLOCK(mreq->object);
return vnode_pager_generic_getpages(ap->a_vp, ap->a_m,
ap->a_count,
OpenPOWER on IntegriCloud