[pnfs] [PATCH 15/21] pnfsblock: read path short reads

Fred Isaman iisaman at citi.umich.edu
Thu Apr 10 10:07:31 EDT 2008


Handle read request crossing an extent boundary by using the nfs
short read infrastructure.

Signed-off-by: Fred Isaman <iisaman at citi.umich.edu>
---
 fs/nfs/blocklayout/blocklayout.c |   71 +++++++++++++++++++++++++++++---------
 1 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 6d8a897..c98afed 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -188,7 +188,8 @@ static void bl_readlist_done(struct nfs_read_data *rdata, int status)
 	/* STUB - need to think through what to put into rdata */
 	rdata->task.tk_status = status;
 	rdata->res.eof = 0;
-	rdata->res.count = (status ? 0 : rdata->args.count);
+	if (status)
+		rdata->res.count = 0;
 	pnfs_callback_ops->nfs_readlist_complete(rdata);
 }
 
@@ -249,41 +250,77 @@ bl_read_pagelist(struct pnfs_layout_type *layoutid,
 	}
 	isect = (sector_t) (f_offset >> 9);
 	be = find_get_extent(rdata->lseg, isect, &cow_read);
-	if (!be || count > (be->be_length << 9)) {
-		/* STUB - if count is large, should break into
-		 * multiple bios. Also, need to check cow_read size.
-		 */
+	if (!be)
 		goto use_mds;
-	}
+	/* We are relying on nfs short read handling to deal with multiple
+	 * extents covering the range, on the assumption this won't be
+	 * very common, since this serializes io per extent.
+	 */
+	count = min(count, (size_t)be->be_length << 9);
 	hole = is_hole(be, isect);
 	if (hole && !cow_read) {
+		struct page **pp;
+		unsigned int pglen;
 		/* Fill hole w/ zeroes w/o accessing device */
 		dprintk("%s Zeroing pages for hole\n", __func__);
-		for (i = 0; i < nr_pages; i++) {
-			zero_user(pages[i], 0,
-				  min_t(int, PAGE_CACHE_SIZE, count));
-			print_page(pages[i]);
-			count -= PAGE_CACHE_SIZE;
+		rdata->res.count = count;
+		pp = &rdata->args.pages[pgbase >> PAGE_CACHE_SHIFT];
+		pgbase &= ~PAGE_CACHE_MASK;
+		pglen = PAGE_CACHE_SIZE - pgbase;
+		for (;;) {
+			/* This code is similar to
+			 * nfs_readpage_truncate_uninitialised_page
+			 */
+			print_page(*pp);
+			if (count <= pglen) {
+				zero_user(*pp, pgbase, count);
+				break;
+			}
+			zero_user(*pp, pgbase, pglen);
+			pp++;
+			count -= pglen;
+			pglen = PAGE_CACHE_SIZE;
+			pgbase = 0;
 		}
 		bl_readlist_done(rdata, 0);
 	} else {
 		struct pnfs_block_extent *be_read;
 		int added;
-		be_read = hole && cow_read ? cow_read : be;
+		unsigned int pglen;
+
+		if (hole && cow_read) {
+			be_read = cow_read;
+			count = min(count, (size_t)be_read->be_length << 9);
+		} else
+			be_read = be;
+		rdata->res.count = count;
+		nr_pages = 1 + (pgbase + count - 1) / PAGE_CACHE_SIZE;
 		bio = bio_alloc(GFP_NOIO, nr_pages);
 		bio->bi_sector = isect - be_read->be_f_offset +
 			be_read->be_v_offset;
 		bio->bi_bdev = be_read->be_mdev;
 		bio->bi_end_io = bl_end_read_bio;
 		bio->bi_private = rdata;
-		for (i = 0; i < nr_pages; i++) {
-			added = bio_add_page(bio, pages[i], PAGE_SIZE, 0);
-			if (added < PAGE_SIZE) {
-				dprintk("%s bio_add_page(%lu)=%i\n",
-					__func__, PAGE_SIZE, added);
+		pglen = PAGE_CACHE_SIZE;
+		for (i = pgbase >> PAGE_CACHE_SHIFT; i < nr_pages; i++) {
+			dprintk("%s loop i=%i, count=%i\n", __func__, i, count);
+			/* XXX Adding anything less than full page causes
+			 * bio never to be sent, despite callback returning
+			 * without error.  Thus can't accept call from
+			 * pagein_multi for now.
+			 */
+			added = bio_add_page(bio, pages[i], pglen, 0);
+			if (added < pglen) {
+				dprintk("%s bio_add_page(%u)=%i\n",
+					__func__, pglen, added);
 				bio_put(bio);
+				/* FIXME BUG - is this right on second try? */
+				/* FIXME BUG - res.count incorrect */
 				goto use_mds;
 			}
+			if (pglen >= count)
+				break;
+			count -= pglen;
 		}
 		dprintk("%s submitting read bio %u@%Lu\n", __func__,
 			bio->bi_size, (u64)bio->bi_sector);
-- 
1.5.3.3



More information about the pNFS mailing list