Skip to content

Commit 33a1e6e

Browse files
jtlaytonchucklever
authored andcommitted
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 <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 38f080f commit 33a1e6e

File tree

4 files changed

+140
-2
lines changed

4 files changed

+140
-2
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,6 +2154,29 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
21542154
return status == nfserr_same ? nfs_ok : status;
21552155
}
21562156

2157+
static __be32
2158+
nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
2159+
struct nfsd4_compound_state *cstate,
2160+
union nfsd4_op_u *u)
2161+
{
2162+
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
2163+
2164+
/*
2165+
* RFC 8881, section 18.39.3 says:
2166+
*
2167+
* "The server may refuse to grant the delegation. In that case, the
2168+
* server will return NFS4ERR_DIRDELEG_UNAVAIL."
2169+
*
2170+
* This is sub-optimal, since it means that the server would need to
2171+
* abort compound processing just because the delegation wasn't
2172+
* available. RFC8881bis should change this to allow the server to
2173+
* return NFS4_OK with a non-fatal status of GDD4_UNAVAIL in this
2174+
* situation.
2175+
*/
2176+
gdd->gddrnf_status = GDD4_UNAVAIL;
2177+
return nfs_ok;
2178+
}
2179+
21572180
#ifdef CONFIG_NFSD_PNFS
21582181
static const struct nfsd4_layout_ops *
21592182
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,
30823105
* sizeof(__be32);
30833106
}
30843107

3108+
static u32 nfsd4_get_dir_delegation_rsize(const struct svc_rqst *rqstp,
3109+
const struct nfsd4_op *op)
3110+
{
3111+
return (op_encode_hdr_size +
3112+
1 /* gddr_status */ +
3113+
op_encode_verifier_maxsz +
3114+
op_encode_stateid_maxsz +
3115+
2 /* gddr_notification */ +
3116+
2 /* gddr_child_attributes */ +
3117+
2 /* gddr_dir_attributes */);
3118+
}
3119+
30853120
#ifdef CONFIG_NFSD_PNFS
30863121
static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp,
30873122
const struct nfsd4_op *op)
@@ -3470,6 +3505,12 @@ static const struct nfsd4_operation nfsd4_ops[] = {
34703505
.op_get_currentstateid = nfsd4_get_freestateid,
34713506
.op_rsize_bop = nfsd4_only_status_rsize,
34723507
},
3508+
[OP_GET_DIR_DELEGATION] = {
3509+
.op_func = nfsd4_get_dir_delegation,
3510+
.op_flags = OP_MODIFIES_SOMETHING,
3511+
.op_name = "OP_GET_DIR_DELEGATION",
3512+
.op_rsize_bop = nfsd4_get_dir_delegation_rsize,
3513+
},
34733514
#ifdef CONFIG_NFSD_PNFS
34743515
[OP_GETDEVICEINFO] = {
34753516
.op_func = nfsd4_getdeviceinfo,

fs/nfsd/nfs4xdr.c

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,35 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
17321732
return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
17331733
}
17341734

1735+
static __be32
1736+
nfsd4_decode_get_dir_delegation(struct nfsd4_compoundargs *argp,
1737+
union nfsd4_op_u *u)
1738+
{
1739+
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
1740+
__be32 status;
1741+
1742+
memset(gdd, 0, sizeof(*gdd));
1743+
1744+
if (xdr_stream_decode_bool(argp->xdr, &gdd->gdda_signal_deleg_avail) < 0)
1745+
return nfserr_bad_xdr;
1746+
status = nfsd4_decode_bitmap4(argp, gdd->gdda_notification_types,
1747+
ARRAY_SIZE(gdd->gdda_notification_types));
1748+
if (status)
1749+
return status;
1750+
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_child_attr_delay);
1751+
if (status)
1752+
return status;
1753+
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_dir_attr_delay);
1754+
if (status)
1755+
return status;
1756+
status = nfsd4_decode_bitmap4(argp, gdd->gdda_child_attributes,
1757+
ARRAY_SIZE(gdd->gdda_child_attributes));
1758+
if (status)
1759+
return status;
1760+
return nfsd4_decode_bitmap4(argp, gdd->gdda_dir_attributes,
1761+
ARRAY_SIZE(gdd->gdda_dir_attributes));
1762+
}
1763+
17351764
#ifdef CONFIG_NFSD_PNFS
17361765
static __be32
17371766
nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
@@ -2370,7 +2399,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
23702399
[OP_CREATE_SESSION] = nfsd4_decode_create_session,
23712400
[OP_DESTROY_SESSION] = nfsd4_decode_destroy_session,
23722401
[OP_FREE_STATEID] = nfsd4_decode_free_stateid,
2373-
[OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp,
2402+
[OP_GET_DIR_DELEGATION] = nfsd4_decode_get_dir_delegation,
23742403
#ifdef CONFIG_NFSD_PNFS
23752404
[OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo,
23762405
[OP_GETDEVICELIST] = nfsd4_decode_notsupp,
@@ -4963,6 +4992,49 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
49634992
return nfs_ok;
49644993
}
49654994

4995+
static __be32
4996+
nfsd4_encode_get_dir_delegation(struct nfsd4_compoundres *resp, __be32 nfserr,
4997+
union nfsd4_op_u *u)
4998+
{
4999+
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
5000+
struct xdr_stream *xdr = resp->xdr;
5001+
__be32 status = nfserr_resource;
5002+
5003+
switch(gdd->gddrnf_status) {
5004+
case GDD4_OK:
5005+
if (xdr_stream_encode_u32(xdr, GDD4_OK) != XDR_UNIT)
5006+
break;
5007+
status = nfsd4_encode_verifier4(xdr, &gdd->gddr_cookieverf);
5008+
if (status)
5009+
break;
5010+
status = nfsd4_encode_stateid4(xdr, &gdd->gddr_stateid);
5011+
if (status)
5012+
break;
5013+
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_notification[0], 0, 0);
5014+
if (status)
5015+
break;
5016+
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_child_attributes[0],
5017+
gdd->gddr_child_attributes[1],
5018+
gdd->gddr_child_attributes[2]);
5019+
if (status)
5020+
break;
5021+
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_dir_attributes[0],
5022+
gdd->gddr_dir_attributes[1],
5023+
gdd->gddr_dir_attributes[2]);
5024+
break;
5025+
default:
5026+
pr_warn("nfsd: bad gddrnf_status (%u)\n", gdd->gddrnf_status);
5027+
gdd->gddrnf_will_signal_deleg_avail = 0;
5028+
fallthrough;
5029+
case GDD4_UNAVAIL:
5030+
if (xdr_stream_encode_u32(xdr, GDD4_UNAVAIL) != XDR_UNIT)
5031+
break;
5032+
status = nfsd4_encode_bool(xdr, gdd->gddrnf_will_signal_deleg_avail);
5033+
break;
5034+
}
5035+
return status;
5036+
}
5037+
49665038
#ifdef CONFIG_NFSD_PNFS
49675039
static __be32
49685040
nfsd4_encode_device_addr4(struct xdr_stream *xdr,
@@ -5579,7 +5651,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
55795651
[OP_CREATE_SESSION] = nfsd4_encode_create_session,
55805652
[OP_DESTROY_SESSION] = nfsd4_encode_noop,
55815653
[OP_FREE_STATEID] = nfsd4_encode_noop,
5582-
[OP_GET_DIR_DELEGATION] = nfsd4_encode_noop,
5654+
[OP_GET_DIR_DELEGATION] = nfsd4_encode_get_dir_delegation,
55835655
#ifdef CONFIG_NFSD_PNFS
55845656
[OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo,
55855657
[OP_GETDEVICELIST] = nfsd4_encode_noop,

fs/nfsd/xdr4.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,24 @@ struct nfsd4_free_stateid {
518518
stateid_t fr_stateid; /* request */
519519
};
520520

521+
struct nfsd4_get_dir_delegation {
522+
/* request */
523+
u32 gdda_signal_deleg_avail;
524+
u32 gdda_notification_types[1];
525+
struct timespec64 gdda_child_attr_delay;
526+
struct timespec64 gdda_dir_attr_delay;
527+
u32 gdda_child_attributes[3];
528+
u32 gdda_dir_attributes[3];
529+
/* response */
530+
u32 gddrnf_status;
531+
nfs4_verifier gddr_cookieverf;
532+
stateid_t gddr_stateid;
533+
u32 gddr_notification[1];
534+
u32 gddr_child_attributes[3];
535+
u32 gddr_dir_attributes[3];
536+
bool gddrnf_will_signal_deleg_avail;
537+
};
538+
521539
/* also used for NVERIFY */
522540
struct nfsd4_verify {
523541
u32 ve_bmval[3]; /* request */
@@ -797,6 +815,7 @@ struct nfsd4_op {
797815
struct nfsd4_reclaim_complete reclaim_complete;
798816
struct nfsd4_test_stateid test_stateid;
799817
struct nfsd4_free_stateid free_stateid;
818+
struct nfsd4_get_dir_delegation get_dir_delegation;
800819
struct nfsd4_getdeviceinfo getdeviceinfo;
801820
struct nfsd4_layoutget layoutget;
802821
struct nfsd4_layoutcommit layoutcommit;

include/linux/nfs4.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,12 @@ enum state_protect_how4 {
701701
SP4_SSV = 2
702702
};
703703

704+
/* GET_DIR_DELEGATION non-fatal status codes */
705+
enum gddrnf4_status {
706+
GDD4_OK = 0,
707+
GDD4_UNAVAIL = 1
708+
};
709+
704710
enum pnfs_layouttype {
705711
LAYOUT_NFSV4_1_FILES = 1,
706712
LAYOUT_OSD2_OBJECTS = 2,

0 commit comments

Comments
 (0)