From owner-svn-src-stable@FreeBSD.ORG Wed Jan 1 22:14:50 2014 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id E2C89B8C; Wed, 1 Jan 2014 22:14:50 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id C288519B0; Wed, 1 Jan 2014 22:14:50 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s01MEofF059767; Wed, 1 Jan 2014 22:14:50 GMT (envelope-from rmacklem@svn.freebsd.org) Received: (from rmacklem@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s01MEncP059761; Wed, 1 Jan 2014 22:14:49 GMT (envelope-from rmacklem@svn.freebsd.org) Message-Id: <201401012214.s01MEncP059761@svn.freebsd.org> From: Rick Macklem Date: Wed, 1 Jan 2014 22:14:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r260170 - in stable/9/sys: fs/nfsclient nfsclient X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Jan 2014 22:14:51 -0000 Author: rmacklem Date: Wed Jan 1 22:14:49 2014 New Revision: 260170 URL: http://svnweb.freebsd.org/changeset/base/260170 Log: MFC: r259084 For software builds, the NFS client does many small synchronous (with FILE_SYNC) writes because non-contiguous byte ranges in the same buffer cache block are being written. This patch adds a new mount option "noncontigwr" which allows the non-contiguous byte ranges to be combined, with the dirty byte range becoming the superset of the bytes that are dirty, if the file has not been file locked. This reduces the number of writes significantly for software builds. The only case where this change might break existing applications is where an application is writing non-overlapping byte ranges within the same buffer cache block of a file from multiple clients concurrently. Since such an application would normally do file locking on the file, avoiding the byte range merge for files that have been file locked should be sufficient for most (maybe all?) cases. Modified: stable/9/sys/fs/nfsclient/nfs_clbio.c stable/9/sys/fs/nfsclient/nfs_clvfsops.c stable/9/sys/fs/nfsclient/nfs_clvnops.c stable/9/sys/fs/nfsclient/nfsnode.h stable/9/sys/nfsclient/nfsargs.h Directory Properties: stable/9/sys/ (props changed) stable/9/sys/fs/ (props changed) Modified: stable/9/sys/fs/nfsclient/nfs_clbio.c ============================================================================== --- stable/9/sys/fs/nfsclient/nfs_clbio.c Wed Jan 1 21:48:04 2014 (r260169) +++ stable/9/sys/fs/nfsclient/nfs_clbio.c Wed Jan 1 22:14:49 2014 (r260170) @@ -873,7 +873,7 @@ ncl_write(struct vop_write_args *ap) struct vattr vattr; struct nfsmount *nmp = VFSTONFS(vp->v_mount); daddr_t lbn; - int bcount; + int bcount, noncontig_write, obcount; int bp_cached, n, on, error = 0, error1; size_t orig_resid, local_resid; off_t orig_size, tmp_off; @@ -1036,7 +1036,15 @@ again: * unaligned buffer size. */ mtx_lock(&np->n_mtx); - if (uio->uio_offset == np->n_size && n) { + if ((np->n_flag & NHASBEENLOCKED) == 0 && + (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0) + noncontig_write = 1; + else + noncontig_write = 0; + if ((uio->uio_offset == np->n_size || + (noncontig_write != 0 && + lbn == (np->n_size / biosize) && + uio->uio_offset + n > np->n_size)) && n) { mtx_unlock(&np->n_mtx); /* * Get the buffer (in its pre-append state to maintain @@ -1044,8 +1052,8 @@ again: * nfsnode after we have locked the buffer to prevent * readers from reading garbage. */ - bcount = on; - bp = nfs_getcacheblk(vp, lbn, bcount, td); + obcount = np->n_size - (lbn * biosize); + bp = nfs_getcacheblk(vp, lbn, obcount, td); if (bp != NULL) { long save; @@ -1057,9 +1065,12 @@ again: mtx_unlock(&np->n_mtx); save = bp->b_flags & B_CACHE; - bcount += n; + bcount = on + n; allocbuf(bp, bcount); bp->b_flags |= save; + if (noncontig_write != 0 && on > obcount) + vfs_bio_bzero_buf(bp, obcount, on - + obcount); } } else { /* @@ -1158,19 +1169,23 @@ again: * area, just update the b_dirtyoff and b_dirtyend, * otherwise force a write rpc of the old dirty area. * + * If there has been a file lock applied to this file + * or vfs.nfs.old_noncontig_writing is set, do the following: * While it is possible to merge discontiguous writes due to * our having a B_CACHE buffer ( and thus valid read data * for the hole), we don't because it could lead to * significant cache coherency problems with multiple clients, * especially if locking is implemented later on. * - * As an optimization we could theoretically maintain - * a linked list of discontinuous areas, but we would still - * have to commit them separately so there isn't much - * advantage to it except perhaps a bit of asynchronization. + * If vfs.nfs.old_noncontig_writing is not set and there has + * not been file locking done on this file: + * Relax coherency a bit for the sake of performance and + * expand the current dirty region to contain the new + * write even if it means we mark some non-dirty data as + * dirty. */ - if (bp->b_dirtyend > 0 && + if (noncontig_write == 0 && bp->b_dirtyend > 0 && (on > bp->b_dirtyend || (on + n) < bp->b_dirtyoff)) { if (bwrite(bp) == EINTR) { error = EINTR; Modified: stable/9/sys/fs/nfsclient/nfs_clvfsops.c ============================================================================== --- stable/9/sys/fs/nfsclient/nfs_clvfsops.c Wed Jan 1 21:48:04 2014 (r260169) +++ stable/9/sys/fs/nfsclient/nfs_clvfsops.c Wed Jan 1 22:14:49 2014 (r260170) @@ -713,7 +713,7 @@ static const char *nfs_opts[] = { "from" "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", - "nametimeo", "negnametimeo", "nocto", "wcommitsize", + "nametimeo", "negnametimeo", "nocto", "noncontigwr", "wcommitsize", NULL }; /* @@ -833,6 +833,8 @@ nfs_mount(struct mount *mp) args.flags |= NFSMNT_ALLGSSNAME; if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) args.flags |= NFSMNT_NOCTO; + if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0) + args.flags |= NFSMNT_NONCONTIGWR; if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { if (opt == NULL) { vfs_mount_error(mp, "illegal readdirsize"); @@ -1703,6 +1705,8 @@ void nfscl_retopts(struct nfsmount *nmp, &blen); nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf, &blen); + nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0, + ",noncontigwr", &buf, &blen); nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 0, ",lockd", &buf, &blen); nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == Modified: stable/9/sys/fs/nfsclient/nfs_clvnops.c ============================================================================== --- stable/9/sys/fs/nfsclient/nfs_clvnops.c Wed Jan 1 21:48:04 2014 (r260169) +++ stable/9/sys/fs/nfsclient/nfs_clvnops.c Wed Jan 1 22:14:49 2014 (r260170) @@ -3054,6 +3054,10 @@ nfs_advlock(struct vop_advlock_args *ap) np->n_change = va.va_filerev; } } + /* Mark that a file lock has been acquired. */ + mtx_lock(&np->n_mtx); + np->n_flag |= NHASBEENLOCKED; + mtx_unlock(&np->n_mtx); } NFSVOPUNLOCK(vp, 0); return (0); @@ -3073,6 +3077,12 @@ nfs_advlock(struct vop_advlock_args *ap) error = ENOLCK; } } + if (error == 0 && ap->a_op == F_SETLK) { + /* Mark that a file lock has been acquired. */ + mtx_lock(&np->n_mtx); + np->n_flag |= NHASBEENLOCKED; + mtx_unlock(&np->n_mtx); + } } return (error); } Modified: stable/9/sys/fs/nfsclient/nfsnode.h ============================================================================== --- stable/9/sys/fs/nfsclient/nfsnode.h Wed Jan 1 21:48:04 2014 (r260169) +++ stable/9/sys/fs/nfsclient/nfsnode.h Wed Jan 1 22:14:49 2014 (r260170) @@ -158,6 +158,7 @@ struct nfsnode { #define NREMOVEWANT 0x00004000 /* Want notification that remove is done */ #define NLOCK 0x00008000 /* Sleep lock the node */ #define NLOCKWANT 0x00010000 /* Want the sleep lock */ +#define NHASBEENLOCKED 0x00080000 /* Has been file locked. */ /* * Convert between nfsnode pointers and vnode pointers Modified: stable/9/sys/nfsclient/nfsargs.h ============================================================================== --- stable/9/sys/nfsclient/nfsargs.h Wed Jan 1 21:48:04 2014 (r260169) +++ stable/9/sys/nfsclient/nfsargs.h Wed Jan 1 22:14:49 2014 (r260170) @@ -98,5 +98,6 @@ struct nfs_args { #define NFSMNT_ALLGSSNAME 0x08000000 /* Use principal for all accesses */ #define NFSMNT_STRICT3530 0x10000000 /* Adhere strictly to RFC3530 */ #define NFSMNT_NOCTO 0x20000000 /* Don't flush attrcache on open */ +#define NFSMNT_NONCONTIGWR 0x80000000 /* Enable non-contiguous writes */ #endif