diff options
author | alc <alc@FreeBSD.org> | 2014-09-14 18:07:55 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2014-09-14 18:07:55 +0000 |
commit | 810772ca9c678e3b54d4e970d9028be9b0a0a7f6 (patch) | |
tree | 2bf12f22e73cb9521683f0cd0d2220af8de44c9a | |
parent | 3c95d9510474d6b979449e1aa4f54554fa784671 (diff) | |
download | FreeBSD-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.c | 29 | ||||
-rw-r--r-- | sys/nfsclient/nfs_bio.c | 29 | ||||
-rw-r--r-- | sys/vm/vm_pager.c | 27 | ||||
-rw-r--r-- | sys/vm/vm_pager.h | 2 | ||||
-rw-r--r-- | sys/vm/vnode_pager.c | 18 |
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]); |