summaryrefslogtreecommitdiff
path: root/fs/nfs/nfs4xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r--fs/nfs/nfs4xdr.c134
1 files changed, 132 insertions, 2 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 318afde38057..b6fe30577fab 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -393,6 +393,20 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
#define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4)
+#define encode_get_dir_deleg_maxsz (op_encode_hdr_maxsz + \
+ 4 /* gdda_signal_deleg_avail */ + \
+ 8 /* gdda_notification_types */ + \
+ nfstime4_maxsz /* gdda_child_attr_delay */ + \
+ nfstime4_maxsz /* gdda_dir_attr_delay */ + \
+ nfs4_fattr_bitmap_maxsz /* gdda_child_attributes */ + \
+ nfs4_fattr_bitmap_maxsz /* gdda_dir_attributes */)
+#define decode_get_dir_deleg_maxsz (op_decode_hdr_maxsz + \
+ 4 /* gddrnf_status */ + \
+ encode_verifier_maxsz /* gddr_cookieverf */ + \
+ encode_stateid_maxsz /* gddr_stateid */ + \
+ 8 /* gddr_notification */ + \
+ nfs4_fattr_maxsz /* gddr_child_attributes */ + \
+ nfs4_fattr_maxsz /* gddr_dir_attributes */)
#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_DEVICEID4_SIZE) + \
1 /* layout type */ + \
@@ -444,6 +458,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0
+#define encode_get_dir_deleg_maxsz 0
+#define decode_get_dir_deleg_maxsz 0
#define encode_layoutreturn_maxsz 0
#define decode_layoutreturn_maxsz 0
#define encode_layoutget_maxsz 0
@@ -631,11 +647,13 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
+ encode_get_dir_deleg_maxsz + \
encode_getattr_maxsz + \
encode_renew_maxsz)
#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
+ decode_get_dir_deleg_maxsz + \
decode_getattr_maxsz + \
decode_renew_maxsz)
#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
@@ -1623,6 +1641,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
| FATTR4_WORD1_RAWDEV
| FATTR4_WORD1_SPACE_USED
| FATTR4_WORD1_TIME_ACCESS
+ | FATTR4_WORD1_TIME_CREATE
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY;
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
@@ -2007,6 +2026,33 @@ static void encode_sequence(struct xdr_stream *xdr,
#ifdef CONFIG_NFS_V4_1
static void
+encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+ struct timespec64 ts = { 0, 0 };
+ u32 notifications[1] = { 0 };
+ u32 attributes[1] = { 0 };
+ __be32 *p;
+
+ encode_op_hdr(xdr, OP_GET_DIR_DELEGATION, decode_get_dir_deleg_maxsz, hdr);
+
+ /* We don't handle CB_RECALLABLE_OBJ_AVAIL yet. */
+ xdr_stream_encode_bool(xdr, false);
+
+ xdr_encode_bitmap4(xdr, notifications, ARRAY_SIZE(notifications));
+
+ /* Request no delay on attribute updates */
+ p = reserve_space(xdr, 12 + 12);
+ p = xdr_encode_nfstime4(p, &ts);
+ xdr_encode_nfstime4(p, &ts);
+
+ /* Requested child attributes */
+ xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes));
+
+ /* Requested dir attributes */
+ xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes));
+}
+
+static void
encode_getdeviceinfo(struct xdr_stream *xdr,
const struct nfs4_getdeviceinfo_args *args,
struct compound_hdr *hdr)
@@ -2142,6 +2188,11 @@ static void encode_free_stateid(struct xdr_stream *xdr,
}
#else
static inline void
+encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+}
+
+static inline void
encode_layoutreturn(struct xdr_stream *xdr,
const struct nfs4_layoutreturn_args *args,
struct compound_hdr *hdr)
@@ -2355,6 +2406,8 @@ static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
+ if (args->get_dir_deleg)
+ encode_get_dir_delegation(xdr, &hdr);
encode_getfattr(xdr, args->bitmask, &hdr);
encode_nops(&hdr);
}
@@ -4207,6 +4260,24 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
return status;
}
+static int decode_attr_time_create(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
+{
+ int status = 0;
+
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_CREATE - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_TIME_CREATE)) {
+ status = decode_attr_time(xdr, time);
+ if (status == 0)
+ status = NFS_ATTR_FATTR_BTIME;
+ bitmap[1] &= ~FATTR4_WORD1_TIME_CREATE;
+ }
+ dprintk("%s: btime=%lld\n", __func__, time->tv_sec);
+ return status;
+}
+
static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
{
int status = 0;
@@ -4781,6 +4852,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
goto xdr_error;
fattr->valid |= status;
+ status = decode_attr_time_create(xdr, bitmap, &fattr->btime);
+ if (status < 0)
+ goto xdr_error;
+ fattr->valid |= status;
+
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
if (status < 0)
goto xdr_error;
@@ -4906,7 +4982,7 @@ static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
}
/*
- * The prefered block size for layout directed io
+ * The preferred block size for layout directed io
*/
static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t *res)
@@ -5970,6 +6046,49 @@ static int decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
return decode_stateid(xdr, stateid);
}
+static int decode_get_dir_delegation(struct xdr_stream *xdr,
+ struct nfs4_getattr_res *res)
+{
+ struct nfs4_gdd_res *gdd_res = res->gdd_res;
+ nfs4_verifier cookieverf;
+ u32 bitmap[1];
+ int status;
+
+ status = decode_op_hdr(xdr, OP_GET_DIR_DELEGATION);
+ if (status)
+ return status;
+
+ if (xdr_stream_decode_u32(xdr, &gdd_res->status))
+ return -EIO;
+
+ if (gdd_res->status == GDD4_UNAVAIL)
+ return xdr_inline_decode(xdr, 4) ? 0 : -EIO;
+
+ status = decode_verifier(xdr, &cookieverf);
+ if (status)
+ return status;
+
+ status = decode_delegation_stateid(xdr, &gdd_res->deleg);
+ if (status)
+ return status;
+
+ /* Decode supported notification types. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+
+ /* Decode supported child attributes. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+
+ /* Decode supported attributes. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+ return 0;
+}
+
static int decode_getdeviceinfo(struct xdr_stream *xdr,
struct nfs4_getdeviceinfo_res *res)
{
@@ -6184,6 +6303,12 @@ static int decode_free_stateid(struct xdr_stream *xdr,
return res->status;
}
#else
+static int decode_get_dir_delegation(struct xdr_stream *xdr,
+ struct nfs4_getattr_res *res)
+{
+ return 0;
+}
+
static inline
int decode_layoutreturn(struct xdr_stream *xdr,
struct nfs4_layoutreturn_res *res)
@@ -6501,6 +6626,11 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr);
if (status)
goto out;
+ if (res->gdd_res) {
+ status = decode_get_dir_delegation(xdr, res);
+ if (status)
+ goto out;
+ }
status = decode_getfattr(xdr, res->fattr, res->server);
out:
return status;
@@ -6561,7 +6691,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
int status;
if (res->acl_scratch != NULL)
- xdr_set_scratch_page(xdr, res->acl_scratch);
+ xdr_set_scratch_folio(xdr, res->acl_scratch);
status = decode_compound_hdr(xdr, &hdr);
if (status)
goto out;