[PATCH] layout recall changes for nfsd layout cache
Benny Halevy
bhalevy at ns1.bhalevy.com
Mon May 7 12:44:55 EDT 2007
---
fs/nfsd/export.c | 6 +-
fs/nfsd/nfs4callback.c | 90 +++++------
fs/nfsd/nfs4state.c | 323 +++++++++++++++++++++++++++++++--------
include/linux/nfsd/nfsd4_pnfs.h | 6 +
include/linux/nfsd/pnfsd.h | 2 +-
include/linux/nfsd/state.h | 35 +++--
6 files changed, 330 insertions(+), 132 deletions(-)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index f629a3b..b5ea034 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -372,13 +372,11 @@ EXPORT_SYMBOL(cb_change_state);
static int cb_layout_recall(struct super_block *sb, struct inode *inode,
void *p)
{
- struct nfs4_cb_layout *lr = (struct nfs4_cb_layout *)p;
+ struct nfsd4_pnfs_cb_layout *lr = p;
dprintk("cb_layout_recall lr %p\n", lr);
- nfsd_layout_recall_cb(lr);
-
- return 0;
+ return nfsd_layout_recall_cb(inode, lr);
}
EXPORT_SYMBOL(cb_layout_recall);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 6caca21..3abaf04 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -249,36 +249,41 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
}
static int
-encode_cb_layout(struct xdr_stream *xdr, struct nfs4_cb_layout *lr)
+encode_cb_layout(struct xdr_stream *xdr, struct nfs4_layoutrecall *clr)
{
u32 *p;
- int len = lr->cbl_fhlen;
+ int len = clr->cb.cbl_recall_type == RECALL_FILE ?
+ clr->clr_file->fi_fhlen : 0;
- RESERVE_SPACE(48 + len);
+ RESERVE_SPACE(40 + len);
WRITE32(OP_CB_LAYOUT);
- WRITE32(lr->cbl_layout_type);
- WRITE32(lr->cbl_iomode);
- WRITE32(lr->cbl_layoutchanged);
- WRITE32(lr->cbl_recall_type);
- if (lr->cbl_recall_type == RECALL_FSID) {
- WRITE64(lr->cbl_fsid.major);
- WRITE64(lr->cbl_fsid.minor);
+ WRITE32(clr->cb.cbl_seg.layout_type);
+ WRITE32(clr->cb.cbl_seg.iomode);
+ WRITE32(clr->cb.cbl_layoutchanged);
+ WRITE32(clr->cb.cbl_recall_type);
+ if (unlikely(clr->cb.cbl_recall_type == RECALL_FSID)) {
+ struct nfs4_fsid fsid = clr->clr_file->fi_fsid;
+ WRITE64(fsid.major);
+ WRITE64(fsid.minor);
dprintk("%s: type %d iomode %d changed %d recall_type %d fsid 0x%llx-0x%llx\n",
- __FUNCTION__, lr->cbl_layout_type, lr->cbl_iomode,
- lr->cbl_layoutchanged, lr->cbl_recall_type,
- lr->cbl_fsid.major, lr->cbl_fsid.minor);
+ __FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+ clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type,
+ fsid.major, fsid.minor);
}
- else if (lr->cbl_recall_type == RECALL_FILE) {
+ else if (clr->cb.cbl_recall_type == RECALL_FILE) {
WRITE32(len);
- WRITEMEM(lr->cbl_fhval, len);
- WRITE64(lr->cbl_offset);
- WRITE64(lr->cbl_length);
+ WRITEMEM(clr->clr_file->fi_fhval, len);
+ WRITE64(clr->cb.cbl_seg.offset);
+ WRITE64(clr->cb.cbl_seg.length);
dprintk("%s: type %d iomode %d changed %d recall_type %d offset %lld length %lld\n",
- __FUNCTION__, lr->cbl_layout_type, lr->cbl_iomode,
- lr->cbl_layoutchanged, lr->cbl_recall_type,
- lr->cbl_offset, lr->cbl_length);
- }
+ __FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+ clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type,
+ clr->cb.cbl_seg.offset, clr->cb.cbl_seg.length);
+ } else
+ dprintk("%s: type %d iomode %d changed %d recall_type %d\n",
+ __FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+ clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type);
return 0;
}
@@ -308,7 +313,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args
}
static int
-nfs4_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p, struct nfs4_cb_layout *args)
+nfs4_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p, struct nfs4_layoutrecall *args)
{
struct xdr_stream xdr;
@@ -632,51 +637,38 @@ out:
* called with dp->dl_count inc'ed.
* nfs4_lock_state() may or may not have been called.
*/
-void
-nfsd4_cb_layout(struct nfs4_cb_layout *cbl)
+int
+nfsd4_cb_layout(struct nfs4_layoutrecall *clr)
{
- struct nfs4_client *clp = cbl->cbl_client;
+ struct nfs4_client *clp = clr->clr_client;
struct rpc_clnt *clnt = NULL;
struct rpc_message msg = {
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_LAYOUT],
- .rpc_argp = cbl,
+ .rpc_argp = clr,
};
- int retries = 1;
- int status = 0;
if (clp)
clnt = clp->cl_callback.cb_client;
+ clr->clr_status = -EIO;
if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
- return;
+ goto out;
msg.rpc_cred = nfsd4_lookupcred(clp, 0);
- if (IS_ERR(msg.rpc_cred))
+ if (IS_ERR(msg.rpc_cred)) {
+ clr->clr_status = PTR_ERR(msg.rpc_cred);
goto out;
-
- status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
- while (retries--) {
- switch (status) {
- case -EIO:
- /* Network partition? */
- case -EBADHANDLE:
- break;
- default:
- goto out_put_cred;
- }
- ssleep(2);
- status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
}
-out_put_cred:
+ clr->clr_status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+
put_rpccred(msg.rpc_cred);
-out:
- if (status == -EIO)
+ if (clr->clr_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_layout: status %d\n", status);
-
- return;
+ dprintk("NFSD: nfsd4_cb_layout: status %d\n", clr->clr_status);
+ return clr->clr_status;
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3d438e4..6a65586 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -87,9 +87,9 @@ static void nfs4_set_recdir(char *recdir);
/*
* Layout state - NFSv4.1 pNFS
*/
-static struct list_head layout_recall_lru;
static kmem_cache_t *pnfs_layout_slab = NULL;
-static void destroy_layout(struct nfs4_layout *lp);
+static kmem_cache_t *pnfs_layoutrecall_slab = NULL;
+static void destroy_layoutrecall(struct nfs4_layoutrecall *lrp);
static void release_pnfs_ds_dev_list(struct nfs4_stateid *stp);
#endif /* CONFIG_PNFS */
@@ -547,6 +547,8 @@ static void
free_nfs4_client(struct kref *kref)
{
struct nfs4_client *clp = container_of(kref, struct nfs4_client, cl_ref);
+ BUG_ON(!list_empty(&clp->cl_layouts));
+ BUG_ON(!list_empty(&clp->cl_layoutrecalls));
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
kfree(clp->cl_name.data);
@@ -578,7 +580,7 @@ expire_client(struct nfs4_client *clp)
{
struct nfs4_stateowner *sop;
struct nfs4_delegation *dp;
- struct nfs4_layout *lp;
+ struct nfs4_layoutrecall *lrp;
struct nfs41_session *ses;
struct list_head reaplist;
@@ -606,22 +608,14 @@ expire_client(struct nfs4_client *clp)
list_del(&clp->cl_strhash);
list_del(&clp->cl_lru);
#if defined(CONFIG_PNFS)
- spin_lock(&recall_lock);
- while (!list_empty(&clp->cl_layouts)) {
- lp = list_entry(clp->cl_layouts.next, struct nfs4_layout, lo_perclnt);
- dprintk("NFSD: expire client. lp %p, fp %p\n", lp,
- lp->lo_file);
- BUG_ON(lp->lo_client != clp);
- list_del_init(&lp->lo_perclnt);
- list_move(&lp->lo_recall_lru, &reaplist);
+ while (!list_empty(&clp->cl_layoutrecalls)) {
+ lrp = list_entry(clp->cl_layoutrecalls.next,
+ struct nfs4_layoutrecall, clr_perclnt);
+ dprintk("NFSD: expire client. lrp %p, fp %p\n", lrp,
+ lrp->clr_file);
+ BUG_ON(lrp->clr_client != clp);
+ destroy_layoutrecall(lrp);
}
- spin_unlock(&recall_lock);
- while (!list_empty(&reaplist)) {
- lp = list_entry(reaplist.next, struct nfs4_layout, lo_recall_lru);
- list_del_init(&lp->lo_recall_lru);
- destroy_layout(lp);
- }
-
#endif
while (!list_empty(&clp->cl_openowners)) {
sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
@@ -648,6 +642,7 @@ create_client(struct xdr_netobj name, char *recdir) {
INIT_LIST_HEAD(&clp->cl_openowners);
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_layouts);
+ INIT_LIST_HEAD(&clp->cl_layoutrecalls);
INIT_LIST_HEAD(&clp->cl_sessions);
INIT_LIST_HEAD(&clp->cl_lru);
out:
@@ -1454,6 +1449,7 @@ nfsd4_free_slabs(void)
nfsd4_free_slab(&deleg_slab);
#if defined(CONFIG_PNFS)
nfsd4_free_slab(&pnfs_layout_slab);
+ nfsd4_free_slab(&pnfs_layoutrecall_slab);
#endif /* CONFIG_PNFS */
}
@@ -1481,6 +1477,10 @@ nfsd4_init_slabs(void)
sizeof(struct nfs4_layout), 0, 0, NULL, NULL);
if (pnfs_layout_slab == NULL)
goto out_nomem;
+ pnfs_layoutrecall_slab = kmem_cache_create("pnfs_layoutrecalls",
+ sizeof(struct nfs4_layoutrecall), 0, 0, NULL, NULL);
+ if (pnfs_layoutrecall_slab == NULL)
+ goto out_nomem;
#endif /* CONFIG_PNFS */
return 0;
@@ -3927,10 +3927,60 @@ destroy_layout(struct nfs4_layout *lp)
put_nfs4_file(fp);
}
+/*
+ * Create a layoutrecall structure
+ * An optional layoutrecall can be cloned (except for the layoutrecall lists)
+ */
+static struct nfs4_layoutrecall *
+alloc_init_layoutrecall(struct nfs4_layoutrecall *clone)
+{
+ struct nfs4_layoutrecall *clr;
+
+ dprintk("NFSD %s\n", __FUNCTION__);
+ clr = kmem_cache_alloc(pnfs_layoutrecall_slab, GFP_KERNEL);
+ if (clr == NULL)
+ return clr;
+
+ dprintk("NFSD %s clr %p clone %p\n", __FUNCTION__, clr, clone);
+
+ if (clone)
+ memcpy(clr, clone, sizeof(*clr));
+ else
+ memset(clr, 0, sizeof(*clr));
+ INIT_LIST_HEAD(&clr->clr_perclnt);
+
+ dprintk("NFSD %s return %p\n", __FUNCTION__, clr);
+ return clr;
+}
+
static void
-pnfs_hash_cb_layout(struct nfs4_layout *lp)
+hash_layoutrecall(struct nfs4_layoutrecall *clr)
{
- list_add(&lp->lo_recall_lru, &layout_recall_lru);
+ struct nfs4_client *clp = clr->clr_client;
+ struct nfs4_file *fp = clr->clr_file;
+
+ dprintk("NFSD %s clr %p clp %p fp %p\n", __FUNCTION__, clr, clp, fp);
+ get_nfs4_client(clp);
+ list_add(&clr->clr_perclnt, &clp->cl_layoutrecalls);
+ if (fp)
+ get_nfs4_file(fp);
+ dprintk("NFSD %s exit\n", __FUNCTION__);
+}
+
+static void
+destroy_layoutrecall(struct nfs4_layoutrecall *clr)
+{
+ int did_lock;
+
+ dprintk("pNFS %s: clr %p fp %p clp %p\n", __FUNCTION__, clr,
+ clr->clr_file, clr->clr_client);
+ did_lock = nfs4_trylock_state();
+ list_del(&clr->clr_perclnt);
+ put_nfs4_client(clr->clr_client);
+ put_nfs4_file(clr->clr_file);
+ nfs4_unlock_state();
+
+ kmem_cache_free(pnfs_layoutrecall_slab, clr);
}
/*
@@ -3990,6 +4040,36 @@ same_fsid(struct nfs4_fsid *fsid, struct svc_fh *current_fh)
}
/*
+ * find a layout recall conflicting with the specified layoutget
+ */
+static int
+is_layout_recalled(struct nfs4_client *clp, struct svc_fh *current_fh,
+ struct nfsd4_pnfs_layoutget *lgp)
+{
+ struct nfs4_layoutrecall *clr;
+
+ list_for_each_entry (clr, &clp->cl_layoutrecalls, clr_perclnt) {
+ if ((clr->clr_flags & LAYOUTRECALL_FLAG_DONE) ||
+ clr->cb.cbl_seg.layout_type != lgp->lg_seg.layout_type)
+ continue;
+
+ if (clr->cb.cbl_recall_type == RECALL_ALL)
+ return 1;
+ if (clr->cb.cbl_recall_type == RECALL_FSID) {
+ if (same_fsid(&clr->clr_file->fi_fsid, current_fh))
+ return 1;
+ else
+ continue;
+ }
+ BUG_ON(clr->cb.cbl_recall_type != RECALL_FILE);
+ if (clr->cb.cbl_seg.clientid == lgp->lg_seg.clientid &&
+ lo_seg_overlapping(&clr->cb.cbl_seg, &lgp->lg_seg))
+ return 1;
+ }
+ return 0;
+}
+
+/*
* are two octet ranges overlapping or adjacent?
*/
static inline int
@@ -4080,6 +4160,11 @@ int nfs4_pnfs_get_layout(struct super_block *sb, struct svc_fh *current_fh,
if (!fp || !clp)
goto out;
+ if (is_layout_recalled(clp, current_fh, lgp)) {
+ status = nfserr_recallconflict;
+ goto out;
+ }
+
can_merge = sb->s_export_op->can_merge_layouts != NULL &&
sb->s_export_op->can_merge_layouts(lgp->lg_seg.layout_type);
@@ -4225,49 +4310,127 @@ out:
return status;
}
+static int
+cl_has_file_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *clr)
+{
+ struct nfs4_layout *lp;
+
+ list_for_each_entry(lp, &clp->cl_layouts, lo_perclnt)
+ if (lp->lo_file == clr->clr_file)
+ return 1;
+
+ return 0;
+}
+
+static int
+cl_has_fsid_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *clr)
+{
+ struct nfs4_layout *lp;
+
+ /* note: minor version unused */
+ list_for_each_entry(lp, &clp->cl_layouts, lo_perclnt)
+ if (lp->lo_file->fi_fsid.major == clr->clr_file->fi_fsid.major)
+ return 1;
+
+ return 0;
+}
+
+static int
+cl_has_any_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *dummy)
+{
+ return !list_empty(&clp->cl_layouts);
+}
+
/*
- * Recall a layout
+ * Recall a layout asynchronously
+ * FIXME: Failures are nor reported back
*/
static int
-do_layout_recall(void *__lr)
+do_layout_recall(void *__clr)
{
- struct nfs4_cb_layout *lr = __lr;
+ struct nfs4_layoutrecall *pending, *clr = __clr;
struct nfs4_client *clp = NULL;
- unsigned int i;
+ unsigned int i;
+ int status;
+ struct list_head todolist;
+ static int (*__has_layout)(struct nfs4_client *,
+ struct nfs4_layoutrecall *);
daemonize("nfsv4-layout");
- if (lr->cbl_recall_type == RECALL_ALL) {
- for (i = 0; i < CLIENT_HASH_SIZE; i++) {
- list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash) {
- if (clp) {
- if (!clp->cl_callback.cb_client)
- continue;
-//??? check if this client has any layouts
- lr->cbl_client = clp;
- nfsd4_cb_layout(lr);
- }
- }
- }
+ INIT_LIST_HEAD(&todolist);
+
+ /* specific client */
+ if (clr->clr_client) {
+ list_add(&clr->clr_perclnt, &todolist);
+ clr = NULL; /* so it won't be destroyed here */
+ goto doit;
}
- if (lr->cbl_recall_type == RECALL_FSID) {
- for (i = 0; i < CLIENT_HASH_SIZE; i++) {
- list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash) {
- if (clp) {
- if (!clp->cl_callback.cb_client)
- continue;
-//??? check if this client has any layouts for this FSID
- lr->cbl_client = clp;
- nfsd4_cb_layout(lr);
- }
+
+ switch (clr->cb.cbl_recall_type) {
+ case RECALL_FILE:
+ __has_layout = cl_has_file_layout;
+ break;
+ case RECALL_FSID:
+ __has_layout = cl_has_fsid_layout;
+ break;
+ case RECALL_ALL:
+ __has_layout = cl_has_any_layout;
+ break;
+ }
+
+ nfs4_lock_state();
+ for (i = 0; i < CLIENT_HASH_SIZE; i++)
+ list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash)
+ if (__has_layout(clp, clr)) {
+ pending = alloc_init_layoutrecall(clr);
+ if (!pending)
+ goto doit;
+ pending->clr_client = clp;
+ list_add(&pending->clr_perclnt, &todolist);
}
+ nfs4_unlock_state();
+
+ /* cleanup only in the multi client, single client went into todolist */
+ destroy_layoutrecall(clr);
+
+doit:
+ while (!list_empty(&todolist)) {
+ pending = list_entry(todolist.next, struct nfs4_layoutrecall,
+ clr_perclnt);
+ list_del(&pending->clr_perclnt);
+ dprintk("%s: clp %p cb_client %p fp %p\n", __FUNCTION__,
+ pending->clr_client,
+ pending->clr_client->cl_callback.cb_client,
+ pending->clr_file);
+ if (unlikely(!pending->clr_client->cl_callback.cb_client)) {
+ printk("%s: clientid %llx has no callback path\n",
+ __FUNCTION__,
+ (unsigned long long)clr->cb.cbl_seg.clientid);
+ destroy_layoutrecall(pending);
+ continue;
}
+ pending->clr_flags = LAYOUTRECALL_FLAG_PENDING;
+ pending->clr_time = CURRENT_TIME;
+ nfs4_lock_state();
+ hash_layoutrecall(pending);
+ nfs4_unlock_state();
+ status = nfsd4_cb_layout(pending);
+ if (status && status != NFSERR_NOMATCHING_LAYOUT)
+ printk("%s: clp %p cb_client %p fp %p "
+ "failed with status %d\n", __FUNCTION__,
+ pending->clr_client,
+ pending->clr_client->cl_callback.cb_client,
+ pending->clr_file,
+ status);
+ nfs4_lock_state();
+ if (!status && !(pending->clr_flags & LAYOUTRECALL_FLAG_DONE))
+ pending->clr_flags &= ~LAYOUTRECALL_FLAG_PENDING;
+ else
+ destroy_layoutrecall(pending);
+ nfs4_unlock_state();
}
- if (lr->cbl_recall_type == RECALL_FILE) {
-//??? find layout for this file (given by inode)
- if (lr->cbl_client)
- nfsd4_cb_layout(lr);
- }
+
return 0;
}
@@ -4275,22 +4438,60 @@ do_layout_recall(void *__lr)
* Spawn a thread to perform a recall layout
*
*/
-void nfsd_layout_recall_cb(struct nfs4_cb_layout *lr)
+int nfsd_layout_recall_cb(struct inode *inode, struct nfsd4_pnfs_cb_layout *cbl)
{
+ int status;
+ struct nfs4_layoutrecall *clr = NULL;
struct task_struct *t;
- dprintk("NFSD nfsd_layout_recall_cb: lp %p\n",lr);
- if (!lr)
- return;
+ dprintk("NFSD nfsd_layout_recall_cb: inode %p cbl %p\n", inode, cbl);
+ BUG_ON(!cbl);
+ BUG_ON(cbl->cbl_recall_type != RECALL_FILE &&
+ cbl->cbl_recall_type != RECALL_FSID &&
+ cbl->cbl_recall_type != RECALL_ALL);
+ BUG_ON(cbl->cbl_recall_type != RECALL_ALL && !inode);
- t = kthread_run(do_layout_recall, lr, "%s", "nfs4_cb_recall");
- if (IS_ERR(t)) {
- struct nfs4_client *clp = lr->cbl_client;
+ clr = alloc_init_layoutrecall(NULL);
+ if (!clr)
+ return -ENOMEM;
+ clr->cb = *cbl;
- printk(KERN_INFO "NFSD: Callback thread failed for "
- "for client (clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+ INIT_LIST_HEAD(&clr->clr_perclnt);
+ clr->clr_client = NULL;
+ clr->clr_file = NULL;
+
+ nfs4_lock_state();
+ status = -ENOENT;
+ if (clr->cb.cbl_seg.clientid) {
+ clr->clr_client =
+ find_confirmed_client((clientid_t *)&clr->cb.cbl_seg.clientid);
+ if (!clr->clr_client) {
+ printk("%s: clientid %llx not found\n", __FUNCTION__,
+ (unsigned long long)clr->cb.cbl_seg.clientid);
+ goto err;
+ }
+ }
+ if (inode) {
+ clr->clr_file = find_file(inode);
+ if (!clr->clr_file) {
+ dprintk("NFSD nfsd_layout_recall_cb: nfs4_file not found\n");
+ goto err;
+ }
}
+ nfs4_unlock_state();
+
+ t = kthread_run(do_layout_recall, clr, "%s", "nfs4_cb_recall");
+ if (!IS_ERR(t))
+ return 0; /* Success!, refcounts handled by kthread */
+
+ status = PTR_ERR(t);
+ nfs4_lock_state();
+err:
+ put_nfs4_client(clr->clr_client);
+ put_nfs4_file(clr->clr_file);
+ nfs4_unlock_state();
+ destroy_layoutrecall(clr);
+ return status;
}
#endif /* CONFIG_PNFS */
diff --git a/include/linux/nfsd/nfsd4_pnfs.h b/include/linux/nfsd/nfsd4_pnfs.h
index c63c5a9..e133c9c 100644
--- a/include/linux/nfsd/nfsd4_pnfs.h
+++ b/include/linux/nfsd/nfsd4_pnfs.h
@@ -113,4 +113,10 @@ struct nfsd4_pnfs_layoutreturn {
u32 lr_flags;
};
+struct nfsd4_pnfs_cb_layout {
+ u32 cbl_recall_type; /* request */
+ struct nfsd4_layout_seg cbl_seg; /* request */
+ u32 cbl_layoutchanged; /* request */
+};
+
#endif /* _LINUX_NFSD_NFSD4_PNFS_H */
diff --git a/include/linux/nfsd/pnfsd.h b/include/linux/nfsd/pnfsd.h
index 04db406..8311d2d 100644
--- a/include/linux/nfsd/pnfsd.h
+++ b/include/linux/nfsd/pnfsd.h
@@ -78,7 +78,7 @@ struct pnfs_mds_id {
time_t di_mdsboot; /* mds boot time */
};
-void nfsd_layout_recall_cb(struct nfs4_cb_layout *);
+int nfsd_layout_recall_cb(struct inode *inode, struct nfsd4_pnfs_cb_layout *);
int nfs4_pnfs_cb_get_state(struct pnfs_get_state *);
void nfs4_pnfs_state_init(void);
int nfs4_pnfs_get_layout(struct super_block *, struct svc_fh *,
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 5040b6f..18b8b99 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -202,6 +202,7 @@ struct nfs4_client {
struct list_head cl_delegations;
#ifdef CONFIG_PNFS
struct list_head cl_layouts; /* outstanding layouts */
+ struct list_head cl_layoutrecalls; /* outstanding layoutrecall callbacks */
#endif /* CONFIG_PNFS */
struct list_head cl_sessions;
struct list_head cl_lru; /* tail queue */
@@ -230,31 +231,31 @@ struct nfs4_fsid {
#ifdef CONFIG_PNFS
#include <linux/nfsd/nfsd4_pnfs.h>
-struct nfs4_cb_layout {
- struct super_block *cbl_sb;
- struct nfs4_client *cbl_client;
- u32 cbl_ident;
- u32 cbl_recall_type;
- u32 cbl_layout_type;
- u32 cbl_iomode;
- u32 cbl_layoutchanged;
- u64 cbl_offset;
- u64 cbl_length;
- struct nfs4_fsid cbl_fsid;
- u32 cbl_fhlen;
- u32 cbl_fhval[NFS4_FHSIZE];
-};
-
/* outstanding layout */
struct nfs4_layout {
struct list_head lo_perfile; /* hash by f_id */
struct list_head lo_perclnt; /* hash by clientid */
- struct list_head lo_recall_lru; /* when in recall */
struct nfs4_file *lo_file; /* backpointer */
struct nfs4_client *lo_client;
struct nfsd4_layout_seg lo_seg;
};
+enum {
+ LAYOUTRECALL_FLAG_PENDING = 1<<0,
+ LAYOUTRECALL_FLAG_DONE = 1<<1,
+};
+
+/* layoutrecall request (from exported filesystem) */
+struct nfs4_layoutrecall {
+ struct nfsd4_pnfs_cb_layout cb; /* request */
+ struct list_head clr_perclnt; /* on cl_layoutrecalls */
+ struct nfs4_client *clr_client;
+ struct nfs4_file *clr_file;
+ int clr_status;
+ unsigned clr_flags;
+ struct timespec clr_time; /* last activity */
+};
+
#endif /* CONFIG_PNFS */
/* struct nfs4_client_reset
@@ -430,7 +431,7 @@ extern void nfs4_free_stateowner(struct kref *kref);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
#ifdef CONFIG_PNFS
-extern void nfsd4_cb_layout(struct nfs4_cb_layout *lp);
+extern int nfsd4_cb_layout(struct nfs4_layoutrecall *lp);
#endif /* CONFIG_PNFS */
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
--
1.5.1
--------------070205060706090907070607--
More information about the pNFS
mailing list