[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