From nobody Wed Jun 05 01:48:53 2024 X-Original-To: dev-commits-src-all@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 4Vv9Nj6JQjz5NGkF; Wed, 05 Jun 2024 01:48:53 +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 4Vv9Nj5jXGz4XvS; Wed, 5 Jun 2024 01:48:53 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1717552133; 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=ygjKEz5anYAp3EAgXF/w3m4j+qy3/uw6lXkQ+zmqCD0=; b=nNJRndfp0Urpzk7f8JxQ4uS61wC4OXXff8EN7Utv0IhIKHTePAumlhZpN4Wu1EasnTtGWf pgsv6T9xsqN0yoaLep/6xdxc3oCdu6tFXVfSu3ZLuKGZ8qyZch0HEsMehW7X+TsaG/3t3/ nng34VzluT+yp0N0wxi+0+2u3AgZNISv9CQ531WypRsBX6rCz9tTvUHA5piHc5k/l5Gf6j 6ITMzOECb8s2sayqgHsSzVj0z0BTek5h8so2M2lFzVFjuyYz4K7sHJFos18KtaZ9U4hLRj 00JyPdkPlKQEVq38yNZG5xjh8aYWGlLPo5Ly1aisJPejZN1gFeJnRu4ZIIjgnQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1717552133; a=rsa-sha256; cv=none; b=U5t25xYngeYxX5q09ptDUIynrme+dCSNY5QWjME8neGT+GlTXZM9vq37y2Wm2Ehuancy/H YhX/AT2FrzwotaNwGqp+NM6x9vYujemoshL4C22qR4NiXfYsUQJrf2mqP2DNOujkQW/24Q 22l5CZHqoZlfD8J4SdnU5TN+IY2zIC4HqmSDjCotD5PTJB/yc18ePzlYteSiBIxDwi5PBS 1DAVUWaf7Gt6BnjPa5HzKwM6HwWWbXKq5LnamYWue/UyvngkmttU3K+bb5lYCqiGk7+OI2 tQjOO0zsmgiPJ7FKoYYB64x1c9i3XmJ88oPLopmIn8GgrKj0IRb6Jco9Jonbkg== 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=1717552133; 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=ygjKEz5anYAp3EAgXF/w3m4j+qy3/uw6lXkQ+zmqCD0=; b=W4SVkJywn0vpE3fhdbvD8erpQBtxg2RNk9ZDLxxMO8XptZOVb9y8WdvQHm46liz5LFK2e/ K/H31rPkYUav6CZvCXFXPPJR2hKYR4dsJArcMIyd5SpHvRRyzjIYc9/dYb0yY2PhmqugjJ 5ejOlRfOZm68RU1YGejuVjL096ufZYiHy8yKu6lRJbl81QdC3z2C8JgOBLeu7+ffHYA2fi egqqSW+TuCGaKIw674inq7QNWOQGo9+u9e4qA1EWDz28A7EWAYDBR0aw4Yq604fZhx5j4D uROZdIpOSHgzgvqCOug8qNTEsjQYz0IDGD8g0TbUriLUYxS1LnkxJUJZkhEGhQ== 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 4Vv9Nj5FbkzjGv; Wed, 5 Jun 2024 01:48:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 4551mrIu048350; Wed, 5 Jun 2024 01:48:53 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 4551mrBV048347; Wed, 5 Jun 2024 01:48:53 GMT (envelope-from git) Date: Wed, 5 Jun 2024 01:48:53 GMT Message-Id: <202406050148.4551mrBV048347@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: e2c9fad2e0ae - main - nfsd: Fix delegation handled for atomic upgrade List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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/main X-Git-Reftype: branch X-Git-Commit: e2c9fad2e0ae3f7049831bf7f2be1a3573363cdc Auto-Submitted: auto-generated The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=e2c9fad2e0ae3f7049831bf7f2be1a3573363cdc commit e2c9fad2e0ae3f7049831bf7f2be1a3573363cdc Author: Rick Macklem AuthorDate: 2024-06-05 01:46:41 +0000 Commit: Rick Macklem CommitDate: 2024-06-05 01:46:41 +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. MFC after: 1 month --- 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++; + } +}