Re: [PATCH 3/4] NFSD: add supports for CB_GETATTR callback

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hey Dai-

Jeff's a little better with the state-related code, so let
me start with a review of the new CB_GETATTR implementation.


> On May 11, 2023, at 2:43 PM, Dai Ngo <dai.ngo@xxxxxxxxxx> wrote:
> 
> Includes:
>   . CB_GETATTR proc for nfs4_cb_procedures[]
> 
>   . XDR encoding and decoding function for CB_GETATTR request/reply
> 
>   . add nfs4_cb_fattr to nfs4_delegation for sending CB_GETATTR
>     and store file attributes from client's reply.
> 
> Signed-off-by: Dai Ngo <dai.ngo@xxxxxxxxxx>
> ---
> fs/nfsd/nfs4callback.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++
> fs/nfsd/state.h        |  17 +++++++
> fs/nfsd/xdr4cb.h       |  19 ++++++++
> 3 files changed, 153 insertions(+)
> 
> diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
> index 4039ffcf90ba..ca3d72ef5fbc 100644
> --- a/fs/nfsd/nfs4callback.c
> +++ b/fs/nfsd/nfs4callback.c
> @@ -87,6 +87,43 @@ static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap,
> WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0);
> }
> 
> +static void decode_bitmap4(struct xdr_stream *xdr, __u32 *bitmap,
> +   size_t len)
> +{
> + WARN_ON_ONCE(xdr_stream_decode_uint32_array(xdr, bitmap, len) < 0);
> +}

encode_bitmap4() hides the WARN_ON_ONCE.

However, for decoding, we actually want to get the result
of the decode, so let's get rid of decode_bitmap4() and
simply call xdr_stream_decode_uint32_array() directly from
nfs4_xdr_dec_cb_getattr() (and, of course, check it's return
code properly, no WARN_ON).


> +
> +static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen)
> +{
> + __be32 *p;
> +
> + p = xdr_inline_decode(xdr, 4);
> + if (unlikely(!p))
> + return -EIO;
> + *attrlen = be32_to_cpup(p);
> + return 0;
> +}
> +
> +static int decode_cb_getattr(struct xdr_stream *xdr, uint32_t *bitmap,
> + struct nfs4_cb_fattr *fattr)
> +{
> + __be32 *ptr;
> +
> + if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
> + ptr = xdr_inline_decode(xdr, 8);
> + if (unlikely(!ptr))
> + return -EIO;
> + xdr_decode_hyper(ptr, &fattr->ncf_cb_cinfo);
> + }
> + if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
> + ptr = xdr_inline_decode(xdr, 8);
> + if (unlikely(!ptr))
> + return -EIO;
> + xdr_decode_hyper(ptr, &fattr->ncf_cb_fsize);
> + }

Let's use xdr_stream_decode_u64() for these.

Also, I don't think the likely() is necessary -- this
isn't performance-sensitive code.


> + return 0;
> +}
> +
> /*
>  * nfs_cb_opnum4
>  *
> @@ -358,6 +395,26 @@ encode_cb_recallany4args(struct xdr_stream *xdr,
> }
> 
> /*
> + * 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 knfsd_fh *fh, struct nfs4_cb_fattr *fattr)

Nit: Can this take just a "struct nfs4_cb_fattr *" parameter
instead of the filehandle and fattr?


> +{
> + 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
>  *
>  * struct CB_SEQUENCE4args {
> @@ -493,6 +550,29 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
> }
> 
> /*
> + * 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_delegation *dp =
> + container_of(ncf, struct nfs4_delegation, dl_cb_fattr);
> + 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,
> + &dp->dl_stid.sc_file->fi_fhandle, &dp->dl_cb_fattr);
> + encode_cb_nops(&hdr);
> +}
> +
> +/*
>  * 20.2. Operation 4: CB_RECALL - Recall a Delegation
>  */
> static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr,
> @@ -548,6 +628,42 @@ static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
> }
> 
> /*
> + * 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;
> + decode_bitmap4(xdr, bitmap, 3);
> + status = decode_attr_length(xdr, &attrlen);
> + if (status)
> + return status;

Let's use xdr_stream_decode_u32 directly here, and
check that attrlen is a reasonable value. Say, not
larger than the full expected array length?


> + ncf->ncf_cb_cinfo = 0;
> + ncf->ncf_cb_fsize = 0;
> + status = decode_cb_getattr(xdr, bitmap, ncf);
> + return status;

You're actually decoding a fattr4 here, not the whole
CB_GETATTR result. Can we call the function
decode_cb_fattr4() ?

Nit: Let's fold the initialization of cb_cinfo and
cb_fsize into decode_cb_fattr4().



> +}
> +
> +/*
>  * 20.2. Operation 4: CB_RECALL - Recall a Delegation
>  */
> static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
> @@ -855,6 +971,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)];
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index d49d3060ed4f..92349375053a 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -117,6 +117,19 @@ struct nfs4_cpntf_state {
> time64_t cpntf_time; /* last time stateid used */
> };
> 
> +struct nfs4_cb_fattr {
> + struct nfsd4_callback ncf_getattr;
> + u32 ncf_cb_status;
> + u32 ncf_cb_bmap[1];
> +
> + /* from CB_GETATTR reply */
> + u64 ncf_cb_cinfo;

In fs/nfsd/nfs4xdr.c, we use "cinfo" to mean change info:
that's a boolean, and a pair of 64-bit change attribute values.
IIUC, I don't think that's what this is; it's just a single
change attribute value.

To avoid overloading the name "cinfo" can you call this field
something like ncf_cb_change ?


> + u64 ncf_cb_fsize;
> +};
> +
> +/* bits for ncf_cb_flags */
> +#define CB_GETATTR_BUSY 0
> +
> /*
>  * Represents a delegation stateid. The nfs4_client holds references to these
>  * and they are put when it is being destroyed or when the delegation is
> @@ -150,6 +163,9 @@ struct nfs4_delegation {
> int dl_retries;
> struct nfsd4_callback dl_recall;
> bool dl_recalled;
> +
> + /* for CB_GETATTR */
> + struct nfs4_cb_fattr    dl_cb_fattr;
> };
> 
> #define cb_to_delegation(cb) \
> @@ -642,6 +658,7 @@ enum nfsd4_cb_op {
> NFSPROC4_CLNT_CB_SEQUENCE,
> NFSPROC4_CLNT_CB_NOTIFY_LOCK,
> NFSPROC4_CLNT_CB_RECALL_ANY,
> + NFSPROC4_CLNT_CB_GETATTR,
> };
> 
> /* Returns true iff a is later than b: */
> diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h
> index 0d39af1b00a0..3a31bb0a3ded 100644
> --- a/fs/nfsd/xdr4cb.h
> +++ b/fs/nfsd/xdr4cb.h
> @@ -54,3 +54,22 @@
> #define NFS4_dec_cb_recall_any_sz (cb_compound_dec_hdr_sz  +      \
> cb_sequence_dec_sz +            \
> op_dec_sz)
> +
> +/*
> + * 1: CB_GETATTR opcode (32-bit)
> + * N: file_handle
> + * 1: number of entry in attribute array (32-bit)
> + * 1: entry 0 in attribute array (32-bit)
> + */
> +#define NFS4_enc_cb_getattr_sz (cb_compound_enc_hdr_sz +       \
> + cb_sequence_enc_sz +            \
> + 1 + enc_nfs4_fh_sz + 1 + 1)
> +/*
> + * 1: attr mask (32-bit bmap)
> + * 2: length of attribute array (64-bit)

Isn't the array length field 32 bits?


> + * 2: change attr (64-bit)
> + * 2: size (64-bit)
> + */
> +#define NFS4_dec_cb_getattr_sz (cb_compound_dec_hdr_sz  +      \
> + cb_sequence_dec_sz + 7 + \

Generally we list the length of each item separately
to document the individual values, so:

1 + 1 + 2 + 2

is preferred over a single integer.


> + op_dec_sz)
> -- 
> 2.9.5
> 

--
Chuck Lever






[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux