NFSv4: Plumb in XDR support for the new delegation-only setattr op
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 17 Jun 2024 01:21:22 +0000 (21:21 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Mon, 8 Jul 2024 17:47:25 +0000 (13:47 -0400)
We want to send the updated atime and mtime as part of the delegreturn
compound. Add a special structure to hold those variables.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
include/linux/nfs_xdr.h

index 90df37f3866a0344fa2a9140efcf7b782cbbe66f..af07582101629e234d8cea89b2dc6a981b1ee621 100644 (file)
@@ -6575,6 +6575,7 @@ struct nfs4_delegreturndata {
                u32 roc_barrier;
                bool roc;
        } lr;
+       struct nfs4_delegattr sattr;
        struct nfs_fattr fattr;
        int rpc_status;
        struct inode *inode;
@@ -6599,6 +6600,30 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                          &data->res.lr_ret) == -EAGAIN)
                goto out_restart;
 
+       if (data->args.sattr_args && task->tk_status != 0) {
+               switch(data->res.sattr_ret) {
+               case 0:
+                       data->args.sattr_args = NULL;
+                       data->res.sattr_res = false;
+                       break;
+               case -NFS4ERR_ADMIN_REVOKED:
+               case -NFS4ERR_DELEG_REVOKED:
+               case -NFS4ERR_EXPIRED:
+               case -NFS4ERR_BAD_STATEID:
+                       /* Let the main handler below do stateid recovery */
+                       break;
+               case -NFS4ERR_OLD_STATEID:
+                       if (nfs4_refresh_delegation_stateid(&data->stateid,
+                                               data->inode))
+                               goto out_restart;
+                       fallthrough;
+               default:
+                       data->args.sattr_args = NULL;
+                       data->res.sattr_res = false;
+                       goto out_restart;
+               }
+       }
+
        switch (task->tk_status) {
        case 0:
                renew_lease(data->res.server, data->timestamp);
index 119061da52989d20d16dc6c52fa29439913defc9..4c22b865b9c9a9c6fc43ada4c5c3b093d3024fe7 100644 (file)
@@ -224,6 +224,11 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                                 encode_attrs_maxsz)
 #define decode_setattr_maxsz   (op_decode_hdr_maxsz + \
                                 nfs4_fattr_bitmap_maxsz)
+#define encode_delegattr_maxsz (op_encode_hdr_maxsz + \
+                                encode_stateid_maxsz + \
+                               nfs4_fattr_bitmap_maxsz + \
+                               2*nfstime4_maxsz)
+#define decode_delegattr_maxsz (decode_setattr_maxsz)
 #define encode_read_maxsz      (op_encode_hdr_maxsz + \
                                 encode_stateid_maxsz + 3)
 #define decode_read_maxsz      (op_decode_hdr_maxsz + 2 + pagepad_maxsz)
@@ -758,12 +763,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
                                encode_layoutreturn_maxsz + \
+                               encode_delegattr_maxsz + \
                                encode_delegreturn_maxsz + \
                                encode_getattr_maxsz)
 #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
                                decode_layoutreturn_maxsz + \
+                               decode_delegattr_maxsz + \
                                decode_delegreturn_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_getacl_sz     (compound_encode_hdr_maxsz + \
@@ -1735,6 +1742,33 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
                        server->attr_bitmask);
 }
 
+static void encode_delegattr(struct xdr_stream *xdr,
+               const nfs4_stateid *stateid,
+               const struct nfs4_delegattr *attr,
+               struct compound_hdr *hdr)
+{
+       uint32_t bitmap[3] = { 0 };
+       uint32_t len = 0;
+       __be32 *p;
+
+       encode_op_hdr(xdr, OP_SETATTR, encode_delegattr_maxsz, hdr);
+       encode_nfs4_stateid(xdr, stateid);
+       if (attr->atime_set) {
+               bitmap[2] |= FATTR4_WORD2_TIME_DELEG_ACCESS;
+               len += (nfstime4_maxsz << 2);
+       }
+       if (attr->mtime_set) {
+               bitmap[2] |= FATTR4_WORD2_TIME_DELEG_MODIFY;
+               len += (nfstime4_maxsz << 2);
+       }
+       xdr_encode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+       xdr_stream_encode_opaque_inline(xdr, (void **)&p, len);
+       if (bitmap[2] & FATTR4_WORD2_TIME_DELEG_ACCESS)
+               p = xdr_encode_nfstime4(p, &attr->atime);
+       if (bitmap[2] & FATTR4_WORD2_TIME_DELEG_MODIFY)
+               p = xdr_encode_nfstime4(p, &attr->mtime);
+}
+
 static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
 {
        __be32 *p;
@@ -2812,6 +2846,8 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
        encode_putfh(xdr, args->fhandle, &hdr);
        if (args->lr_args)
                encode_layoutreturn(xdr, args->lr_args, &hdr);
+       if (args->sattr_args)
+               encode_delegattr(xdr, args->stateid, args->sattr_args, &hdr);
        if (args->bitmask)
                encode_getfattr(xdr, args->bitmask, &hdr);
        encode_delegreturn(xdr, args->stateid, &hdr);
@@ -5163,9 +5199,11 @@ static int decode_rw_delegation(struct xdr_stream *xdr,
 
        switch (res->open_delegation_type) {
        case NFS4_OPEN_DELEGATE_READ:
+       case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
                res->type = FMODE_READ;
                break;
        case NFS4_OPEN_DELEGATE_WRITE:
+       case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
                res->type = FMODE_WRITE|FMODE_READ;
                if (decode_space_limit(xdr, &res->pagemod_limit) < 0)
                                return -EIO;
@@ -5207,6 +5245,8 @@ static int decode_delegation(struct xdr_stream *xdr,
                return 0;
        case NFS4_OPEN_DELEGATE_READ:
        case NFS4_OPEN_DELEGATE_WRITE:
+       case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
+       case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
                return decode_rw_delegation(xdr, res);
        case NFS4_OPEN_DELEGATE_NONE_EXT:
                return decode_no_delegation(xdr, res);
@@ -5480,6 +5520,11 @@ static int decode_setattr(struct xdr_stream *xdr)
        return -EIO;
 }
 
+static int decode_delegattr(struct xdr_stream *xdr)
+{
+       return decode_setattr(xdr);
+}
+
 static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
 {
        __be32 *p;
@@ -7052,6 +7097,12 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
                if (status)
                        goto out;
        }
+       if (res->sattr_res) {
+               status = decode_delegattr(xdr);
+               res->sattr_ret = status;
+               if (status)
+                       goto out;
+       }
        if (res->fattr) {
                status = decode_getfattr(xdr, res->fattr, res->server);
                if (status != 0)
index 682559e19d9d0c76e8a445c4437d3c5a59b2b357..f40be64ce9429c705b813204a8b6997134b81b73 100644 (file)
@@ -622,6 +622,13 @@ struct nfs_release_lockowner_res {
        struct nfs4_sequence_res        seq_res;
 };
 
+struct nfs4_delegattr {
+       struct timespec64       atime;
+       struct timespec64       mtime;
+       bool                    atime_set;
+       bool                    mtime_set;
+};
+
 struct nfs4_delegreturnargs {
        struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
@@ -629,6 +636,7 @@ struct nfs4_delegreturnargs {
        const u32 *bitmask;
        u32 bitmask_store[NFS_BITMASK_SZ];
        struct nfs4_layoutreturn_args *lr_args;
+       struct nfs4_delegattr *sattr_args;
 };
 
 struct nfs4_delegreturnres {
@@ -637,6 +645,8 @@ struct nfs4_delegreturnres {
        struct nfs_server *server;
        struct nfs4_layoutreturn_res *lr_res;
        int lr_ret;
+       bool sattr_res;
+       int sattr_ret;
 };
 
 /*