summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2014-09-14 18:07:55 +0000
committeralc <alc@FreeBSD.org>2014-09-14 18:07:55 +0000
commit810772ca9c678e3b54d4e970d9028be9b0a0a7f6 (patch)
tree2bf12f22e73cb9521683f0cd0d2220af8de44c9a
parent3c95d9510474d6b979449e1aa4f54554fa784671 (diff)
downloadFreeBSD-src-810772ca9c678e3b54d4e970d9028be9b0a0a7f6.zip
FreeBSD-src-810772ca9c678e3b54d4e970d9028be9b0a0a7f6.tar.gz
Avoid an exclusive acquisition of the object lock on the expected execution
path through the NFS clients' getpages functions. Introduce vm_pager_free_nonreq(). This function can be used to eliminate code that is duplicated in many getpages functions. Also, in contrast to the code that currently appears in those getpages functions, vm_pager_free_nonreq() avoids acquiring an exclusive object lock in one case. Reviewed by: kib MFC after: 6 weeks Sponsored by: EMC / Isilon Storage Division
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c29
-rw-r--r--sys/nfsclient/nfs_bio.c29
-rw-r--r--sys/vm/vm_pager.c27
-rw-r--r--sys/vm/vm_pager.h2
-rw-r--r--sys/vm/vnode_pager.c18
5 files changed, 49 insertions, 56 deletions
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index dc106ee..4c8c2dc 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -129,23 +129,20 @@ ncl_getpages(struct vop_getpages_args *ap)
npages = btoc(count);
/*
+ * Since the caller has busied the requested page, that page's valid
+ * field will not be changed by other threads.
+ */
+ vm_page_assert_xbusied(pages[ap->a_reqpage]);
+
+ /*
* If the requested page is partially valid, just return it and
* allow the pager to zero-out the blanks. Partially valid pages
* can only occur at the file EOF.
*/
- VM_OBJECT_WLOCK(object);
if (pages[ap->a_reqpage]->valid != 0) {
- for (i = 0; i < npages; ++i) {
- if (i != ap->a_reqpage) {
- vm_page_lock(pages[i]);
- vm_page_free(pages[i]);
- vm_page_unlock(pages[i]);
- }
- }
- VM_OBJECT_WUNLOCK(object);
- return (0);
+ vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages);
+ return (VM_PAGER_OK);
}
- VM_OBJECT_WUNLOCK(object);
/*
* We use only the kva address for the buffer, but this is extremely
@@ -175,15 +172,7 @@ ncl_getpages(struct vop_getpages_args *ap)
if (error && (uio.uio_resid == count)) {
ncl_printf("nfs_getpages: error %d\n", error);
- VM_OBJECT_WLOCK(object);
- for (i = 0; i < npages; ++i) {
- if (i != ap->a_reqpage) {
- vm_page_lock(pages[i]);
- vm_page_free(pages[i]);
- vm_page_unlock(pages[i]);
- }
- }
- VM_OBJECT_WUNLOCK(object);
+ vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages);
return (VM_PAGER_ERROR);
}
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index 1f07b46..1a5b156 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -123,23 +123,20 @@ nfs_getpages(struct vop_getpages_args *ap)
npages = btoc(count);
/*
+ * Since the caller has busied the requested page, that page's valid
+ * field will not be changed by other threads.
+ */
+ vm_page_assert_xbusied(pages[ap->a_reqpage]);
+
+ /*
* If the requested page is partially valid, just return it and
* allow the pager to zero-out the blanks. Partially valid pages
* can only occur at the file EOF.
*/
- VM_OBJECT_WLOCK(object);
if (pages[ap->a_reqpage]->valid != 0) {
- for (i = 0; i < npages; ++i) {
- if (i != ap->a_reqpage) {
- vm_page_lock(pages[i]);
- vm_page_free(pages[i]);
- vm_page_unlock(pages[i]);
- }
- }
- VM_OBJECT_WUNLOCK(object);
- return (0);
+ vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages);
+ return (VM_PAGER_OK);
}
- VM_OBJECT_WUNLOCK(object);
/*
* We use only the kva address for the buffer, but this is extremely
@@ -169,15 +166,7 @@ nfs_getpages(struct vop_getpages_args *ap)
if (error && (uio.uio_resid == count)) {
nfs_printf("nfs_getpages: error %d\n", error);
- VM_OBJECT_WLOCK(object);
- for (i = 0; i < npages; ++i) {
- if (i != ap->a_reqpage) {
- vm_page_lock(pages[i]);
- vm_page_free(pages[i]);
- vm_page_unlock(pages[i]);
- }
- }
- VM_OBJECT_WUNLOCK(object);
+ vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages);
return (VM_PAGER_ERROR);
}
diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c
index c7d038b..65193c3 100644
--- a/sys/vm/vm_pager.c
+++ b/sys/vm/vm_pager.c
@@ -282,6 +282,33 @@ vm_pager_object_lookup(struct pagerlst *pg_list, void *handle)
}
/*
+ * Free the non-requested pages from the given array.
+ */
+void
+vm_pager_free_nonreq(vm_object_t object, vm_page_t ma[], int reqpage,
+ int npages)
+{
+ int i;
+ boolean_t object_locked;
+
+ VM_OBJECT_ASSERT_UNLOCKED(object);
+ object_locked = FALSE;
+ for (i = 0; i < npages; ++i) {
+ if (i != reqpage) {
+ if (!object_locked) {
+ VM_OBJECT_WLOCK(object);
+ object_locked = TRUE;
+ }
+ vm_page_lock(ma[i]);
+ vm_page_free(ma[i]);
+ vm_page_unlock(ma[i]);
+ }
+ }
+ if (object_locked)
+ VM_OBJECT_WUNLOCK(object);
+}
+
+/*
* initialize a physical buffer
*/
diff --git a/sys/vm/vm_pager.h b/sys/vm/vm_pager.h
index 62265a2..e3d292d 100644
--- a/sys/vm/vm_pager.h
+++ b/sys/vm/vm_pager.h
@@ -106,6 +106,8 @@ static __inline int vm_pager_get_pages(vm_object_t, vm_page_t *, int, int);
static __inline boolean_t vm_pager_has_page(vm_object_t, vm_pindex_t, int *, int *);
void vm_pager_init(void);
vm_object_t vm_pager_object_lookup(struct pagerlst *, void *);
+void vm_pager_free_nonreq(vm_object_t object, vm_page_t ma[], int reqpage,
+ int npages);
/*
* vm_page_get_pages:
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 072f197..1b0dc7e 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -722,14 +722,7 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount,
VM_OBJECT_WUNLOCK(object);
return (error);
} else if (error != 0) {
- VM_OBJECT_WLOCK(object);
- for (i = 0; i < count; i++)
- if (i != reqpage) {
- vm_page_lock(m[i]);
- vm_page_free(m[i]);
- vm_page_unlock(m[i]);
- }
- VM_OBJECT_WUNLOCK(object);
+ vm_pager_free_nonreq(object, m, reqpage, count);
return (VM_PAGER_ERROR);
/*
@@ -739,14 +732,7 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount,
*/
} else if ((PAGE_SIZE / bsize) > 1 &&
(vp->v_mount->mnt_stat.f_type != nfs_mount_type)) {
- VM_OBJECT_WLOCK(object);
- for (i = 0; i < count; i++)
- if (i != reqpage) {
- vm_page_lock(m[i]);
- vm_page_free(m[i]);
- vm_page_unlock(m[i]);
- }
- VM_OBJECT_WUNLOCK(object);
+ vm_pager_free_nonreq(object, m, reqpage, count);
PCPU_INC(cnt.v_vnodein);
PCPU_INC(cnt.v_vnodepgsin);
return vnode_pager_input_smlfs(object, m[reqpage]);
OpenPOWER on IntegriCloud