NFSD: add support for CB_GETATTR callback
[sfrench/cifs-2.6.git] / fs / nfsd / nfs4callback.c
index 4039ffcf90ba5879bb38583b4a11efeb729f49e6..92bc109dabe6381e3012d1df9e979ecbdbe09bf1 100644 (file)
@@ -84,7 +84,21 @@ static void encode_uint32(struct xdr_stream *xdr, u32 n)
 static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap,
                           size_t len)
 {
-       WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0);
+       xdr_stream_encode_uint32_array(xdr, bitmap, len);
+}
+
+static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
+                               struct nfs4_cb_fattr *fattr)
+{
+       fattr->ncf_cb_change = 0;
+       fattr->ncf_cb_fsize = 0;
+       if (bitmap[0] & FATTR4_WORD0_CHANGE)
+               if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_change) < 0)
+                       return -NFSERR_BAD_XDR;
+       if (bitmap[0] & FATTR4_WORD0_SIZE)
+               if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_fsize) < 0)
+                       return -NFSERR_BAD_XDR;
+       return 0;
 }
 
 /*
@@ -357,6 +371,30 @@ encode_cb_recallany4args(struct xdr_stream *xdr,
        hdr->nops++;
 }
 
+/*
+ * CB_GETATTR4args
+ *     struct CB_GETATTR4args {
+ *        nfs_fh4 fh;
+ *        bitmap4 attr_request;
+ *     };
+ *
+ * The size and change attributes are the only one
+ * guaranteed to be serviced by the client.
+ */
+static void
+encode_cb_getattr4args(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr,
+                       struct nfs4_cb_fattr *fattr)
+{
+       struct nfs4_delegation *dp =
+               container_of(fattr, struct nfs4_delegation, dl_cb_fattr);
+       struct knfsd_fh *fh = &dp->dl_stid.sc_file->fi_fhandle;
+
+       encode_nfs_cb_opnum4(xdr, OP_CB_GETATTR);
+       encode_nfs_fh4(xdr, fh);
+       encode_bitmap4(xdr, fattr->ncf_cb_bmap, ARRAY_SIZE(fattr->ncf_cb_bmap));
+       hdr->nops++;
+}
+
 /*
  * CB_SEQUENCE4args
  *
@@ -492,6 +530,26 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
        xdr_reserve_space(xdr, 0);
 }
 
+/*
+ * 20.1.  Operation 3: CB_GETATTR - Get Attributes
+ */
+static void nfs4_xdr_enc_cb_getattr(struct rpc_rqst *req,
+               struct xdr_stream *xdr, const void *data)
+{
+       const struct nfsd4_callback *cb = data;
+       struct nfs4_cb_fattr *ncf =
+               container_of(cb, struct nfs4_cb_fattr, ncf_getattr);
+       struct nfs4_cb_compound_hdr hdr = {
+               .ident = cb->cb_clp->cl_cb_ident,
+               .minorversion = cb->cb_clp->cl_minorversion,
+       };
+
+       encode_cb_compound4args(xdr, &hdr);
+       encode_cb_sequence4args(xdr, cb, &hdr);
+       encode_cb_getattr4args(xdr, &hdr, ncf);
+       encode_cb_nops(&hdr);
+}
+
 /*
  * 20.2. Operation 4: CB_RECALL - Recall a Delegation
  */
@@ -547,6 +605,42 @@ static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
        return 0;
 }
 
+/*
+ * 20.1.  Operation 3: CB_GETATTR - Get Attributes
+ */
+static int nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp,
+                                 struct xdr_stream *xdr,
+                                 void *data)
+{
+       struct nfsd4_callback *cb = data;
+       struct nfs4_cb_compound_hdr hdr;
+       int status;
+       u32 bitmap[3] = {0};
+       u32 attrlen;
+       struct nfs4_cb_fattr *ncf =
+               container_of(cb, struct nfs4_cb_fattr, ncf_getattr);
+
+       status = decode_cb_compound4res(xdr, &hdr);
+       if (unlikely(status))
+               return status;
+
+       status = decode_cb_sequence4res(xdr, cb);
+       if (unlikely(status || cb->cb_seq_status))
+               return status;
+
+       status = decode_cb_op_status(xdr, OP_CB_GETATTR, &cb->cb_status);
+       if (status)
+               return status;
+       if (xdr_stream_decode_uint32_array(xdr, bitmap, 3) < 0)
+               return -NFSERR_BAD_XDR;
+       if (xdr_stream_decode_u32(xdr, &attrlen) < 0)
+               return -NFSERR_BAD_XDR;
+       if (attrlen > (sizeof(ncf->ncf_cb_change) + sizeof(ncf->ncf_cb_fsize)))
+               return -NFSERR_BAD_XDR;
+       status = decode_cb_fattr4(xdr, bitmap, ncf);
+       return status;
+}
+
 /*
  * 20.2. Operation 4: CB_RECALL - Recall a Delegation
  */
@@ -855,6 +949,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[] = {
        PROC(CB_NOTIFY_LOCK,    COMPOUND,       cb_notify_lock, cb_notify_lock),
        PROC(CB_OFFLOAD,        COMPOUND,       cb_offload,     cb_offload),
        PROC(CB_RECALL_ANY,     COMPOUND,       cb_recall_any,  cb_recall_any),
+       PROC(CB_GETATTR,        COMPOUND,       cb_getattr,     cb_getattr),
 };
 
 static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)];