diff --git a/sys/fs/nfsclient/nfs_clbio.c.append2 b/sys/fs/nfsclient/nfs_clbio.c --- a/sys/fs/nfsclient/nfs_clbio.c.append2 +++ b/sys/fs/nfsclient/nfs_clbio.c @@ -1001,12 +1001,25 @@ if (uio->uio_resid == 0) return (0); + /* + * If the file in not mmap()'d, do IO_APPEND writing via a + * synchronous direct write. This can result in a significant + * performance improvement. + * If the file is mmap()'d, this cannot be done, since there + * is no way to maintain consistency between the file on the + * NFS server and the file's mmap()'d pages. + */ + NFSLOCKNODE(np); if (vp->v_type == VREG && ((newnfs_directio_enable && (ioflag & - IO_DIRECT)) || (ioflag & IO_APPEND))) { + IO_DIRECT)) || ((ioflag & IO_APPEND) && + ((np->n_flag & NMMAPPED) == 0 || vp->v_object == NULL || + !vm_is_object_active(vp->v_object))))) { + NFSUNLOCKNODE(np); if ((ioflag & IO_APPEND) != 0) ioflag |= IO_SYNC; return nfs_directio_write(vp, uio, cred, ioflag); } + NFSUNLOCKNODE(np); /* * Maybe this should be above the vnode op call, but so long as diff --git a/sys/fs/nfsclient/nfs_clvnops.c.append2 b/sys/fs/nfsclient/nfs_clvnops.c --- a/sys/fs/nfsclient/nfs_clvnops.c.append2 +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -154,6 +154,7 @@ static vop_listextattr_t nfs_listextattr; static vop_deleteextattr_t nfs_deleteextattr; static vop_lock1_t nfs_lock; +static vop_mmapped_t nfs_mmapped; /* * Global vfs data structures for nfs @@ -201,6 +202,7 @@ .vop_setextattr = nfs_setextattr, .vop_listextattr = nfs_listextattr, .vop_deleteextattr = nfs_deleteextattr, + .vop_mmapped = nfs_mmapped, }; VFS_VOP_VECTOR_REGISTER(newnfs_vnodeops_nosig); @@ -4576,4 +4578,19 @@ break; } return (error); +} + +/* + * Mark the vnode as mmap()'d. + */ +static int +nfs_mmapped(struct vop_mmapped_args *ap) +{ + struct nfsnode *np; + + np = VTONFS(ap->a_vp); + NFSLOCKNODE(np); + np->n_flag |= NMMAPPED; + NFSUNLOCKNODE(np); + return (0); } diff --git a/sys/fs/nfsclient/nfsnode.h.append2 b/sys/fs/nfsclient/nfsnode.h --- a/sys/fs/nfsclient/nfsnode.h.append2 +++ b/sys/fs/nfsclient/nfsnode.h @@ -167,6 +167,7 @@ #define NDSCOMMIT 0x00100000 /* Commit is done via the DS. */ #define NVNSETSZSKIP 0x00200000 /* Skipped vnode_pager_setsize() */ #define NMIGHTBELOCKED 0x00400000 /* Might be file locked. */ +#define NMMAPPED 0x00800000 /* Has been mmap()'d. */ /* * Convert between nfsnode pointers and vnode pointers diff --git a/sys/vm/vm_extern.h.append2 b/sys/vm/vm_extern.h --- a/sys/vm/vm_extern.h.append2 +++ b/sys/vm/vm_extern.h @@ -131,6 +131,7 @@ vm_page_t ma[], int npages, int req_class); u_int vm_active_count(void); u_int vm_inactive_count(void); +bool vm_is_object_active(vm_object_t obj); u_int vm_laundry_count(void); u_int vm_wait_count(void); #endif /* _KERNEL */ diff --git a/sys/vm/vm_meter.c.append2 b/sys/vm/vm_meter.c --- a/sys/vm/vm_meter.c.append2 +++ b/sys/vm/vm_meter.c @@ -150,8 +150,8 @@ * has very low overhead and is good enough for the advisory * vm.vmtotal sysctl. */ -static bool -is_object_active(vm_object_t obj) +bool +vm_is_object_active(vm_object_t obj) { return (obj->ref_count > obj->shadow_count); @@ -268,7 +268,7 @@ } total.t_vm += object->size; total.t_rm += object->resident_page_count; - if (is_object_active(object)) { + if (vm_is_object_active(object)) { total.t_avm += object->size; total.t_arm += object->resident_page_count; } @@ -276,7 +276,7 @@ /* shared object */ total.t_vmshr += object->size; total.t_rmshr += object->resident_page_count; - if (is_object_active(object)) { + if (vm_is_object_active(object)) { total.t_avmshr += object->size; total.t_armshr += object->resident_page_count; }