From owner-dev-commits-src-branches@freebsd.org Sun Aug 15 23:46:04 2021 Return-Path: Delivered-To: dev-commits-src-branches@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 5D23A668874; Sun, 15 Aug 2021 23:46:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Gnv7c283Wz4rQ3; Sun, 15 Aug 2021 23:46:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 2E6151F0D0; Sun, 15 Aug 2021 23:46:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 17FNk4Ev019329; Sun, 15 Aug 2021 23:46:04 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 17FNk4FS019328; Sun, 15 Aug 2021 23:46:04 GMT (envelope-from git) Date: Sun, 15 Aug 2021 23:46:04 GMT Message-Id: <202108152346.17FNk4FS019328@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: a54cdded3d65 - stable/13 - nfscl: Cache an open stateid for the "oneopenown" mount option MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: a54cdded3d6570997b8216df003767d663856533 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Aug 2021 23:46:04 -0000 The branch stable/13 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=a54cdded3d6570997b8216df003767d663856533 commit a54cdded3d6570997b8216df003767d663856533 Author: Rick Macklem AuthorDate: 2021-07-28 22:48:27 +0000 Commit: Rick Macklem CommitDate: 2021-08-15 23:41:18 +0000 nfscl: Cache an open stateid for the "oneopenown" mount option For NFSv4.1/4.2, if the "oneopenown" mount option is used, there is, at most, only one open stateid for each NFS vnode. When an open stateid for a file is acquired, set a pointer to the open structure in the NFS vnode. This pointer can be used to acquire the open stateid without searching the open linked list when the following is true: - No delegations have been issued for the file. Since delegations can outlive an NFS vnode for a file, use the global NFSMNTP_DELEGISSUED flag on the mount to determine this. - No lock stateid has been issued for the file. To determine this, a new NFS vnode flag called NMIGHTBELOCKED is set when a lock stateid is issued, which can then be tested. When this open structure pointer can be used, it avoids the need to acquire the NFSCLSTATELOCK() and searching the open structure list for an open. The NFSCLSTATELOCK() can be highly contended when there are a lot of opens issued for the NFSv4.1/4.2 mount. This patch only affects NFSv4.1/4.2 mounts when the "oneopenown" mount option is used. (cherry picked from commit efea1bc1fd93831c29fa7594d67094e0c125fb88) --- sys/fs/nfsclient/nfs_clnode.c | 11 ++++++++--- sys/fs/nfsclient/nfs_clrpcops.c | 8 +++++++- sys/fs/nfsclient/nfs_clstate.c | 36 ++++++++++++++++++++++++++++++++++++ sys/fs/nfsclient/nfs_clvnops.c | 17 +++++++++++++++++ sys/fs/nfsclient/nfsnode.h | 2 ++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index 1c0e855ff5a9..9718c2c36a3c 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -243,7 +243,11 @@ ncl_inactive(struct vop_inactive_args *ap) boolean_t retv; td = curthread; + np = VTONFS(vp); if (NFS_ISV4(vp) && vp->v_type == VREG) { + NFSLOCKNODE(np); + np->n_openstateid = NULL; + NFSUNLOCKNODE(np); /* * Since mmap()'d files do I/O after VOP_CLOSE(), the NFSv4 * Close operations are delayed until now. Any dirty @@ -263,7 +267,6 @@ ncl_inactive(struct vop_inactive_args *ap) } } - np = VTONFS(vp); NFSLOCKNODE(np); ncl_releasesillyrename(vp, td); @@ -303,9 +306,10 @@ ncl_reclaim(struct vop_reclaim_args *ap) NFSLOCKNODE(np); ncl_releasesillyrename(vp, td); - NFSUNLOCKNODE(np); if (NFS_ISV4(vp) && vp->v_type == VREG) { + np->n_openstateid = NULL; + NFSUNLOCKNODE(np); /* * We can now safely close any remaining NFSv4 Opens for * this file. Most opens will have already been closed by @@ -325,7 +329,8 @@ ncl_reclaim(struct vop_reclaim_args *ap) nfscl_delegreturnvp(vp, td); } else MNT_IUNLOCK(mp); - } + } else + NFSUNLOCKNODE(np); vfs_hash_remove(vp); diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 6093f7c0adeb..2f6226e38415 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -457,8 +457,14 @@ else printf(" fhl=0\n"); * If error is non-zero, don't increment it, since the Open * hasn't succeeded yet. */ - if (!error) + if (!error) { op->nfso_opencnt++; + if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) { + NFSLOCKNODE(np); + np->n_openstateid = op; + NFSUNLOCKNODE(np); + } + } nfscl_openrelease(nmp, op, error, newone); if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 406dcc9d9b80..b90b500cc7a9 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -547,6 +547,34 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode, return (EISDIR); np = VTONFS(vp); nmp = VFSTONFS(vp->v_mount); + + /* + * For "oneopenown" mounts, first check for a cached open in the + * NFS vnode, that can be used as a stateid. This can only be + * done if no delegations have been issued to the mount and no + * byte range file locking has been done for the file. + */ + if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp) && fords == 0) { + NFSLOCKMNT(nmp); + NFSLOCKNODE(np); + if ((nmp->nm_privflag & NFSMNTP_DELEGISSUED) == 0 && + (np->n_flag & NMIGHTBELOCKED) == 0 && + np->n_openstateid != NULL) { + stateidp->seqid = 0; + stateidp->other[0] = + np->n_openstateid->nfso_stateid.other[0]; + stateidp->other[1] = + np->n_openstateid->nfso_stateid.other[1]; + stateidp->other[2] = + np->n_openstateid->nfso_stateid.other[2]; + NFSUNLOCKNODE(np); + NFSUNLOCKMNT(nmp); + return (0); + } + NFSUNLOCKNODE(np); + NFSUNLOCKMNT(nmp); + } + NFSLOCKCLSTATE(); clp = nfscl_findcl(nmp); if (clp == NULL) { @@ -4301,9 +4329,17 @@ nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp, { struct nfscllockowner *nlp; struct nfsfh *nfhp; + struct nfsnode *np; u_int64_t off, len; int error, newone, donelocally; + if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) { + np = VTONFS(vp); + NFSLOCKNODE(np); + np->n_flag |= NMIGHTBELOCKED; + NFSUNLOCKNODE(np); + } + off = lop->nfslo_first; len = lop->nfslo_end - lop->nfslo_first; error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p, diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 2311ea099042..72d9eac8e962 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -3166,6 +3166,7 @@ nfs_advlock(struct vop_advlock_args *ap) struct vattr va; int ret, error; u_quad_t size; + struct nfsmount *nmp; error = NFSVOPLOCK(vp, LK_SHARED); if (error != 0) @@ -3195,6 +3196,22 @@ nfs_advlock(struct vop_advlock_args *ap) ap->a_flags)) (void) ncl_flush(vp, MNT_WAIT, td, 1, 0); + /* + * Mark NFS node as might have acquired a lock. + * This is separate from NHASBEENLOCKED, because it must + * be done before the nfsrpc_advlock() call, which might + * add a nfscllock structure to the client state. + * It is used to check for the case where a nfscllock + * state structure cannot exist for the file. + * Only done for "oneopenown" NFSv4.1/4.2 mounts. + */ + nmp = VFSTONFS(vp->v_mount); + if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) { + NFSLOCKNODE(np); + np->n_flag |= NMIGHTBELOCKED; + NFSUNLOCKNODE(np); + } + /* * Loop around doing the lock op, while a blocking lock * must wait for the lock op to succeed. diff --git a/sys/fs/nfsclient/nfsnode.h b/sys/fs/nfsclient/nfsnode.h index 66a2de31551a..b34e362a8522 100644 --- a/sys/fs/nfsclient/nfsnode.h +++ b/sys/fs/nfsclient/nfsnode.h @@ -128,6 +128,7 @@ struct nfsnode { u_int64_t n_change; /* old Change attribute */ struct nfsv4node *n_v4; /* extra V4 stuff */ struct ucred *n_writecred; /* Cred. for putpages */ + struct nfsclopen *n_openstateid; /* Cached open stateid */ }; #define n_atim n_un1.nf_atim @@ -164,6 +165,7 @@ struct nfsnode { #define NHASBEENLOCKED 0x00080000 /* Has been file locked. */ #define NDSCOMMIT 0x00100000 /* Commit is done via the DS. */ #define NVNSETSZSKIP 0x00200000 /* Skipped vnode_pager_setsize() */ +#define NMIGHTBELOCKED 0x00400000 /* Might be file locked. */ /* * Convert between nfsnode pointers and vnode pointers