[pnfs] [PATCH] pnfsd: Notify device ID changes

Marc Eshel eshel at almaden.ibm.com
Mon May 19 19:15:21 EDT 2008


From: Marc Eshel <eshel at almaden.ibm.com>
Signed-off-by: Marc Eshel <eshel at almaden.ibm.com>


---

 fs/nfsd/export.c                |   12 ++++
 fs/nfsd/nfs4callback.c          |  115 +++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfs4state.c             |   40 ++++++++++++++
 include/linux/exportfs.h        |    1 
 include/linux/nfs4.h            |    5 ++
 include/linux/nfsd/nfsd4_pnfs.h |    7 ++
 include/linux/nfsd/pnfsd.h      |    1 
 include/linux/nfsd/state.h      |    8 +++
 8 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index bdf3dad..7bbc2e5 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -390,6 +390,16 @@ static int cb_layout_recall(struct super_block *sb, struct inode *inode,
 	return nfsd_layout_recall_cb(sb, inode, lr);
 }
 EXPORT_SYMBOL(cb_layout_recall);
+
+static int cb_device_notify(struct super_block *sb, void *p)
+{
+	struct nfsd4_pnfs_cb_device *nd = p;
+
+	dprintk("cb_device_notify nd %p\n", nd);
+
+	return nfsd_device_notify_cb(sb, nd);
+}
+EXPORT_SYMBOL(cb_device_notify);
 #endif /* CONFIG_PNFSD */
 
 static struct svc_export *svc_export_update(struct svc_export *new,
@@ -434,6 +444,8 @@ static int check_export(struct inode *inode, int flags, unsigned char *uuid)
 		inode->i_sb->s_export_op->cb_change_state = cb_change_state;
 	if (!inode->i_sb->s_export_op->cb_layout_recall)
 		inode->i_sb->s_export_op->cb_layout_recall = cb_layout_recall;
+	if (!inode->i_sb->s_export_op->cb_device_notify)
+		inode->i_sb->s_export_op->cb_device_notify = cb_device_notify;
 #endif /* CONFIG_PNFSD */
 
 	return 0;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index d56a085..fb9f00c 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -67,6 +67,7 @@ enum {
 	NFSPROC4_CLNT_CB_SEQUENCE,
 #if defined(CONFIG_PNFSD)
 	NFSPROC4_CLNT_CB_LAYOUT,
+	NFSPROC4_CLNT_CB_DEVICE,
 #endif
 };
 
@@ -74,6 +75,7 @@ enum nfs_cb_opnum4 {
 	OP_CB_RECALL            = 4,
 	OP_CB_LAYOUT            = 5,
 	OP_CB_SEQUENCE          = 11,
+	OP_CB_DEVICE            = 14,
 };
 
 #define NFS4_MAXTAGLEN		20
@@ -116,6 +118,13 @@ enum nfs_cb_opnum4 {
 					cb_sequence41_dec_sz +          \
 					op_dec_sz)
 
+#define NFS41_enc_cb_device_sz		(cb_compound_enc_hdr_sz +       \
+					cb_sequence41_enc_sz +          \
+					1 + 6)
+#define NFS41_dec_cb_device_sz		(cb_compound_dec_hdr_sz  +      \
+					cb_sequence41_dec_sz +          \
+					op_dec_sz)
+
 struct nfs41_rpc_args {
 	struct nfs4_callback     *args_callback;
 	void                     *args_op;
@@ -351,6 +360,31 @@ encode_cb_layout(struct xdr_stream *xdr, struct nfs4_layoutrecall *clr)
 			clr->cb.cbl_recall_type);
 	return 0;
 }
+
+static int
+encode_cb_device(struct xdr_stream *xdr, struct nfs4_notify_device *nd)
+{
+	u32 *p;
+
+	RESERVE_SPACE(32);
+	WRITE32(OP_CB_DEVICE);
+	WRITE32(nd->cbd.cbd_notify_type);
+	WRITE32(nd->cbd.cbd_layout_type);
+	WRITE64(nd->cbd.cbd_devid.pnfs_fsid);
+	WRITE64(nd->cbd.cbd_devid.pnfs_devid);
+	WRITE32(nd->cbd.cbd_immediat);
+
+	if (nd->cbd.cbd_notify_type == NOTIFY_DEVICE_CHANGE) {
+		RESERVE_SPACE(4);
+		WRITE32(nd->cbd.cbd_immediat);
+	}
+	dprintk("%s: notify_type %d layout_type %d devid 0x%llx-0x%llx\n",
+			__func__, nd->cbd.cbd_notify_type,
+			nd->cbd.cbd_layout_type,
+			nd->cbd.cbd_devid.pnfs_fsid,
+			nd->cbd.cbd_devid.pnfs_devid);
+	return 0;
+}
 #endif /* CONFIG_PNFSD */
 #endif /* defined(CONFIG_NFSD_V4_1) */
 
@@ -426,6 +460,23 @@ nfs41_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p,
 	encode_cb_sequence(&xdr, rpc_args->args_seq);
 	return (encode_cb_layout(&xdr, args));
 }
+
+static int
+nfs41_xdr_enc_cb_device(struct rpc_rqst *req, u32 *p,
+			struct nfs41_rpc_args *rpc_args)
+{
+	struct xdr_stream xdr;
+	struct nfs4_notify_device *args = rpc_args->args_op;
+	struct nfs4_cb_compound_hdr hdr = {
+		.ident = 0,
+		.nops   = 2,
+	};
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_cb_compound41_hdr(&xdr, &hdr);
+	encode_cb_sequence(&xdr, rpc_args->args_seq);
+	return (encode_cb_device(&xdr, args));
+}
 #endif /* CONFIG_PNFSD */
 #endif /* defined(CONFIG_NFSD_V4_1) */
 
@@ -545,6 +596,26 @@ nfs41_xdr_dec_cb_layout(struct rpc_rqst *rqstp, u32 *p,
 out:
 	return status;
 }
+
+static int
+nfs41_xdr_dec_cb_device(struct rpc_rqst *rqstp, u32 *p,
+			struct nfs41_rpc_res *rpc_res)
+{
+	struct xdr_stream xdr;
+	struct nfs4_cb_compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_cb_compound_hdr(&xdr, &hdr);
+	if (status)
+		goto out;
+	status = decode_cb_sequence(&xdr, rpc_res->res_seq);
+	if (status)
+		goto out;
+	status = decode_cb_op_hdr(&xdr, OP_CB_DEVICE);
+out:
+	return status;
+}
 #endif /* CONFIG_PNFSD */
 #endif /* defined(CONFIG_NFSD_V4_1) */
 
@@ -595,6 +666,7 @@ static struct rpc_procinfo     nfs41_cb_procedures[] = {
 	PROC41(CB_RECALL,    COMPOUND,   enc_cb_recall,      dec_cb_recall),
 #if defined(CONFIG_PNFSD)
 	PROC41(CB_LAYOUT,    COMPOUND,   enc_cb_layout,      dec_cb_layout),
+	PROC41(CB_DEVICE,    COMPOUND,   enc_cb_device,      dec_cb_device),
 #endif
 };
 
@@ -911,4 +983,47 @@ out:
 	dprintk("NFSD: nfsd4_cb_layout: status %d\n", clr->clr_status);
 	return clr->clr_status;
 }
+
+/*
+ * called with dp->dl_count inc'ed.
+ * nfs4_lock_state() may or may not have been called.
+ */
+int
+nfsd4_cb_notify_device(struct nfs4_notify_device *cbnd)
+{
+	struct nfs4_client *clp = cbnd->cbd_client;
+	struct rpc_clnt *clnt = NULL;
+	struct nfs41_cb_sequence seq;
+	struct nfs41_rpc_args args = {
+		.args_op = cbnd,
+		.args_seq = &seq
+	};
+	struct nfs41_rpc_res res = {
+		.res_seq = &seq
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs41_cb_procedures[NFSPROC4_CLNT_CB_DEVICE],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
+
+	if (clp)
+		clnt = clp->cl_callback.cb_client;
+
+	cbnd->cbd_status = -EIO;
+	if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
+		goto out;
+
+	nfs41_cb_sequence_setup(clp, &seq);
+	cbnd->cbd_status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+	nfs41_cb_sequence_done(clp, &seq);
+
+	if (cbnd->cbd_status == -EIO)
+		atomic_set(&clp->cl_callback.cb_set, 0);
+out:
+	/* Success or failure, now we're either waiting for lease expiration
+	   or layout_return. */
+	dprintk("NFSD: nfsd4_cb_device: status %d\n", cbnd->cbd_status);
+	return cbnd->cbd_status;
+}
 #endif /* CONFIG_PNFSD */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 751271f..54a669a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5242,4 +5242,44 @@ err:
 	return status;
 }
 
+/*
+ * Spawn a thread to perform a device notify
+ *
+ */
+int nfsd_device_notify_cb(struct super_block *sb, struct nfsd4_pnfs_cb_device *nd)
+{
+	struct nfs4_notify_device cbnd;
+	struct nfs4_client *clp = NULL;
+	unsigned int i;
+	int status, did_lock;
+
+	dprintk("NFSD nfsd_device_notify_cb: cbl %p\n", nd);
+	BUG_ON(!nd);
+	BUG_ON(nd->cbd_notify_type != NOTIFY_DEVICE_CHANGE &&
+	       nd->cbd_notify_type != NOTIFY_DEVICE_DELETE);
+
+	if (nfsd_serv == NULL)
+		return -ENOENT;
+
+	did_lock = nfs4_lock_state_nested();
+	status = -ENOENT;
+
+	cbnd.cbd.cbd_notify_type = nd->cbd_notify_type;
+	cbnd.cbd.cbd_layout_type = nd->cbd_layout_type;
+	cbnd.cbd.cbd_devid = nd->cbd_devid;
+	cbnd.cbd.cbd_immediat = nd->cbd_immediat;
+
+	for (i = 0; i < CLIENT_HASH_SIZE; i++)
+		list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash)
+		{
+			cbnd.cbd_client = clp;
+			status = nfsd4_cb_notify_device(&cbnd);
+		}
+
+	dprintk("NFSD nfsd_device_notify_cb: i %d status %d\n", i , status);
+	if (did_lock)
+		nfs4_unlock_state();
+	return status;
+}
+
 #endif /* CONFIG_PNFSD */
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index a310468..21d12c4 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -231,6 +231,7 @@ struct export_operations {
 		/* callback from fs on MDS only */
 	int (*cb_get_state) (struct super_block *sb, void *state);
 	int (*cb_layout_recall) (struct super_block *sb, struct inode *inode, void *p);
+	int (*cb_device_notify) (struct super_block *sb, void *p);
 		/* call fs on DS only */
 	int (*get_state) (struct inode *inode, void *fh, void *state);
 		/* callback from fs on DS only */
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 33a2ce2..a3f7494 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -511,6 +511,11 @@ enum pnfs_layouttype {
 	LAYOUT_PVFS2        = 4
 };
 
+enum pnfs_notifydevice {
+	NOTIFY_DEVICE_CHANGE = 1,
+	NOTIFY_DEVICE_DELETE = 2
+};
+
 /* FIXME: should recall and return types be combined? */
 enum pnfs_layoutrecall_type {
 	RECALL_FILE = 1,
diff --git a/include/linux/nfsd/nfsd4_pnfs.h b/include/linux/nfsd/nfsd4_pnfs.h
index 9ee427a..bf2287a 100644
--- a/include/linux/nfsd/nfsd4_pnfs.h
+++ b/include/linux/nfsd/nfsd4_pnfs.h
@@ -107,6 +107,13 @@ struct nfsd4_pnfs_cb_layout {
 	struct nfs4_fsid	cbl_fsid;
 };
 
+struct nfsd4_pnfs_cb_device {
+	u32			cbd_notify_type;	/* request */
+	u32			cbd_layout_type;	/* request */
+	deviceid_t		cbd_devid;		/* request */
+	u32			cbd_immediat;		/* request */
+};
+
 #endif /* CONFIG_PNFSD */
 
 #endif /* _LINUX_NFSD_NFSD4_PNFS_H */
diff --git a/include/linux/nfsd/pnfsd.h b/include/linux/nfsd/pnfsd.h
index d937594..adc79ea 100644
--- a/include/linux/nfsd/pnfsd.h
+++ b/include/linux/nfsd/pnfsd.h
@@ -85,6 +85,7 @@ struct pnfs_mds_id {
 };
 
 int nfsd_layout_recall_cb(struct super_block *, struct inode *, struct nfsd4_pnfs_cb_layout *);
+int nfsd_device_notify_cb(struct super_block *, struct nfsd4_pnfs_cb_device *);
 int nfs4_pnfs_cb_get_state(struct super_block *, struct pnfs_get_state *);
 void nfs4_pnfs_state_init(void);
 int nfs4_pnfs_get_layout(struct svc_fh *, struct pnfs_layoutget_arg *,
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index ac3a40e..0722162 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -287,6 +287,13 @@ struct nfs4_layoutrecall {
 	struct timespec			clr_time;	/* last activity */
 };
 
+/* notify device request (from exported filesystem) */
+struct nfs4_notify_device {
+	struct nfsd4_pnfs_cb_device	cbd;
+	struct nfs4_client	       *cbd_client;
+	int				cbd_status;
+};
+
 #endif /* CONFIG_PNFSD */
 
 /* struct nfs4_client_reset
@@ -468,6 +475,7 @@ extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 #if defined(CONFIG_PNFSD)
 extern int nfsd4_cb_layout(struct nfs4_layoutrecall *lp);
+extern int nfsd4_cb_notify_device(struct nfs4_notify_device *cbnd);
 #endif /* CONFIG_PNFSD */
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);


More information about the pNFS mailing list