nfsd41: implement NFS4_SHARE_WANT_NO_DELEG, NFS4_OPEN_DELEGATE_NONE_EXT, why_no_deleg
authorBenny Halevy <benny@tonian.com>
Thu, 16 Feb 2012 18:57:17 +0000 (20:57 +0200)
committerJ. Bruce Fields <bfields@redhat.com>
Fri, 17 Feb 2012 23:38:53 +0000 (18:38 -0500)
Respect client request for not getting a delegation in NFSv4.1
Appropriately return delegation "type" NFS4_OPEN_DELEGATE_NONE_EXT
and WND4_NOT_WANTED reason.

[nfsd41: add missing break when encoding op_why_no_deleg]
Signed-off-by: Benny Halevy <bhalevy@tonian.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/xdr4.h
include/linux/nfs4.h

index f1b74a74ec491cd93755ed88bff06e0daf58de0c..967c677c2e5413c9823126b242a15851d09edd0a 100644 (file)
@@ -2866,7 +2866,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
        int cb_up;
-       int status, flag = 0;
+       int status = 0, flag = 0;
 
        cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
        flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2907,11 +2907,32 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
        dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
                STATEID_VAL(&dp->dl_stid.sc_stateid));
 out:
-       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
-                       && flag == NFS4_OPEN_DELEGATE_NONE
-                       && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
+       if (flag == NFS4_OPEN_DELEGATE_NONE) {
+               if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
+                   open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
+                       dprintk("NFSD: WARNING: refusing delegation reclaim\n");
+
+               if (open->op_deleg_want) {
+                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+                       if (status == -EAGAIN)
+                               open->op_why_no_deleg = WND4_CONTENTION;
+                       else {
+                               open->op_why_no_deleg = WND4_RESOURCE;
+                               switch (open->op_deleg_want) {
+                               case NFS4_SHARE_WANT_READ_DELEG:
+                               case NFS4_SHARE_WANT_WRITE_DELEG:
+                               case NFS4_SHARE_WANT_ANY_DELEG:
+                                       break;
+                               case NFS4_SHARE_WANT_CANCEL:
+                                       open->op_why_no_deleg = WND4_CANCELLED;
+                                       break;
+                               case NFS4_SHARE_WANT_NO_DELEG:
+                                       BUG();  /* not supposed to get here */
+                               }
+                       }
+               }
+       }
        return;
 out_free:
        nfs4_put_delegation(dp);
@@ -2981,20 +3002,45 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
-       if (nfsd4_has_session(&resp->cstate))
+       if (nfsd4_has_session(&resp->cstate)) {
                open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
 
+               if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
+                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+                       open->op_why_no_deleg = WND4_NOT_WANTED;
+                       goto nodeleg;
+               }
+       }
+
        /*
        * Attempt to hand out a delegation. No error return, because the
        * OPEN succeeds even if we fail.
        */
        nfs4_open_delegation(current_fh, open, stp);
-
+nodeleg:
        status = nfs_ok;
 
        dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
                STATEID_VAL(&stp->st_stid.sc_stateid));
 out:
+       /* 4.1 client trying to upgrade/downgrade delegation? */
+       if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
+           open->op_deleg_want) {
+               if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
+                   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+                       open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
+               } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
+                          dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+                       open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
+               }
+               /* Otherwise the client must be confused wanting a delegation
+                * it already has, therefore we don't return
+                * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
+                */
+       }
+
        if (fp)
                put_nfs4_file(fp);
        if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
index a58f2064f47957545e3cbc387c3cd0b307ecd23e..f8fcddca0414410c1e38da919a512bc47aa3aba6 100644 (file)
@@ -2849,6 +2849,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
                WRITE32(0);   /* XXX: is NULL principal ok? */
                ADJUST_ARGS();
                break;
+       case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
+               switch (open->op_why_no_deleg) {
+               case WND4_CONTENTION:
+               case WND4_RESOURCE:
+                       RESERVE_SPACE(8);
+                       WRITE32(open->op_why_no_deleg);
+                       WRITE32(0);     /* deleg signaling not supported yet */
+                       break;
+               default:
+                       RESERVE_SPACE(4);
+                       WRITE32(open->op_why_no_deleg);
+               }
+               ADJUST_ARGS();
+               break;
        default:
                BUG();
        }
index 7110a082275f817d43555759320a5aba8cfacda3..b89781f1477a296bfc68fccfde608651608a4b18 100644 (file)
@@ -223,6 +223,7 @@ struct nfsd4_open {
        struct xdr_netobj op_fname;         /* request - everything but CLAIM_PREV */
        u32             op_delegate_type;   /* request - CLAIM_PREV only */
        stateid_t       op_delegate_stateid; /* request - response */
+       u32             op_why_no_deleg;    /* response - DELEG_NONE_EXT only */
        u32             op_create;          /* request */
        u32             op_createmode;      /* request */
        u32             op_bmval[3];        /* request */
index 32345c2805c0588bb2373b63e234359271fc7cfe..8cdde4d1fad86a9a3446bdf73e59550f5f87d251 100644 (file)
@@ -441,7 +441,20 @@ enum limit_by4 {
 enum open_delegation_type4 {
        NFS4_OPEN_DELEGATE_NONE = 0,
        NFS4_OPEN_DELEGATE_READ = 1,
-       NFS4_OPEN_DELEGATE_WRITE = 2
+       NFS4_OPEN_DELEGATE_WRITE = 2,
+       NFS4_OPEN_DELEGATE_NONE_EXT = 3, /* 4.1 */
+};
+
+enum why_no_delegation4 { /* new to v4.1 */
+       WND4_NOT_WANTED = 0,
+       WND4_CONTENTION = 1,
+       WND4_RESOURCE = 2,
+       WND4_NOT_SUPP_FTYPE = 3,
+       WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4,
+       WND4_NOT_SUPP_UPGRADE = 5,
+       WND4_NOT_SUPP_DOWNGRADE = 6,
+       WND4_CANCELLED = 7,
+       WND4_IS_DIR = 8,
 };
 
 enum lock_type4 {