[PATCH 1/4] NFS: Add an outline for the CB_NOTIFY operation

Anna Schumaker <[email protected]>
Newsgroups org.kernel.vger.linux-nfs
Message-ID <[email protected]>
From: Anna Schumaker <[email protected]>

Support for individual notification types will be added over the next
few patches.

Signed-off-by: Anna Schumaker <[email protected]>
Signed-off-by: Anna Schumaker <[email protected]>
---
 fs/nfs/callback.h      | 14 +++++++++++
 fs/nfs/callback_proc.c |  9 +++++++
 fs/nfs/callback_xdr.c  | 54 +++++++++++++++++++++++++++++++++++++++++-
 fs/nfs/nfs4xdr.c       |  2 +-
 include/linux/nfs4.h   |  3 +++
 5 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 2a721c422d48..f7cc5b6931bf 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -143,6 +143,20 @@ struct cb_layoutrecallargs {
 extern __be32 nfs4_callback_layoutrecall(void *argp, void *resp,
 		struct cb_process_state *cps);
 
+struct cb_notify_changes {
+	u32 notify_mask;
+};
+
+struct cb_notifyargs {
+	nfs4_stateid			cna_stateid;
+	struct nfs_fh			cna_fh;
+	uint32_t			cna_n_changes;
+	struct cb_notify_changes	*cna_changes;
+};
+
+extern __be32 nfs4_callback_notify(void *argp, void *resp,
+				   struct cb_process_state *cps);
+
 struct cb_devicenotifyitem {
 	uint32_t		cbd_notify_type;
 	uint32_t		cbd_layout_type;
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 10f2354ba304..5c414b3b01d8 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -368,6 +368,15 @@ static void pnfs_recall_all_layouts(struct nfs_client *clp,
 	do_callback_layoutrecall(clp, &args, cps);
 }
 
+__be32 nfs4_callback_notify(void *argp, void *resp,
+			    struct cb_process_state *cps)
+{
+	struct cb_notifyargs *args = argp;
+
+	kfree(args->cna_changes);
+	return 0;
+}
+
 __be32 nfs4_callback_devicenotify(void *argp, void *resp,
 				  struct cb_process_state *cps)
 {
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 4382baddc9ee..b96d0028fa3d 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -31,6 +31,7 @@
 #define CB_OP_RECALL_RES_MAXSZ		(CB_OP_HDR_RES_MAXSZ)
 
 #define CB_OP_LAYOUTRECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_NOTIFY_RES_MAXSZ		(CB_OP_HDR_RES_MAXSZ)
 #define CB_OP_DEVICENOTIFY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
 #define CB_OP_SEQUENCE_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
 					 NFS4_MAX_SESSIONID_LEN + \
@@ -251,6 +252,52 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
 	return 0;
 }
 
+static
+__be32 decode_notify_args(struct svc_rqst *rqstp,
+			  struct xdr_stream *xdr,
+			  void *argp)
+{
+	struct cb_notifyargs *args = argp;
+	__be32 status;
+	size_t res;
+	__be32 *p;
+	int i;
+
+	status = decode_stateid(xdr, &args->cna_stateid);
+	if (unlikely(status != 0))
+		return status;
+
+	status = decode_fh(xdr, &args->cna_fh);
+	if (unlikely(status != 0))
+		return status;
+
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(!p))
+		goto out;
+
+	args->cna_n_changes = ntohl(*p++);
+	args->cna_changes = kmalloc_array(args->cna_n_changes,
+					  sizeof(*args->cna_changes),
+					  GFP_KERNEL);
+	if (!args->cna_changes)
+		goto out;
+
+	for (i = 0; i < args->cna_n_changes; i++) {
+		struct cb_notify_changes *change = &args->cna_changes[i];
+
+		res = xdr_stream_decode_uint32_array(xdr,
+						     &change->notify_mask, 1);
+		if (unlikely(res < 0))
+			goto err;
+	}
+
+	return 0;
+err:
+	kfree(args->cna_changes);
+out:
+	return htonl(NFS4ERR_BADXDR);
+}
+
 static
 __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
 				struct xdr_stream *xdr,
@@ -797,12 +844,12 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
 	case OP_CB_RECALL_ANY:
 	case OP_CB_RECALL_SLOT:
 	case OP_CB_LAYOUTRECALL:
+	case OP_CB_NOTIFY:
 	case OP_CB_NOTIFY_DEVICEID:
 	case OP_CB_NOTIFY_LOCK:
 		*op = &callback_ops[op_nr];
 		break;
 
-	case OP_CB_NOTIFY:
 	case OP_CB_PUSH_DELEG:
 	case OP_CB_RECALLABLE_OBJ_AVAIL:
 	case OP_CB_WANTS_CANCELLED:
@@ -1034,6 +1081,11 @@ static struct callback_op callback_ops[] = {
 		.decode_args = decode_layoutrecall_args,
 		.res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
 	},
+	[OP_CB_NOTIFY] = {
+		.process_op = nfs4_callback_notify,
+		.decode_args = decode_notify_args,
+		.res_maxsize = CB_OP_NOTIFY_RES_MAXSZ,
+	},
 	[OP_CB_NOTIFY_DEVICEID] = {
 		.process_op = nfs4_callback_devicenotify,
 		.decode_args = decode_devicenotify_args,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c23c2eee1b5c..64b8fd061852 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -2011,7 +2011,7 @@ static void
 encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
 	struct timespec64 ts = { 0, 0 };
-	u32 notifications[1] = { 0 };
+	u32 notifications[1] = { CB_NOTIFY4_GFLAG_EXTEND };
 	u32 attributes[1] = { 0 };
 	__be32 *p;
 
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 44e5e9fa12e1..fcf0eee55c35 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -482,6 +482,9 @@ enum {
 #define THRESHOLD_RD_IO                 (1UL << 2)
 #define THRESHOLD_WR_IO                 (1UL << 3)
 
+/* Directory Delegation / CB_NOTIFY bits */
+#define CB_NOTIFY4_GFLAG_EXTEND		(1UL << 6)
+
 #define NFSPROC4_NULL 0
 #define NFSPROC4_COMPOUND 1
 #define NFS4_VERSION 4
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.