[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