[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