From nobody Fri Jul 05 01:14:43 2024 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4WFbCR3S72z5Ps05; Fri, 05 Jul 2024 01:14:43 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4WFbCR35CLz4v0n; Fri, 5 Jul 2024 01:14:43 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1720142083; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sFaLrhYOyDGwI6QTXLFnKR9LEx6VfjFW4EOnWKyKX1M=; b=Utk6EGC6c0L803Aw2D22HLfLoc1Kz0nNAhFNU9ZapWduppUX2WRTO8ETwgGYh7kfPmTlsv wnRfR3/haw2EvSO8OoScoxYgxdDt5QeuDMwLKRyIj6FwzndVGwNFikdMQScBP5w67voqDo WEjQOg5mO2oqBB52eNhZvZegCETy3GTyNZYlTG9E2t3L2uXUwRlCl46sbByP3NfaOXS7vG etSp2LDjg/Yo5NLViT4AGoBd99RIW7QXT/Gaih5XfDukj2JkHABFXy3wKl4QyO+Zm348Tl 1BN7OST9HT71KOlOVzwpB3B9PgyofhgW0sujlJWhp7IckxmmKmnFW0eUAi+/mA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1720142083; a=rsa-sha256; cv=none; b=BahF/UwlDy82g8nfqTyg1XOkuLY2tCIOquTO8JTGPsfSdiT1kRiGp91x6n87i8H+CFCFkY u6Cbe12yFrtWnFonZm2cuDqcesHCkz0eaiBRsk8uhQLa1DCX8ilM18RN7RO1diDt+GRXZe kAfEIWjXg/nnWhKG8vgSCVsMpLJFVz2U1nJbyG4oeNRTQ2Ltcjs9yXXK622GomrnatjTxj 7dgTMGfHq6Y6rmYKRAvL4r2UVK4tq9bbi6nowkepA64IIAQn3hwcYtBYgeT4dWgmqd4nEW S9oU3XrIOHw9K8jV++qE6wc5lz8S2QgeJTHVxWfTIQ5ff0V5j/ZZaq/V98jN0Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1720142083; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sFaLrhYOyDGwI6QTXLFnKR9LEx6VfjFW4EOnWKyKX1M=; b=vSTB02m7NxIBgIye39CRX5c4TwsuLbNHPLQxHADvfiVyNRDDi5jft3vLOhfxmqeHMR1Ga5 ugMCqgoU/Ytyi9femSl5HEYXnNtStkov6Ly5lXV8CMNq+l1kQS+UDuYI4YB+3pBJNPnCl9 eXfSTva9jknnIyxfytQseVtUBjsBIMD8kVRY+vAWNAL54xbTBDF0Ibv8a4GqxxGyYUHk+w gBjBz1/QPWkVPTnHjfQJjH2zkQsg7A+fSxnlRQ5hNMD76UXcdqHtwX3xvNK6XtPGQs+L8P AMcRanggLr0a0upGzrqSN3EmnqBvgklJ/KUCweiAonHDkg3hD4KF6Ks2OnAhPQ== 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 4WFbCR2h05zclY; Fri, 5 Jul 2024 01:14:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4651EhLx082186; Fri, 5 Jul 2024 01:14:43 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4651Ehfv082183; Fri, 5 Jul 2024 01:14:43 GMT (envelope-from git) Date: Fri, 5 Jul 2024 01:14:43 GMT Message-Id: <202407050114.4651Ehfv082183@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: 98c53b0b5540 - stable/14 - nfsd: Fix delegation handled for atomic upgrade List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org 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/14 X-Git-Reftype: branch X-Git-Commit: 98c53b0b55401eaed374b235a40f3a547a5ab4e9 Auto-Submitted: auto-generated The branch stable/14 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=98c53b0b55401eaed374b235a40f3a547a5ab4e9 commit 98c53b0b55401eaed374b235a40f3a547a5ab4e9 Author: Rick Macklem AuthorDate: 2024-06-05 01:46:41 +0000 Commit: Rick Macklem CommitDate: 2024-07-05 01:12:26 +0000 nfsd: Fix delegation handled for atomic upgrade For NFSv4.1/4.2, an atomic upgrade of a delegation from a read delegation to a write delegation is allowed and can result in signoficantly improved performance. This patch adds support for this atomic upgrade, plus fixes a couple of other delegation related bugs. Since there were three cases where delegations were being issued, the patch factors this out into a separate function called nfsrv_issuedelegations(). This patch should only affect the NFSv4.1/4.2 behaviour when delegations are enabled, which is not the default. (cherry picked from commit e2c9fad2e0ae3f7049831bf7f2be1a3573363cdc) --- sys/fs/nfsserver/nfs_nfsdserv.c | 7 + sys/fs/nfsserver/nfs_nfsdstate.c | 297 ++++++++++++++++++--------------------- 2 files changed, 141 insertions(+), 163 deletions(-) diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index 0c8bda6dc6a6..47e3a20390f4 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -3244,6 +3244,13 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); *tl = newnfs_false; + } else if ((rflags & + NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE); + } else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE); } else { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index c73840277022..ce3f3481f04a 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -240,6 +240,11 @@ static int nfsrv_createdsfile(vnode_t vp, fhandle_t *fhp, struct pnfsdsfile *pf, static struct nfsdevice *nfsrv_findmirroredds(struct nfsmount *nmp); static int nfsrv_checkmachcred(int op, struct nfsrv_descript *nd, struct nfsclient *clp); +static void nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp, + struct nfsrv_descript *nd, int delegate, int writedeleg, int readonly, + u_quad_t filerev, uint64_t rdonly, struct nfsstate **new_delegp, + struct nfsstate *new_stp, struct nfslockfile *lfp, uint32_t *rflagsp, + nfsv4stateid_t *delegstateidp); /* * Scan the client list for a match and either return the current one, @@ -442,7 +447,8 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, /* * If the verifier has changed, the client has rebooted * and a new client id is issued. The old state info - * can be thrown away once the SETCLIENTID_CONFIRM occurs. + * can be thrown away once the SetClientID_Confirm or + * Create_Session that confirms the clientid occurs. */ LIST_REMOVE(clp, lc_hash); @@ -2648,6 +2654,8 @@ tryagain: * considered a conflict since the client with a read delegation * could have done an Open with ReadAccess and WriteDeny * locally and then not have checked for the WriteDeny.) + * The exception is a NFSv4.1/4.2 client that has requested + * an atomic upgrade to a write delegation. * Don't check for a Reclaim, since that will be dealt with * by nfsrv_openctrl(). */ @@ -2657,9 +2665,10 @@ tryagain: while (stp != LIST_END(&lfp->lf_deleg)) { nstp = LIST_NEXT(stp, ls_file); if ((readonly && stp->ls_clp != clp && - (stp->ls_flags & NFSLCK_DELEGWRITE)) || + (stp->ls_flags & NFSLCK_DELEGWRITE) != 0) || (!readonly && (stp->ls_clp != clp || - (stp->ls_flags & NFSLCK_DELEGREAD)))) { + ((stp->ls_flags & NFSLCK_DELEGREAD) != 0 && + (new_stp->ls_flags & NFSLCK_WANTWDELEG) == 0)))) { ret = nfsrv_delegconflict(stp, &haslock, p, vp); if (ret) { /* @@ -2944,6 +2953,8 @@ tryagain: * considered a conflict since the client with a read delegation * could have done an Open with ReadAccess and WriteDeny * locally and then not have checked for the WriteDeny.) + * The exception is a NFSv4.1/4.2 client that has requested + * an atomic upgrade to a write delegation. */ if (!(new_stp->ls_flags & (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR))) { stp = LIST_FIRST(&lfp->lf_deleg); @@ -2951,12 +2962,15 @@ tryagain: nstp = LIST_NEXT(stp, ls_file); if (stp->ls_clp != clp && (stp->ls_flags & NFSLCK_DELEGREAD)) writedeleg = 0; - else + else if (stp->ls_clp != clp || + (stp->ls_flags & NFSLCK_DELEGWRITE) != 0 || + (new_stp->ls_flags & NFSLCK_WANTWDELEG) == 0) delegate = 0; if ((readonly && stp->ls_clp != clp && - (stp->ls_flags & NFSLCK_DELEGWRITE)) || + (stp->ls_flags & NFSLCK_DELEGWRITE) != 0) || (!readonly && (stp->ls_clp != clp || - (stp->ls_flags & NFSLCK_DELEGREAD)))) { + ((stp->ls_flags & NFSLCK_DELEGREAD) != 0 && + (new_stp->ls_flags & NFSLCK_WANTWDELEG) == 0)))) { if (new_stp->ls_flags & NFSLCK_RECLAIM) { delegate = 2; } else { @@ -3204,47 +3218,9 @@ tryagain: /* * This is where we can choose to issue a delegation. */ - if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0) - *rflagsp |= NFSV4OPEN_WDNOTWANTED; - else if (nfsrv_issuedelegs == 0) - *rflagsp |= NFSV4OPEN_WDSUPPFTYPE; - else if (NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt)) - *rflagsp |= NFSV4OPEN_WDRESOURCE; - else if (delegate == 0 || writedeleg == 0 || - NFSVNO_EXRDONLY(exp) || (readonly != 0 && - nfsrv_writedelegifpos == 0) || - !NFSVNO_DELEGOK(vp) || - (new_stp->ls_flags & NFSLCK_WANTRDELEG) != 0 || - (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != - LCL_CALLBACKSON) - *rflagsp |= NFSV4OPEN_WDCONTENTION; - else { - new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; - new_deleg->ls_stateid.other[0] = delegstateidp->other[0] - = clp->lc_clientid.lval[0]; - new_deleg->ls_stateid.other[1] = delegstateidp->other[1] - = clp->lc_clientid.lval[1]; - new_deleg->ls_stateid.other[2] = delegstateidp->other[2] - = nfsrv_nextstateindex(clp); - new_deleg->ls_flags = (NFSLCK_DELEGWRITE | - NFSLCK_READACCESS | NFSLCK_WRITEACCESS); - *rflagsp |= NFSV4OPEN_WRITEDELEGATE; - new_deleg->ls_uid = new_stp->ls_uid; - new_deleg->ls_lfp = lfp; - new_deleg->ls_clp = clp; - new_deleg->ls_filerev = filerev; - new_deleg->ls_compref = nd->nd_compref; - new_deleg->ls_lastrecall = 0; - nfsrv_writedelegcnt++; - LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); - LIST_INSERT_HEAD(NFSSTATEHASH(clp, - new_deleg->ls_stateid), new_deleg, ls_hash); - LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); - new_deleg = NULL; - NFSD_VNET(nfsstatsv1_p)->srvdelegates++; - nfsrv_openpluslock++; - nfsrv_delegatecnt++; - } + nfsrv_issuedelegation(vp, clp, nd, delegate, writedeleg, + readonly, filerev, NFSVNO_EXRDONLY(exp), &new_deleg, + new_stp, lfp, rflagsp, delegstateidp); } else { new_open->ls_stateid.seqid = 1; new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; @@ -3269,52 +3245,9 @@ tryagain: /* * This is where we can choose to issue a delegation. */ - if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0) - *rflagsp |= NFSV4OPEN_WDNOTWANTED; - else if (nfsrv_issuedelegs == 0) - *rflagsp |= NFSV4OPEN_WDSUPPFTYPE; - else if (NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt)) - *rflagsp |= NFSV4OPEN_WDRESOURCE; - else if (delegate == 0 || (writedeleg == 0 && - readonly == 0) || !NFSVNO_DELEGOK(vp) || - (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != - LCL_CALLBACKSON) - *rflagsp |= NFSV4OPEN_WDCONTENTION; - else { - new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; - new_deleg->ls_stateid.other[0] = delegstateidp->other[0] - = clp->lc_clientid.lval[0]; - new_deleg->ls_stateid.other[1] = delegstateidp->other[1] - = clp->lc_clientid.lval[1]; - new_deleg->ls_stateid.other[2] = delegstateidp->other[2] - = nfsrv_nextstateindex(clp); - if (writedeleg && !NFSVNO_EXRDONLY(exp) && - (nfsrv_writedelegifpos || !readonly) && - (new_stp->ls_flags & NFSLCK_WANTRDELEG) == 0) { - new_deleg->ls_flags = (NFSLCK_DELEGWRITE | - NFSLCK_READACCESS | NFSLCK_WRITEACCESS); - *rflagsp |= NFSV4OPEN_WRITEDELEGATE; - nfsrv_writedelegcnt++; - } else { - new_deleg->ls_flags = (NFSLCK_DELEGREAD | - NFSLCK_READACCESS); - *rflagsp |= NFSV4OPEN_READDELEGATE; - } - new_deleg->ls_uid = new_stp->ls_uid; - new_deleg->ls_lfp = lfp; - new_deleg->ls_clp = clp; - new_deleg->ls_filerev = filerev; - new_deleg->ls_compref = nd->nd_compref; - new_deleg->ls_lastrecall = 0; - LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); - LIST_INSERT_HEAD(NFSSTATEHASH(clp, - new_deleg->ls_stateid), new_deleg, ls_hash); - LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); - new_deleg = NULL; - NFSD_VNET(nfsstatsv1_p)->srvdelegates++; - nfsrv_openpluslock++; - nfsrv_delegatecnt++; - } + nfsrv_issuedelegation(vp, clp, nd, delegate, writedeleg, + readonly, filerev, NFSVNO_EXRDONLY(exp), &new_deleg, + new_stp, lfp, rflagsp, delegstateidp); } } else { /* @@ -3337,78 +3270,28 @@ tryagain: if (new_stp->ls_flags & NFSLCK_RECLAIM) { new_stp->ls_flags = 0; } else if ((nd->nd_flag & ND_NFSV41) != 0) { - /* NFSv4.1 never needs confirmation. */ - new_stp->ls_flags = 0; + /* + * This is where we can choose to issue a delegation. + */ + nfsrv_issuedelegation(vp, clp, nd, delegate, writedeleg, + readonly, filerev, NFSVNO_EXRDONLY(exp), &new_deleg, + new_stp, lfp, rflagsp, delegstateidp); + /* NFSv4.1 never needs confirmation. */ + new_stp->ls_flags = 0; - /* - * This is where we can choose to issue a delegation. - */ - if (delegate && nfsrv_issuedelegs && - (writedeleg || readonly) && - (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == - LCL_CALLBACKSON && - !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && - NFSVNO_DELEGOK(vp) && - ((nd->nd_flag & ND_NFSV41) == 0 || - (new_stp->ls_flags & NFSLCK_WANTNODELEG) == 0)) { - new_deleg->ls_stateid.seqid = - delegstateidp->seqid = 1; - new_deleg->ls_stateid.other[0] = - delegstateidp->other[0] - = clp->lc_clientid.lval[0]; - new_deleg->ls_stateid.other[1] = - delegstateidp->other[1] - = clp->lc_clientid.lval[1]; - new_deleg->ls_stateid.other[2] = - delegstateidp->other[2] - = nfsrv_nextstateindex(clp); - if (writedeleg && !NFSVNO_EXRDONLY(exp) && - (nfsrv_writedelegifpos || !readonly) && - ((nd->nd_flag & ND_NFSV41) == 0 || - (new_stp->ls_flags & NFSLCK_WANTRDELEG) == - 0)) { - new_deleg->ls_flags = - (NFSLCK_DELEGWRITE | - NFSLCK_READACCESS | - NFSLCK_WRITEACCESS); - *rflagsp |= NFSV4OPEN_WRITEDELEGATE; - nfsrv_writedelegcnt++; - } else { - new_deleg->ls_flags = - (NFSLCK_DELEGREAD | - NFSLCK_READACCESS); - *rflagsp |= NFSV4OPEN_READDELEGATE; - } - new_deleg->ls_uid = new_stp->ls_uid; - new_deleg->ls_lfp = lfp; - new_deleg->ls_clp = clp; - new_deleg->ls_filerev = filerev; - new_deleg->ls_compref = nd->nd_compref; - new_deleg->ls_lastrecall = 0; - LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, - ls_file); - LIST_INSERT_HEAD(NFSSTATEHASH(clp, - new_deleg->ls_stateid), new_deleg, ls_hash); - LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, - ls_list); - new_deleg = NULL; - NFSD_VNET(nfsstatsv1_p)->srvdelegates++; - nfsrv_openpluslock++; - nfsrv_delegatecnt++; - } - /* - * Since NFSv4.1 never does an OpenConfirm, the first - * open state will be acquired here. - */ - if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) { - clp->lc_flags |= LCL_STAMPEDSTABLE; - len = clp->lc_idlen; - NFSBCOPY(clp->lc_id, clidp, len); - gotstate = 1; - } + /* + * Since NFSv4.1 never does an OpenConfirm, the first + * open state will be acquired here. + */ + if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) { + clp->lc_flags |= LCL_STAMPEDSTABLE; + len = clp->lc_idlen; + NFSBCOPY(clp->lc_id, clidp, len); + gotstate = 1; + } } else { - *rflagsp |= NFSV4OPEN_RESULTCONFIRM; - new_stp->ls_flags = NFSLCK_NEEDSCONFIRM; + *rflagsp |= NFSV4OPEN_RESULTCONFIRM; + new_stp->ls_flags = NFSLCK_NEEDSCONFIRM; } nfsrvd_refcache(new_stp->ls_op); new_stp->ls_noopens = 0; @@ -5179,6 +5062,11 @@ nfsrv_markreclaim(struct nfsclient *clp) * Now, just set the flag. */ sp->nst_flag |= NFSNST_RECLAIMED; + + /* + * Free up any old delegations. + */ + nfsrv_freedeleglist(&clp->lc_olddeleg); } /* @@ -8943,3 +8831,86 @@ nfsrv_checkmachcred(int op, struct nfsrv_descript *nd, struct nfsclient *clp) return (0); return (NFSERR_AUTHERR | AUTH_TOOWEAK); } + +/* + * Issue a delegation and, optionally set rflagsp for why not. + */ +static void +nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp, + struct nfsrv_descript *nd, int delegate, int writedeleg, int readonly, + u_quad_t filerev, uint64_t rdonly, struct nfsstate **new_delegp, + struct nfsstate *new_stp, struct nfslockfile *lfp, uint32_t *rflagsp, + nfsv4stateid_t *delegstateidp) +{ + struct nfsstate *up_deleg, *new_deleg; + + new_deleg = *new_delegp; + up_deleg = LIST_FIRST(&lfp->lf_deleg); + if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0) + *rflagsp |= NFSV4OPEN_WDNOTWANTED; + else if (nfsrv_issuedelegs == 0) + *rflagsp |= NFSV4OPEN_WDSUPPFTYPE; + else if (NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt)) + *rflagsp |= NFSV4OPEN_WDRESOURCE; + else if (delegate == 0 || !NFSVNO_DELEGOK(vp) || + (writedeleg == 0 && (readonly == 0 || + (new_stp->ls_flags & NFSLCK_WANTWDELEG) != 0)) || + (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != + LCL_CALLBACKSON) { + /* Is this a downgrade attempt? */ + if (up_deleg != NULL && up_deleg->ls_clp == clp && + (up_deleg->ls_flags & NFSLCK_DELEGWRITE) != 0 && + (new_stp->ls_flags & NFSLCK_WANTRDELEG) != 0) + *rflagsp |= NFSV4OPEN_WDNOTSUPPDOWNGRADE; + else + *rflagsp |= NFSV4OPEN_WDCONTENTION; + } else if (up_deleg != NULL && + (up_deleg->ls_flags & NFSLCK_DELEGREAD) != 0 && + (new_stp->ls_flags & NFSLCK_WANTWDELEG) != 0) { + /* This is an atomic upgrade. */ + up_deleg->ls_stateid.seqid++; + delegstateidp->seqid = up_deleg->ls_stateid.seqid; + delegstateidp->other[0] = up_deleg->ls_stateid.other[0]; + delegstateidp->other[1] = up_deleg->ls_stateid.other[1]; + delegstateidp->other[2] = up_deleg->ls_stateid.other[2]; + up_deleg->ls_flags = (NFSLCK_DELEGWRITE | + NFSLCK_READACCESS | NFSLCK_WRITEACCESS); + *rflagsp |= NFSV4OPEN_WRITEDELEGATE; + nfsrv_writedelegcnt++; + } else { + new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1; + new_deleg->ls_stateid.other[0] = delegstateidp->other[0] + = clp->lc_clientid.lval[0]; + new_deleg->ls_stateid.other[1] = delegstateidp->other[1] + = clp->lc_clientid.lval[1]; + new_deleg->ls_stateid.other[2] = delegstateidp->other[2] + = nfsrv_nextstateindex(clp); + if (writedeleg && !rdonly && + (nfsrv_writedelegifpos || !readonly) && + (new_stp->ls_flags & (NFSLCK_WANTRDELEG | + NFSLCK_WANTWDELEG)) != NFSLCK_WANTRDELEG) { + new_deleg->ls_flags = (NFSLCK_DELEGWRITE | + NFSLCK_READACCESS | NFSLCK_WRITEACCESS); + *rflagsp |= NFSV4OPEN_WRITEDELEGATE; + nfsrv_writedelegcnt++; + } else { + new_deleg->ls_flags = (NFSLCK_DELEGREAD | + NFSLCK_READACCESS); + *rflagsp |= NFSV4OPEN_READDELEGATE; + } + new_deleg->ls_uid = new_stp->ls_uid; + new_deleg->ls_lfp = lfp; + new_deleg->ls_clp = clp; + new_deleg->ls_filerev = filerev; + new_deleg->ls_compref = nd->nd_compref; + new_deleg->ls_lastrecall = 0; + LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); + LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_deleg->ls_stateid), + new_deleg, ls_hash); + LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); + *new_delegp = NULL; + NFSD_VNET(nfsstatsv1_p)->srvdelegates++; + nfsrv_openpluslock++; + nfsrv_delegatecnt++; + } +}