nfsd: trivial GET_DIR_DELEGATION support
This adds basic infrastructure for handing GET_DIR_DELEGATION calls from clients, including the decoders and encoders. For now, it always just returns NFS4_OK + GDD4_UNAVAIL. Eventually clients may start sending this operation, and it's better if we can return GDD4_UNAVAIL instead of having to abort the whole compound. Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
38f080f3cd
commit
33a1e6ea73
@ -2154,6 +2154,29 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
return status == nfserr_same ? nfs_ok : status;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
|
||||
|
||||
/*
|
||||
* RFC 8881, section 18.39.3 says:
|
||||
*
|
||||
* "The server may refuse to grant the delegation. In that case, the
|
||||
* server will return NFS4ERR_DIRDELEG_UNAVAIL."
|
||||
*
|
||||
* This is sub-optimal, since it means that the server would need to
|
||||
* abort compound processing just because the delegation wasn't
|
||||
* available. RFC8881bis should change this to allow the server to
|
||||
* return NFS4_OK with a non-fatal status of GDD4_UNAVAIL in this
|
||||
* situation.
|
||||
*/
|
||||
gdd->gddrnf_status = GDD4_UNAVAIL;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
static const struct nfsd4_layout_ops *
|
||||
nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
|
||||
@ -3082,6 +3105,18 @@ static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp,
|
||||
* sizeof(__be32);
|
||||
}
|
||||
|
||||
static u32 nfsd4_get_dir_delegation_rsize(const struct svc_rqst *rqstp,
|
||||
const struct nfsd4_op *op)
|
||||
{
|
||||
return (op_encode_hdr_size +
|
||||
1 /* gddr_status */ +
|
||||
op_encode_verifier_maxsz +
|
||||
op_encode_stateid_maxsz +
|
||||
2 /* gddr_notification */ +
|
||||
2 /* gddr_child_attributes */ +
|
||||
2 /* gddr_dir_attributes */);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp,
|
||||
const struct nfsd4_op *op)
|
||||
@ -3470,6 +3505,12 @@ static const struct nfsd4_operation nfsd4_ops[] = {
|
||||
.op_get_currentstateid = nfsd4_get_freestateid,
|
||||
.op_rsize_bop = nfsd4_only_status_rsize,
|
||||
},
|
||||
[OP_GET_DIR_DELEGATION] = {
|
||||
.op_func = nfsd4_get_dir_delegation,
|
||||
.op_flags = OP_MODIFIES_SOMETHING,
|
||||
.op_name = "OP_GET_DIR_DELEGATION",
|
||||
.op_rsize_bop = nfsd4_get_dir_delegation_rsize,
|
||||
},
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
[OP_GETDEVICEINFO] = {
|
||||
.op_func = nfsd4_getdeviceinfo,
|
||||
|
@ -1732,6 +1732,35 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
|
||||
return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_get_dir_delegation(struct nfsd4_compoundargs *argp,
|
||||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
|
||||
__be32 status;
|
||||
|
||||
memset(gdd, 0, sizeof(*gdd));
|
||||
|
||||
if (xdr_stream_decode_bool(argp->xdr, &gdd->gdda_signal_deleg_avail) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
status = nfsd4_decode_bitmap4(argp, gdd->gdda_notification_types,
|
||||
ARRAY_SIZE(gdd->gdda_notification_types));
|
||||
if (status)
|
||||
return status;
|
||||
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_child_attr_delay);
|
||||
if (status)
|
||||
return status;
|
||||
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_dir_attr_delay);
|
||||
if (status)
|
||||
return status;
|
||||
status = nfsd4_decode_bitmap4(argp, gdd->gdda_child_attributes,
|
||||
ARRAY_SIZE(gdd->gdda_child_attributes));
|
||||
if (status)
|
||||
return status;
|
||||
return nfsd4_decode_bitmap4(argp, gdd->gdda_dir_attributes,
|
||||
ARRAY_SIZE(gdd->gdda_dir_attributes));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
static __be32
|
||||
nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
|
||||
@ -2370,7 +2399,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
|
||||
[OP_CREATE_SESSION] = nfsd4_decode_create_session,
|
||||
[OP_DESTROY_SESSION] = nfsd4_decode_destroy_session,
|
||||
[OP_FREE_STATEID] = nfsd4_decode_free_stateid,
|
||||
[OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp,
|
||||
[OP_GET_DIR_DELEGATION] = nfsd4_decode_get_dir_delegation,
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
[OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo,
|
||||
[OP_GETDEVICELIST] = nfsd4_decode_notsupp,
|
||||
@ -4963,6 +4992,49 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_get_dir_delegation(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
|
||||
struct xdr_stream *xdr = resp->xdr;
|
||||
__be32 status = nfserr_resource;
|
||||
|
||||
switch(gdd->gddrnf_status) {
|
||||
case GDD4_OK:
|
||||
if (xdr_stream_encode_u32(xdr, GDD4_OK) != XDR_UNIT)
|
||||
break;
|
||||
status = nfsd4_encode_verifier4(xdr, &gdd->gddr_cookieverf);
|
||||
if (status)
|
||||
break;
|
||||
status = nfsd4_encode_stateid4(xdr, &gdd->gddr_stateid);
|
||||
if (status)
|
||||
break;
|
||||
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_notification[0], 0, 0);
|
||||
if (status)
|
||||
break;
|
||||
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_child_attributes[0],
|
||||
gdd->gddr_child_attributes[1],
|
||||
gdd->gddr_child_attributes[2]);
|
||||
if (status)
|
||||
break;
|
||||
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_dir_attributes[0],
|
||||
gdd->gddr_dir_attributes[1],
|
||||
gdd->gddr_dir_attributes[2]);
|
||||
break;
|
||||
default:
|
||||
pr_warn("nfsd: bad gddrnf_status (%u)\n", gdd->gddrnf_status);
|
||||
gdd->gddrnf_will_signal_deleg_avail = 0;
|
||||
fallthrough;
|
||||
case GDD4_UNAVAIL:
|
||||
if (xdr_stream_encode_u32(xdr, GDD4_UNAVAIL) != XDR_UNIT)
|
||||
break;
|
||||
status = nfsd4_encode_bool(xdr, gdd->gddrnf_will_signal_deleg_avail);
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
static __be32
|
||||
nfsd4_encode_device_addr4(struct xdr_stream *xdr,
|
||||
@ -5579,7 +5651,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
|
||||
[OP_CREATE_SESSION] = nfsd4_encode_create_session,
|
||||
[OP_DESTROY_SESSION] = nfsd4_encode_noop,
|
||||
[OP_FREE_STATEID] = nfsd4_encode_noop,
|
||||
[OP_GET_DIR_DELEGATION] = nfsd4_encode_noop,
|
||||
[OP_GET_DIR_DELEGATION] = nfsd4_encode_get_dir_delegation,
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
[OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo,
|
||||
[OP_GETDEVICELIST] = nfsd4_encode_noop,
|
||||
|
@ -518,6 +518,24 @@ struct nfsd4_free_stateid {
|
||||
stateid_t fr_stateid; /* request */
|
||||
};
|
||||
|
||||
struct nfsd4_get_dir_delegation {
|
||||
/* request */
|
||||
u32 gdda_signal_deleg_avail;
|
||||
u32 gdda_notification_types[1];
|
||||
struct timespec64 gdda_child_attr_delay;
|
||||
struct timespec64 gdda_dir_attr_delay;
|
||||
u32 gdda_child_attributes[3];
|
||||
u32 gdda_dir_attributes[3];
|
||||
/* response */
|
||||
u32 gddrnf_status;
|
||||
nfs4_verifier gddr_cookieverf;
|
||||
stateid_t gddr_stateid;
|
||||
u32 gddr_notification[1];
|
||||
u32 gddr_child_attributes[3];
|
||||
u32 gddr_dir_attributes[3];
|
||||
bool gddrnf_will_signal_deleg_avail;
|
||||
};
|
||||
|
||||
/* also used for NVERIFY */
|
||||
struct nfsd4_verify {
|
||||
u32 ve_bmval[3]; /* request */
|
||||
@ -797,6 +815,7 @@ struct nfsd4_op {
|
||||
struct nfsd4_reclaim_complete reclaim_complete;
|
||||
struct nfsd4_test_stateid test_stateid;
|
||||
struct nfsd4_free_stateid free_stateid;
|
||||
struct nfsd4_get_dir_delegation get_dir_delegation;
|
||||
struct nfsd4_getdeviceinfo getdeviceinfo;
|
||||
struct nfsd4_layoutget layoutget;
|
||||
struct nfsd4_layoutcommit layoutcommit;
|
||||
|
@ -701,6 +701,12 @@ enum state_protect_how4 {
|
||||
SP4_SSV = 2
|
||||
};
|
||||
|
||||
/* GET_DIR_DELEGATION non-fatal status codes */
|
||||
enum gddrnf4_status {
|
||||
GDD4_OK = 0,
|
||||
GDD4_UNAVAIL = 1
|
||||
};
|
||||
|
||||
enum pnfs_layouttype {
|
||||
LAYOUT_NFSV4_1_FILES = 1,
|
||||
LAYOUT_OSD2_OBJECTS = 2,
|
||||
|
Loading…
Reference in New Issue
Block a user