[PATCH] layout return changes for nfsd layout cache
Benny Halevy
bhalevy at ns1.bhalevy.com
Mon May 7 13:51:02 EDT 2007
---
fs/nfsd/nfs4proc.c | 18 +++++
fs/nfsd/nfs4state.c | 174 +++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 165 insertions(+), 27 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8ae3291..919bfe5 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -939,6 +939,24 @@ nfsd4_layoutreturn( struct svc_rqst *rqstp, struct current_session *cses, struct
goto out;
}
+ status = nfserr_inval;
+ if (lrp->lr_return_type != RETURN_FILE &&
+ lrp->lr_return_type != RETURN_FSID &&
+ lrp->lr_return_type != RETURN_ALL) {
+ dprintk("pNFS %s: invalid return_type %d\n", __FUNCTION__,
+ lrp->lr_return_type);
+ goto out;
+ }
+
+ status = nfserr_inval;
+ if (lrp->lr_seg.iomode != IOMODE_READ &&
+ lrp->lr_seg.iomode != IOMODE_RW &&
+ lrp->lr_seg.iomode != IOMODE_ANY) {
+ dprintk("pNFS %s: invalid iomode %d\n", __FUNCTION__,
+ lrp->lr_seg.iomode);
+ goto out;
+ }
+
/* Set clientid from sessionid */
lrp->lr_seg.clientid = *(u64 *)&cses->cs_sid.clientid;
status = nfs4_pnfs_return_layout(sb, current_fh, lrp);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6a65586..34b46ee 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4127,19 +4127,6 @@ merge_layout(struct nfs4_file *fp, struct nfs4_client *clp,
return NULL;
}
-static struct nfs4_layout *
-find_layout(struct nfs4_file *fp, struct nfs4_client *clp)
-{
- struct nfs4_layout *lp;
-
- list_for_each_entry (lp, &fp->fi_layouts, lo_perfile) {
- //??? if the right layout
- if (lp->lo_client == clp)
- return lp;
- }
- return NULL;
-}
-
int nfs4_pnfs_get_layout(struct super_block *sb, struct svc_fh *current_fh,
struct nfsd4_pnfs_layoutget *lgp)
{
@@ -4235,37 +4222,170 @@ out:
return status;
}
+static void
+trim_layout(struct nfsd4_layout_seg *lo, struct nfsd4_layout_seg *lr)
+{
+ u64 lo_start = lo->offset;
+ u64 lo_end = end_offset(lo_start, lo->length);
+ u64 lr_start = lr->offset;
+ u64 lr_end = end_offset(lr_start, lr->length);
+
+ /* lr fully covers lo? */
+ if (lr_start <= lo_start && lo_end <= lr_end) {
+ lo->length = 0;
+ return;
+ }
+
+ /*
+ * split not supported yet. retain layout segment.
+ * remains must be returned by the client
+ * on the final layout return.
+ */
+ if (lo_start < lr_start && lr_end < lo_end) {
+ return;
+ }
+
+ if (lo_start < lr_start)
+ lo_end = lr_start - 1;
+ else /* lr_end < lo_end */
+ lo_start = lr_end + 1;
+
+ lo->offset = lo_start;
+ lo->length = (lo_end == NFS4_LENGTH_EOF) ?
+ lo_end : lo_end - lo_start;
+}
+
+static void
+layoutrecall_done(struct nfs4_layoutrecall *clr)
+{
+ clr->clr_time = CURRENT_TIME;
+ clr->clr_flags |= LAYOUTRECALL_FLAG_DONE;
+ if (clr->clr_flags & LAYOUTRECALL_FLAG_PENDING)
+ return;
+ destroy_layoutrecall(clr);
+}
+
+static int
+recall_return_perfect_match(struct nfs4_layoutrecall *clr,
+ struct nfsd4_pnfs_layoutreturn *lrp,
+ struct nfs4_file *fp,
+ struct svc_fh *current_fh)
+{
+ if (clr->cb.cbl_seg.iomode != lrp->lr_seg.iomode ||
+ clr->cb.cbl_recall_type != lrp->lr_return_type)
+ return 0;
+
+ return (clr->cb.cbl_recall_type == RECALL_FILE &&
+ clr->clr_file == fp &&
+ clr->cb.cbl_seg.offset == lrp->lr_seg.offset &&
+ clr->cb.cbl_seg.length == lrp->lr_seg.length) ||
+
+ (clr->cb.cbl_recall_type == RECALL_FSID &&
+ same_fsid(&clr->clr_file->fi_fsid, current_fh)) ||
+
+ clr->cb.cbl_recall_type == RECALL_ALL;
+}
+
+static int
+recall_return_partial_match(struct nfs4_layoutrecall *clr,
+ struct nfsd4_pnfs_layoutreturn *lrp,
+ struct nfs4_file *fp,
+ struct svc_fh *current_fh)
+{
+ /* iomode matching? */
+ if (clr->cb.cbl_seg.iomode != lrp->lr_seg.iomode &&
+ clr->cb.cbl_seg.iomode != IOMODE_ANY &&
+ lrp->lr_seg.iomode != IOMODE_ANY)
+ return 0;
+
+ if (clr->cb.cbl_recall_type == RECALL_ALL ||
+ lrp->lr_return_type == RETURN_ALL)
+ return 1;
+
+ /* fsid matches? */
+ if (clr->cb.cbl_recall_type == RECALL_FSID ||
+ lrp->lr_return_type == RETURN_FSID)
+ return same_fsid(&clr->clr_file->fi_fsid, current_fh);
+
+ /* file matches, range overlapping? */
+ return clr->clr_file == fp &&
+ lo_seg_overlapping(&clr->cb.cbl_seg, &lrp->lr_seg);
+}
+
int nfs4_pnfs_return_layout(struct super_block *sb, struct svc_fh *current_fh,
struct nfsd4_pnfs_layoutreturn *lrp)
{
int status = -ENOENT;
+ int layouts_found = 0;
struct inode *ino = current_fh->fh_dentry->d_inode;
- struct nfs4_file *fp;
- struct nfs4_client *clp;
- struct nfs4_layout *lp;
+ struct nfs4_file *fp = NULL;
+ struct nfs4_client *clp = NULL;
+ struct nfs4_layout *lp, *nextlp;
+ struct nfs4_layoutrecall *clr, *nextclr;
+
+ dprintk("NFSD: %s\n", __FUNCTION__);
- dprintk("NFSD: nfs4_pnfs_return_layout\n");
+ /* call exported filesystem layout_return first */
+ if (sb->s_export_op->layout_return) {
+ status = sb->s_export_op->layout_return(ino, lrp);
+ if (status)
+ goto out;
+ }
+ nfs4_lock_state();
+ clp = find_confirmed_client((clientid_t *)&lrp->lr_seg.clientid);
+ if (!clp)
+ goto out;
fp = find_file(ino);
if (!fp)
goto out;
- dprintk("pNFS %s: fp %p\n", __FUNCTION__, fp);
+ dprintk("pNFS %s: clp %p fp %p\n", __FUNCTION__, clp, fp);
- clp = find_confirmed_client((clientid_t *)&lrp->lr_seg.clientid);
- dprintk("pNFS %s: clp %p \n", __FUNCTION__, clp);
- if (!clp)
- goto out;
+ /* update layouts */
+ if (lrp->lr_return_type == RETURN_FILE) {
+ list_for_each_entry_safe (lp, nextlp, &fp->fi_layouts, lo_perclnt) {
+ if (lp->lo_client != clp ||
+ lp->lo_seg.layout_type != lrp->lr_seg.layout_type ||
+ (lp->lo_seg.iomode != lrp->lr_seg.iomode &&
+ lrp->lr_seg.iomode != IOMODE_ANY) ||
+ !lo_seg_overlapping(&lp->lo_seg, &lrp->lr_seg))
+ continue;
+ layouts_found++;
+ trim_layout(&lp->lo_seg, &lrp->lr_seg);
+ if (!lp->lo_seg.length)
+ destroy_layout(lp);
+ }
+ } else list_for_each_entry_safe (lp, nextlp, &clp->cl_layouts, lo_perclnt) {
+ if (lrp->lr_seg.layout_type != lp->lo_seg.layout_type ||
+ (lrp->lr_seg.iomode != lp->lo_seg.iomode &&
+ lrp->lr_seg.iomode != IOMODE_ANY))
+ continue;
- lp = find_layout(fp, clp);
- dprintk("pNFS %s: lp %p\n", __FUNCTION__, lp);
+ if (lrp->lr_return_type == RETURN_FSID &&
+ !same_fsid(&lp->lo_file->fi_fsid, current_fh))
+ continue;
- if (lp) {
+ layouts_found++;
destroy_layout(lp);
- status = 0;
}
- put_nfs4_file(fp);
+
+ /* update layoutrecalls */
+ list_for_each_entry_safe (clr, nextclr, &clp->cl_layoutrecalls, clr_perclnt) {
+ if (clr->cb.cbl_seg.layout_type != lrp->lr_seg.layout_type)
+ continue;
+
+ if (recall_return_perfect_match(clr, lrp, fp, current_fh))
+ layoutrecall_done(clr);
+ else if (layouts_found &&
+ recall_return_partial_match(clr, lrp, fp, current_fh))
+ clr->clr_time = CURRENT_TIME;
+ }
+
out:
+ put_nfs4_client(clp);
+ put_nfs4_file(fp);
+ nfs4_unlock_state();
dprintk("pNFS %s: exit status %d \n", __FUNCTION__, status);
return status;
}
--
1.5.1
--------------090709040407080005040504--
More information about the pNFS
mailing list