Commit cd841605 authored by Fred Isaman's avatar Fred Isaman Committed by Trond Myklebust

NFS: create common nfs_pgio_header for both read and write

In order to avoid duplicating all the data in nfs_read_data whenever we
split it up into multiple RPC calls (either due to a short read result
or due to rsize < PAGE_SIZE), we split out the bits that are the same
per RPC call into a separate "header" structure.

The goal this patch moves towards is to have a single header
refcounted by several rpc_data structures.  Thus, want to always refer
from rpc_data to the header, and not the other way.  This patch comes
close to that ideal, but the directio code currently needs some
special casing, isolated in the nfs_direct_[read_write]hdr_release()
functions.  This will be dealt with in a future patch.
Signed-off-by: default avatarFred Isaman <iisaman@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent b5542849
...@@ -187,7 +187,6 @@ static void bl_end_io_read(struct bio *bio, int err) ...@@ -187,7 +187,6 @@ static void bl_end_io_read(struct bio *bio, int err)
struct parallel_io *par = bio->bi_private; struct parallel_io *par = bio->bi_private;
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
struct nfs_read_data *rdata = (struct nfs_read_data *)par->data;
do { do {
struct page *page = bvec->bv_page; struct page *page = bvec->bv_page;
...@@ -198,9 +197,12 @@ static void bl_end_io_read(struct bio *bio, int err) ...@@ -198,9 +197,12 @@ static void bl_end_io_read(struct bio *bio, int err)
SetPageUptodate(page); SetPageUptodate(page);
} while (bvec >= bio->bi_io_vec); } while (bvec >= bio->bi_io_vec);
if (!uptodate) { if (!uptodate) {
if (!rdata->pnfs_error) struct nfs_read_data *rdata = par->data;
rdata->pnfs_error = -EIO; struct nfs_pgio_header *header = rdata->header;
pnfs_set_lo_fail(rdata->lseg);
if (!header->pnfs_error)
header->pnfs_error = -EIO;
pnfs_set_lo_fail(header->lseg);
} }
bio_put(bio); bio_put(bio);
put_parallel(par); put_parallel(par);
...@@ -221,7 +223,7 @@ bl_end_par_io_read(void *data, int unused) ...@@ -221,7 +223,7 @@ bl_end_par_io_read(void *data, int unused)
{ {
struct nfs_read_data *rdata = data; struct nfs_read_data *rdata = data;
rdata->task.tk_status = rdata->pnfs_error; rdata->task.tk_status = rdata->header->pnfs_error;
INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
schedule_work(&rdata->task.u.tk_work); schedule_work(&rdata->task.u.tk_work);
} }
...@@ -229,6 +231,7 @@ bl_end_par_io_read(void *data, int unused) ...@@ -229,6 +231,7 @@ bl_end_par_io_read(void *data, int unused)
static enum pnfs_try_status static enum pnfs_try_status
bl_read_pagelist(struct nfs_read_data *rdata) bl_read_pagelist(struct nfs_read_data *rdata)
{ {
struct nfs_pgio_header *header = rdata->header;
int i, hole; int i, hole;
struct bio *bio = NULL; struct bio *bio = NULL;
struct pnfs_block_extent *be = NULL, *cow_read = NULL; struct pnfs_block_extent *be = NULL, *cow_read = NULL;
...@@ -256,10 +259,10 @@ bl_read_pagelist(struct nfs_read_data *rdata) ...@@ -256,10 +259,10 @@ bl_read_pagelist(struct nfs_read_data *rdata)
bl_put_extent(cow_read); bl_put_extent(cow_read);
bio = bl_submit_bio(READ, bio); bio = bl_submit_bio(READ, bio);
/* Get the next one */ /* Get the next one */
be = bl_find_get_extent(BLK_LSEG2EXT(rdata->lseg), be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg),
isect, &cow_read); isect, &cow_read);
if (!be) { if (!be) {
rdata->pnfs_error = -EIO; header->pnfs_error = -EIO;
goto out; goto out;
} }
extent_length = be->be_length - extent_length = be->be_length -
...@@ -286,7 +289,7 @@ bl_read_pagelist(struct nfs_read_data *rdata) ...@@ -286,7 +289,7 @@ bl_read_pagelist(struct nfs_read_data *rdata)
isect, pages[i], be_read, isect, pages[i], be_read,
bl_end_io_read, par); bl_end_io_read, par);
if (IS_ERR(bio)) { if (IS_ERR(bio)) {
rdata->pnfs_error = PTR_ERR(bio); header->pnfs_error = PTR_ERR(bio);
bio = NULL; bio = NULL;
goto out; goto out;
} }
...@@ -294,9 +297,9 @@ bl_read_pagelist(struct nfs_read_data *rdata) ...@@ -294,9 +297,9 @@ bl_read_pagelist(struct nfs_read_data *rdata)
isect += PAGE_CACHE_SECTORS; isect += PAGE_CACHE_SECTORS;
extent_length -= PAGE_CACHE_SECTORS; extent_length -= PAGE_CACHE_SECTORS;
} }
if ((isect << SECTOR_SHIFT) >= rdata->inode->i_size) { if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
rdata->res.eof = 1; rdata->res.eof = 1;
rdata->res.count = rdata->inode->i_size - f_offset; rdata->res.count = header->inode->i_size - f_offset;
} else { } else {
rdata->res.count = (isect << SECTOR_SHIFT) - f_offset; rdata->res.count = (isect << SECTOR_SHIFT) - f_offset;
} }
...@@ -345,7 +348,6 @@ static void bl_end_io_write_zero(struct bio *bio, int err) ...@@ -345,7 +348,6 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
struct parallel_io *par = bio->bi_private; struct parallel_io *par = bio->bi_private;
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
struct nfs_write_data *wdata = (struct nfs_write_data *)par->data;
do { do {
struct page *page = bvec->bv_page; struct page *page = bvec->bv_page;
...@@ -358,9 +360,12 @@ static void bl_end_io_write_zero(struct bio *bio, int err) ...@@ -358,9 +360,12 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
} while (bvec >= bio->bi_io_vec); } while (bvec >= bio->bi_io_vec);
if (unlikely(!uptodate)) { if (unlikely(!uptodate)) {
if (!wdata->pnfs_error) struct nfs_write_data *data = par->data;
wdata->pnfs_error = -EIO; struct nfs_pgio_header *header = data->header;
pnfs_set_lo_fail(wdata->lseg);
if (!header->pnfs_error)
header->pnfs_error = -EIO;
pnfs_set_lo_fail(header->lseg);
} }
bio_put(bio); bio_put(bio);
put_parallel(par); put_parallel(par);
...@@ -370,12 +375,13 @@ static void bl_end_io_write(struct bio *bio, int err) ...@@ -370,12 +375,13 @@ static void bl_end_io_write(struct bio *bio, int err)
{ {
struct parallel_io *par = bio->bi_private; struct parallel_io *par = bio->bi_private;
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct nfs_write_data *wdata = (struct nfs_write_data *)par->data; struct nfs_write_data *data = par->data;
struct nfs_pgio_header *header = data->header;
if (!uptodate) { if (!uptodate) {
if (!wdata->pnfs_error) if (!header->pnfs_error)
wdata->pnfs_error = -EIO; header->pnfs_error = -EIO;
pnfs_set_lo_fail(wdata->lseg); pnfs_set_lo_fail(header->lseg);
} }
bio_put(bio); bio_put(bio);
put_parallel(par); put_parallel(par);
...@@ -391,9 +397,9 @@ static void bl_write_cleanup(struct work_struct *work) ...@@ -391,9 +397,9 @@ static void bl_write_cleanup(struct work_struct *work)
dprintk("%s enter\n", __func__); dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work); task = container_of(work, struct rpc_task, u.tk_work);
wdata = container_of(task, struct nfs_write_data, task); wdata = container_of(task, struct nfs_write_data, task);
if (likely(!wdata->pnfs_error)) { if (likely(!wdata->header->pnfs_error)) {
/* Marks for LAYOUTCOMMIT */ /* Marks for LAYOUTCOMMIT */
mark_extents_written(BLK_LSEG2EXT(wdata->lseg), mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg),
wdata->args.offset, wdata->args.count); wdata->args.offset, wdata->args.count);
} }
pnfs_ld_write_done(wdata); pnfs_ld_write_done(wdata);
...@@ -404,12 +410,12 @@ static void bl_end_par_io_write(void *data, int num_se) ...@@ -404,12 +410,12 @@ static void bl_end_par_io_write(void *data, int num_se)
{ {
struct nfs_write_data *wdata = data; struct nfs_write_data *wdata = data;
if (unlikely(wdata->pnfs_error)) { if (unlikely(wdata->header->pnfs_error)) {
bl_free_short_extents(&BLK_LSEG2EXT(wdata->lseg)->bl_inval, bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval,
num_se); num_se);
} }
wdata->task.tk_status = wdata->pnfs_error; wdata->task.tk_status = wdata->header->pnfs_error;
wdata->verf.committed = NFS_FILE_SYNC; wdata->verf.committed = NFS_FILE_SYNC;
INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup);
schedule_work(&wdata->task.u.tk_work); schedule_work(&wdata->task.u.tk_work);
...@@ -540,6 +546,7 @@ bl_find_get_zeroing_page(struct inode *inode, pgoff_t index, ...@@ -540,6 +546,7 @@ bl_find_get_zeroing_page(struct inode *inode, pgoff_t index,
static enum pnfs_try_status static enum pnfs_try_status
bl_write_pagelist(struct nfs_write_data *wdata, int sync) bl_write_pagelist(struct nfs_write_data *wdata, int sync)
{ {
struct nfs_pgio_header *header = wdata->header;
int i, ret, npg_zero, pg_index, last = 0; int i, ret, npg_zero, pg_index, last = 0;
struct bio *bio = NULL; struct bio *bio = NULL;
struct pnfs_block_extent *be = NULL, *cow_read = NULL; struct pnfs_block_extent *be = NULL, *cow_read = NULL;
...@@ -552,7 +559,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -552,7 +559,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
pgoff_t index; pgoff_t index;
u64 temp; u64 temp;
int npg_per_block = int npg_per_block =
NFS_SERVER(wdata->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT; NFS_SERVER(header->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT;
dprintk("%s enter, %Zu@%lld\n", __func__, count, offset); dprintk("%s enter, %Zu@%lld\n", __func__, count, offset);
/* At this point, wdata->pages is a (sequential) list of nfs_pages. /* At this point, wdata->pages is a (sequential) list of nfs_pages.
...@@ -566,7 +573,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -566,7 +573,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
/* At this point, have to be more careful with error handling */ /* At this point, have to be more careful with error handling */
isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT); isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT);
be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read); be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg), isect, &cow_read);
if (!be || !is_writable(be, isect)) { if (!be || !is_writable(be, isect)) {
dprintk("%s no matching extents!\n", __func__); dprintk("%s no matching extents!\n", __func__);
goto out_mds; goto out_mds;
...@@ -597,10 +604,10 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -597,10 +604,10 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
dprintk("%s zero %dth page: index %lu isect %llu\n", dprintk("%s zero %dth page: index %lu isect %llu\n",
__func__, npg_zero, index, __func__, npg_zero, index,
(unsigned long long)isect); (unsigned long long)isect);
page = bl_find_get_zeroing_page(wdata->inode, index, page = bl_find_get_zeroing_page(header->inode, index,
cow_read); cow_read);
if (unlikely(IS_ERR(page))) { if (unlikely(IS_ERR(page))) {
wdata->pnfs_error = PTR_ERR(page); header->pnfs_error = PTR_ERR(page);
goto out; goto out;
} else if (page == NULL) } else if (page == NULL)
goto next_page; goto next_page;
...@@ -612,7 +619,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -612,7 +619,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
__func__, ret); __func__, ret);
end_page_writeback(page); end_page_writeback(page);
page_cache_release(page); page_cache_release(page);
wdata->pnfs_error = ret; header->pnfs_error = ret;
goto out; goto out;
} }
if (likely(!bl_push_one_short_extent(be->be_inval))) if (likely(!bl_push_one_short_extent(be->be_inval)))
...@@ -620,11 +627,11 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -620,11 +627,11 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
else { else {
end_page_writeback(page); end_page_writeback(page);
page_cache_release(page); page_cache_release(page);
wdata->pnfs_error = -ENOMEM; header->pnfs_error = -ENOMEM;
goto out; goto out;
} }
/* FIXME: This should be done in bi_end_io */ /* FIXME: This should be done in bi_end_io */
mark_extents_written(BLK_LSEG2EXT(wdata->lseg), mark_extents_written(BLK_LSEG2EXT(header->lseg),
page->index << PAGE_CACHE_SHIFT, page->index << PAGE_CACHE_SHIFT,
PAGE_CACHE_SIZE); PAGE_CACHE_SIZE);
...@@ -632,7 +639,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -632,7 +639,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
isect, page, be, isect, page, be,
bl_end_io_write_zero, par); bl_end_io_write_zero, par);
if (IS_ERR(bio)) { if (IS_ERR(bio)) {
wdata->pnfs_error = PTR_ERR(bio); header->pnfs_error = PTR_ERR(bio);
bio = NULL; bio = NULL;
goto out; goto out;
} }
...@@ -653,10 +660,10 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -653,10 +660,10 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
bl_put_extent(be); bl_put_extent(be);
bio = bl_submit_bio(WRITE, bio); bio = bl_submit_bio(WRITE, bio);
/* Get the next one */ /* Get the next one */
be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg),
isect, NULL); isect, NULL);
if (!be || !is_writable(be, isect)) { if (!be || !is_writable(be, isect)) {
wdata->pnfs_error = -EINVAL; header->pnfs_error = -EINVAL;
goto out; goto out;
} }
if (be->be_state == PNFS_BLOCK_INVALID_DATA) { if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
...@@ -664,7 +671,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -664,7 +671,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
be->be_inval))) be->be_inval)))
par->bse_count++; par->bse_count++;
else { else {
wdata->pnfs_error = -ENOMEM; header->pnfs_error = -ENOMEM;
goto out; goto out;
} }
} }
...@@ -677,7 +684,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -677,7 +684,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
if (unlikely(ret)) { if (unlikely(ret)) {
dprintk("%s bl_mark_sectors_init fail %d\n", dprintk("%s bl_mark_sectors_init fail %d\n",
__func__, ret); __func__, ret);
wdata->pnfs_error = ret; header->pnfs_error = ret;
goto out; goto out;
} }
} }
...@@ -685,7 +692,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) ...@@ -685,7 +692,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
isect, pages[i], be, isect, pages[i], be,
bl_end_io_write, par); bl_end_io_write, par);
if (IS_ERR(bio)) { if (IS_ERR(bio)) {
wdata->pnfs_error = PTR_ERR(bio); header->pnfs_error = PTR_ERR(bio);
bio = NULL; bio = NULL;
goto out; goto out;
} }
......
...@@ -242,7 +242,7 @@ static void nfs_direct_read_release(void *calldata) ...@@ -242,7 +242,7 @@ static void nfs_direct_read_release(void *calldata)
{ {
struct nfs_read_data *data = calldata; struct nfs_read_data *data = calldata;
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; struct nfs_direct_req *dreq = (struct nfs_direct_req *)data->header->req;
int status = data->task.tk_status; int status = data->task.tk_status;
spin_lock(&dreq->lock); spin_lock(&dreq->lock);
...@@ -269,6 +269,15 @@ static const struct rpc_call_ops nfs_read_direct_ops = { ...@@ -269,6 +269,15 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
.rpc_release = nfs_direct_read_release, .rpc_release = nfs_direct_read_release,
}; };
static void nfs_direct_readhdr_release(struct nfs_read_header *rhdr)
{
struct nfs_read_data *data = &rhdr->rpc_data;
if (data->pagevec != data->page_array)
kfree(data->pagevec);
nfs_readhdr_free(&rhdr->header);
}
/* /*
* For each rsize'd chunk of the user's buffer, dispatch an NFS READ * For each rsize'd chunk of the user's buffer, dispatch an NFS READ
* operation. If nfs_readdata_alloc() or get_user_pages() fails, * operation. If nfs_readdata_alloc() or get_user_pages() fails,
...@@ -301,6 +310,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, ...@@ -301,6 +310,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
ssize_t started = 0; ssize_t started = 0;
do { do {
struct nfs_read_header *rhdr;
struct nfs_read_data *data; struct nfs_read_data *data;
size_t bytes; size_t bytes;
...@@ -308,23 +318,24 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, ...@@ -308,23 +318,24 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
bytes = min(rsize,count); bytes = min(rsize,count);
result = -ENOMEM; result = -ENOMEM;
data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes)); rhdr = nfs_readhdr_alloc(nfs_page_array_len(pgbase, bytes));
if (unlikely(!data)) if (unlikely(!rhdr))
break; break;
data = &rhdr->rpc_data;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
result = get_user_pages(current, current->mm, user_addr, result = get_user_pages(current, current->mm, user_addr,
data->npages, 1, 0, data->pagevec, NULL); data->npages, 1, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
if (result < 0) { if (result < 0) {
nfs_readdata_free(data); nfs_direct_readhdr_release(rhdr);
break; break;
} }
if ((unsigned)result < data->npages) { if ((unsigned)result < data->npages) {
bytes = result * PAGE_SIZE; bytes = result * PAGE_SIZE;
if (bytes <= pgbase) { if (bytes <= pgbase) {
nfs_direct_release_pages(data->pagevec, result); nfs_direct_release_pages(data->pagevec, result);
nfs_readdata_free(data); nfs_direct_readhdr_release(rhdr);
break; break;
} }
bytes -= pgbase; bytes -= pgbase;
...@@ -333,9 +344,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, ...@@ -333,9 +344,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
get_dreq(dreq); get_dreq(dreq);
data->req = (struct nfs_page *) dreq; rhdr->header.req = (struct nfs_page *) dreq;
data->inode = inode; rhdr->header.inode = inode;
data->cred = msg.rpc_cred; rhdr->header.cred = msg.rpc_cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.context = get_nfs_open_context(ctx); data->args.context = get_nfs_open_context(ctx);
data->args.lock_context = dreq->l_ctx; data->args.lock_context = dreq->l_ctx;
...@@ -447,13 +458,23 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -447,13 +458,23 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
return result; return result;
} }
static void nfs_direct_writehdr_release(struct nfs_write_header *whdr)
{
struct nfs_write_data *data = &whdr->rpc_data;
if (data->pagevec != data->page_array)
kfree(data->pagevec);
nfs_writehdr_free(&whdr->header);
}
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
{ {
while (!list_empty(&dreq->rewrite_list)) { while (!list_empty(&dreq->rewrite_list)) {
struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); struct nfs_pgio_header *hdr = list_entry(dreq->rewrite_list.next, struct nfs_pgio_header, pages);
list_del(&data->pages); struct nfs_write_header *whdr = container_of(hdr, struct nfs_write_header, header);
nfs_direct_release_pages(data->pagevec, data->npages); list_del(&hdr->pages);
nfs_writedata_free(data); nfs_direct_release_pages(whdr->rpc_data.pagevec, whdr->rpc_data.npages);
nfs_direct_writehdr_release(whdr);
} }
} }
...@@ -463,6 +484,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) ...@@ -463,6 +484,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
struct inode *inode = dreq->inode; struct inode *inode = dreq->inode;
struct list_head *p; struct list_head *p;
struct nfs_write_data *data; struct nfs_write_data *data;
struct nfs_pgio_header *hdr;
struct rpc_task *task; struct rpc_task *task;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_cred = dreq->ctx->cred, .rpc_cred = dreq->ctx->cred,
...@@ -479,7 +501,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) ...@@ -479,7 +501,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
get_dreq(dreq); get_dreq(dreq);
list_for_each(p, &dreq->rewrite_list) { list_for_each(p, &dreq->rewrite_list) {
data = list_entry(p, struct nfs_write_data, pages); hdr = list_entry(p, struct nfs_pgio_header, pages);
data = &(container_of(hdr, struct nfs_write_header, header))->rpc_data;
get_dreq(dreq); get_dreq(dreq);
...@@ -652,7 +675,8 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) ...@@ -652,7 +675,8 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
static void nfs_direct_write_release(void *calldata) static void nfs_direct_write_release(void *calldata)
{ {
struct nfs_write_data *data = calldata; struct nfs_write_data *data = calldata;
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; struct nfs_pgio_header *hdr = data->header;
struct nfs_direct_req *dreq = (struct nfs_direct_req *) hdr->req;
int status = data->task.tk_status; int status = data->task.tk_status;
spin_lock(&dreq->lock); spin_lock(&dreq->lock);
...@@ -684,7 +708,7 @@ static void nfs_direct_write_release(void *calldata) ...@@ -684,7 +708,7 @@ static void nfs_direct_write_release(void *calldata)
spin_unlock(&dreq->lock); spin_unlock(&dreq->lock);
if (put_dreq(dreq)) if (put_dreq(dreq))
nfs_direct_write_complete(dreq, data->inode); nfs_direct_write_complete(dreq, hdr->inode);
} }
static const struct rpc_call_ops nfs_write_direct_ops = { static const struct rpc_call_ops nfs_write_direct_ops = {
...@@ -725,6 +749,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, ...@@ -725,6 +749,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
ssize_t started = 0; ssize_t started = 0;
do { do {
struct nfs_write_header *whdr;
struct nfs_write_data *data; struct nfs_write_data *data;
size_t bytes; size_t bytes;
...@@ -732,23 +757,25 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, ...@@ -732,23 +757,25 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
bytes = min(wsize,count); bytes = min(wsize,count);
result = -ENOMEM; result = -ENOMEM;
data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes)); whdr = nfs_writehdr_alloc(nfs_page_array_len(pgbase, bytes));
if (unlikely(!data)) if (unlikely(!whdr))
break; break;
data = &whdr->rpc_data;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
result = get_user_pages(current, current->mm, user_addr, result = get_user_pages(current, current->mm, user_addr,
data->npages, 0, 0, data->pagevec, NULL); data->npages, 0, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
if (result < 0) { if (result < 0) {
nfs_writedata_free(data); nfs_direct_writehdr_release(whdr);
break; break;
} }
if ((unsigned)result < data->npages) { if ((unsigned)result < data->npages) {
bytes = result * PAGE_SIZE; bytes = result * PAGE_SIZE;
if (bytes <= pgbase) { if (bytes <= pgbase) {
nfs_direct_release_pages(data->pagevec, result); nfs_direct_release_pages(data->pagevec, result);
nfs_writedata_free(data); nfs_direct_writehdr_release(whdr);
break; break;
} }
bytes -= pgbase; bytes -= pgbase;
...@@ -757,11 +784,11 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, ...@@ -757,11 +784,11 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
get_dreq(dreq); get_dreq(dreq);
list_move_tail(&data->pages, &dreq->rewrite_list); list_move_tail(&whdr->header.pages, &dreq->rewrite_list);
data->req = (struct nfs_page *) dreq; whdr->header.req = (struct nfs_page *) dreq;
data->inode = inode; whdr->header.inode = inode;
data->cred = msg.rpc_cred; whdr->header.cred = msg.rpc_cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.context = ctx; data->args.context = ctx;
data->args.lock_context = dreq->l_ctx; data->args.lock_context = dreq->l_ctx;
......
...@@ -296,6 +296,8 @@ extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); ...@@ -296,6 +296,8 @@ extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
struct nfs_pageio_descriptor; struct nfs_pageio_descriptor;
/* read.c */ /* read.c */
extern struct nfs_read_header *nfs_readhdr_alloc(unsigned int npages);
extern void nfs_readhdr_free(struct nfs_pgio_header *hdr);
extern int nfs_initiate_read(struct rpc_clnt *clnt, extern int nfs_initiate_read(struct rpc_clnt *clnt,
struct nfs_read_data *data, struct nfs_read_data *data,
const struct rpc_call_ops *call_ops); const struct rpc_call_ops *call_ops);
...@@ -309,6 +311,8 @@ extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); ...@@ -309,6 +311,8 @@ extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_readdata_release(struct nfs_read_data *rdata); extern void nfs_readdata_release(struct nfs_read_data *rdata);
/* write.c */ /* write.c */
extern struct nfs_write_header *nfs_writehdr_alloc(unsigned int npages);
extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
struct list_head *head); struct list_head *head);
extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
......
...@@ -811,11 +811,13 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -811,11 +811,13 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) struct inode *inode = data->header->inode;
if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
nfs_invalidate_atime(data->inode); nfs_invalidate_atime(inode);
nfs_refresh_inode(data->inode, &data->fattr); nfs_refresh_inode(inode, &data->fattr);
return 0; return 0;
} }
...@@ -831,10 +833,12 @@ static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da ...@@ -831,10 +833,12 @@ static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da
static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) struct inode *inode = data->header->inode;
if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
return 0; return 0;
} }
......
...@@ -148,6 +148,7 @@ static int filelayout_async_handle_error(struct rpc_task *task, ...@@ -148,6 +148,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
static int filelayout_read_done_cb(struct rpc_task *task, static int filelayout_read_done_cb(struct rpc_task *task,
struct nfs_read_data *data) struct nfs_read_data *data)
{ {
struct nfs_pgio_header *hdr = data->header;
int reset = 0; int reset = 0;
dprintk("%s DS read\n", __func__); dprintk("%s DS read\n", __func__);
...@@ -157,7 +158,7 @@ static int filelayout_read_done_cb(struct rpc_task *task, ...@@ -157,7 +158,7 @@ static int filelayout_read_done_cb(struct rpc_task *task,
dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
__func__, data->ds_clp, data->ds_clp->cl_session); __func__, data->ds_clp, data->ds_clp->cl_session);
if (reset) { if (reset) {
pnfs_set_lo_fail(data->lseg); pnfs_set_lo_fail(hdr->lseg);
nfs4_reset_read(task, data); nfs4_reset_read(task, data);
} }
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
...@@ -175,13 +176,15 @@ static int filelayout_read_done_cb(struct rpc_task *task, ...@@ -175,13 +176,15 @@ static int filelayout_read_done_cb(struct rpc_task *task,
static void static void
filelayout_set_layoutcommit(struct nfs_write_data *wdata) filelayout_set_layoutcommit(struct nfs_write_data *wdata)
{ {
if (FILELAYOUT_LSEG(wdata->lseg)->commit_through_mds || struct nfs_pgio_header *hdr = wdata->header;
if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
wdata->res.verf->committed == NFS_FILE_SYNC) wdata->res.verf->committed == NFS_FILE_SYNC)
return; return;
pnfs_set_layoutcommit(wdata); pnfs_set_layoutcommit(wdata);
dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino, dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
(unsigned long) NFS_I(wdata->inode)->layout->plh_lwb); (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
} }
/* /*
...@@ -210,27 +213,28 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) ...@@ -210,27 +213,28 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
/* Note this may cause RPC to be resent */ /* Note this may cause RPC to be resent */
rdata->mds_ops->rpc_call_done(task, data); rdata->header->mds_ops->rpc_call_done(task, data);
} }
static void filelayout_read_count_stats(struct rpc_task *task, void *data) static void filelayout_read_count_stats(struct rpc_task *task, void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_read_data *rdata = data;
rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics); rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics);
} }
static void filelayout_read_release(void *data) static void filelayout_read_release(void *data)
{ {
struct nfs_read_data *rdata = data; struct nfs_read_data *rdata = data;
put_lseg(rdata->lseg); put_lseg(rdata->header->lseg);
rdata->mds_ops->rpc_release(data); rdata->header->mds_ops->rpc_release(data);
} }
static int filelayout_write_done_cb(struct rpc_task *task, static int filelayout_write_done_cb(struct rpc_task *task,
struct nfs_write_data *data) struct nfs_write_data *data)
{ {
struct nfs_pgio_header *hdr = data->header;
int reset = 0; int reset = 0;
if (filelayout_async_handle_error(task, data->args.context->state, if (filelayout_async_handle_error(task, data->args.context->state,
...@@ -238,7 +242,7 @@ static int filelayout_write_done_cb(struct rpc_task *task, ...@@ -238,7 +242,7 @@ static int filelayout_write_done_cb(struct rpc_task *task,
dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
__func__, data->ds_clp, data->ds_clp->cl_session); __func__, data->ds_clp, data->ds_clp->cl_session);
if (reset) { if (reset) {
pnfs_set_lo_fail(data->lseg); pnfs_set_lo_fail(hdr->lseg);
nfs4_reset_write(task, data); nfs4_reset_write(task, data);
} }
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
...@@ -297,22 +301,22 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data) ...@@ -297,22 +301,22 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
struct nfs_write_data *wdata = data; struct nfs_write_data *wdata = data;
/* Note this may cause RPC to be resent */ /* Note this may cause RPC to be resent */
wdata->mds_ops->rpc_call_done(task, data); wdata->header->mds_ops->rpc_call_done(task, data);
} }
static void filelayout_write_count_stats(struct rpc_task *task, void *data) static void filelayout_write_count_stats(struct rpc_task *task, void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_write_data *wdata = data;
rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics); rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics);
} }
static void filelayout_write_release(void *data) static void filelayout_write_release(void *data)
{ {
struct nfs_write_data *wdata = data; struct nfs_write_data *wdata = data;
put_lseg(wdata->lseg); put_lseg(wdata->header->lseg);
wdata->mds_ops->rpc_release(data); wdata->header->mds_ops->rpc_release(data);
} }
static void filelayout_commit_prepare(struct rpc_task *task, void *data) static void filelayout_commit_prepare(struct rpc_task *task, void *data)
...@@ -377,7 +381,8 @@ static const struct rpc_call_ops filelayout_commit_call_ops = { ...@@ -377,7 +381,8 @@ static const struct rpc_call_ops filelayout_commit_call_ops = {
static enum pnfs_try_status static enum pnfs_try_status
filelayout_read_pagelist(struct nfs_read_data *data) filelayout_read_pagelist(struct nfs_read_data *data)
{ {
struct pnfs_layout_segment *lseg = data->lseg; struct nfs_pgio_header *hdr = data->header;
struct pnfs_layout_segment *lseg = hdr->lseg;
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
loff_t offset = data->args.offset; loff_t offset = data->args.offset;
u32 j, idx; u32 j, idx;
...@@ -385,7 +390,7 @@ filelayout_read_pagelist(struct nfs_read_data *data) ...@@ -385,7 +390,7 @@ filelayout_read_pagelist(struct nfs_read_data *data)
int status; int status;
dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
__func__, data->inode->i_ino, __func__, hdr->inode->i_ino,
data->args.pgbase, (size_t)data->args.count, offset); data->args.pgbase, (size_t)data->args.count, offset);
if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags)) if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags))
...@@ -423,7 +428,8 @@ filelayout_read_pagelist(struct nfs_read_data *data) ...@@ -423,7 +428,8 @@ filelayout_read_pagelist(struct nfs_read_data *data)
static enum pnfs_try_status static enum pnfs_try_status
filelayout_write_pagelist(struct nfs_write_data *data, int sync) filelayout_write_pagelist(struct nfs_write_data *data, int sync)
{ {
struct pnfs_layout_segment *lseg = data->lseg; struct nfs_pgio_header *hdr = data->header;
struct pnfs_layout_segment *lseg = hdr->lseg;
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
loff_t offset = data->args.offset; loff_t offset = data->args.offset;
u32 j, idx; u32 j, idx;
...@@ -445,7 +451,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) ...@@ -445,7 +451,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
return PNFS_NOT_ATTEMPTED; return PNFS_NOT_ATTEMPTED;
} }
dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s\n", __func__, dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s\n", __func__,
data->inode->i_ino, sync, (size_t) data->args.count, offset, hdr->inode->i_ino, sync, (size_t) data->args.count, offset,
ds->ds_remotestr); ds->ds_remotestr);
data->write_done_cb = filelayout_write_done_cb; data->write_done_cb = filelayout_write_done_cb;
......
...@@ -3336,12 +3336,12 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -3336,12 +3336,12 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
void __nfs4_read_done_cb(struct nfs_read_data *data) void __nfs4_read_done_cb(struct nfs_read_data *data)
{ {
nfs_invalidate_atime(data->inode); nfs_invalidate_atime(data->header->inode);
} }
static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
{ {
struct nfs_server *server = NFS_SERVER(data->inode); struct nfs_server *server = NFS_SERVER(data->header->inode);
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
...@@ -3376,7 +3376,7 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message ...@@ -3376,7 +3376,7 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
{ {
if (nfs4_setup_sequence(NFS_SERVER(data->inode), if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args, &data->args.seq_args,
&data->res.seq_res, &data->res.seq_res,
task)) task))
...@@ -3387,22 +3387,25 @@ static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da ...@@ -3387,22 +3387,25 @@ static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da
/* Reset the the nfs_read_data to send the read to the MDS. */ /* Reset the the nfs_read_data to send the read to the MDS. */
void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data) void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data)
{ {
struct nfs_pgio_header *hdr = data->header;
struct inode *inode = hdr->inode;
dprintk("%s Reset task for i/o through\n", __func__); dprintk("%s Reset task for i/o through\n", __func__);
put_lseg(data->lseg); put_lseg(hdr->lseg);
data->lseg = NULL; hdr->lseg = NULL;
data->ds_clp = NULL;
/* offsets will differ in the dense stripe case */ /* offsets will differ in the dense stripe case */
data->args.offset = data->mds_offset; data->args.offset = data->mds_offset;
data->ds_clp = NULL; data->args.fh = NFS_FH(inode);
data->args.fh = NFS_FH(data->inode);
data->read_done_cb = nfs4_read_done_cb; data->read_done_cb = nfs4_read_done_cb;
task->tk_ops = data->mds_ops; task->tk_ops = hdr->mds_ops;
rpc_task_reset_client(task, NFS_CLIENT(data->inode)); rpc_task_reset_client(task, NFS_CLIENT(inode));
} }
EXPORT_SYMBOL_GPL(nfs4_reset_read); EXPORT_SYMBOL_GPL(nfs4_reset_read);
static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
{ {
struct inode *inode = data->inode; struct inode *inode = data->header->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
...@@ -3426,25 +3429,28 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -3426,25 +3429,28 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
/* Reset the the nfs_write_data to send the write to the MDS. */ /* Reset the the nfs_write_data to send the write to the MDS. */
void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data) void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data)
{ {
struct nfs_pgio_header *hdr = data->header;
struct inode *inode = hdr->inode;
dprintk("%s Reset task for i/o through\n", __func__); dprintk("%s Reset task for i/o through\n", __func__);
put_lseg(data->lseg); put_lseg(hdr->lseg);
data->lseg = NULL; hdr->lseg = NULL;
data->ds_clp = NULL; data->ds_clp = NULL;
data->write_done_cb = nfs4_write_done_cb; data->write_done_cb = nfs4_write_done_cb;
data->args.fh = NFS_FH(data->inode); data->args.fh = NFS_FH(inode);
data->args.bitmask = data->res.server->cache_consistency_bitmask; data->args.bitmask = data->res.server->cache_consistency_bitmask;
data->args.offset = data->mds_offset; data->args.offset = data->mds_offset;
data->res.fattr = &data->fattr; data->res.fattr = &data->fattr;
task->tk_ops = data->mds_ops; task->tk_ops = hdr->mds_ops;
rpc_task_reset_client(task, NFS_CLIENT(data->inode)); rpc_task_reset_client(task, NFS_CLIENT(inode));
} }
EXPORT_SYMBOL_GPL(nfs4_reset_write); EXPORT_SYMBOL_GPL(nfs4_reset_write);
static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
{ {
struct nfs_server *server = NFS_SERVER(data->inode); struct nfs_server *server = NFS_SERVER(data->header->inode);
if (data->lseg) { if (data->header->lseg) {
data->args.bitmask = NULL; data->args.bitmask = NULL;
data->res.fattr = NULL; data->res.fattr = NULL;
} else } else
...@@ -3460,7 +3466,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag ...@@ -3460,7 +3466,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
{ {
if (nfs4_setup_sequence(NFS_SERVER(data->inode), if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args, &data->args.seq_args,
&data->res.seq_res, &data->res.seq_res,
task)) task))
......
...@@ -440,11 +440,12 @@ static void _read_done(struct ore_io_state *ios, void *private) ...@@ -440,11 +440,12 @@ static void _read_done(struct ore_io_state *ios, void *private)
int objio_read_pagelist(struct nfs_read_data *rdata) int objio_read_pagelist(struct nfs_read_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header;
struct objio_state *objios; struct objio_state *objios;
int ret; int ret;
ret = objio_alloc_io_state(NFS_I(rdata->inode)->layout, true, ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, true,
rdata->lseg, rdata->args.pages, rdata->args.pgbase, hdr->lseg, rdata->args.pages, rdata->args.pgbase,
rdata->args.offset, rdata->args.count, rdata, rdata->args.offset, rdata->args.count, rdata,
GFP_KERNEL, &objios); GFP_KERNEL, &objios);
if (unlikely(ret)) if (unlikely(ret))
...@@ -483,12 +484,12 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) ...@@ -483,12 +484,12 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
{ {
struct objio_state *objios = priv; struct objio_state *objios = priv;
struct nfs_write_data *wdata = objios->oir.rpcdata; struct nfs_write_data *wdata = objios->oir.rpcdata;
struct address_space *mapping = wdata->header->inode->i_mapping;
pgoff_t index = offset / PAGE_SIZE; pgoff_t index = offset / PAGE_SIZE;
struct page *page = find_get_page(wdata->inode->i_mapping, index); struct page *page = find_get_page(mapping, index);
if (!page) { if (!page) {
page = find_or_create_page(wdata->inode->i_mapping, page = find_or_create_page(mapping, index, GFP_NOFS);
index, GFP_NOFS);
if (unlikely(!page)) { if (unlikely(!page)) {
dprintk("%s: grab_cache_page Failed index=0x%lx\n", dprintk("%s: grab_cache_page Failed index=0x%lx\n",
__func__, index); __func__, index);
...@@ -518,11 +519,12 @@ static const struct _ore_r4w_op _r4w_op = { ...@@ -518,11 +519,12 @@ static const struct _ore_r4w_op _r4w_op = {
int objio_write_pagelist(struct nfs_write_data *wdata, int how) int objio_write_pagelist(struct nfs_write_data *wdata, int how)
{ {
struct nfs_pgio_header *hdr = wdata->header;
struct objio_state *objios; struct objio_state *objios;
int ret; int ret;
ret = objio_alloc_io_state(NFS_I(wdata->inode)->layout, false, ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, false,
wdata->lseg, wdata->args.pages, wdata->args.pgbase, hdr->lseg, wdata->args.pages, wdata->args.pgbase,
wdata->args.offset, wdata->args.count, wdata, GFP_NOFS, wdata->args.offset, wdata->args.count, wdata, GFP_NOFS,
&objios); &objios);
if (unlikely(ret)) if (unlikely(ret))
......
...@@ -258,7 +258,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -258,7 +258,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
if (status >= 0) if (status >= 0)
rdata->res.count = status; rdata->res.count = status;
else else
rdata->pnfs_error = status; rdata->header->pnfs_error = status;
objlayout_iodone(oir); objlayout_iodone(oir);
/* must not use oir after this point */ /* must not use oir after this point */
...@@ -279,12 +279,14 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -279,12 +279,14 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
enum pnfs_try_status enum pnfs_try_status
objlayout_read_pagelist(struct nfs_read_data *rdata) objlayout_read_pagelist(struct nfs_read_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header;
struct inode *inode = hdr->inode;
loff_t offset = rdata->args.offset; loff_t offset = rdata->args.offset;
size_t count = rdata->args.count; size_t count = rdata->args.count;
int err; int err;
loff_t eof; loff_t eof;
eof = i_size_read(rdata->inode); eof = i_size_read(inode);
if (unlikely(offset + count > eof)) { if (unlikely(offset + count > eof)) {
if (offset >= eof) { if (offset >= eof) {
err = 0; err = 0;
...@@ -297,17 +299,17 @@ objlayout_read_pagelist(struct nfs_read_data *rdata) ...@@ -297,17 +299,17 @@ objlayout_read_pagelist(struct nfs_read_data *rdata)
} }
rdata->res.eof = (offset + count) >= eof; rdata->res.eof = (offset + count) >= eof;
_fix_verify_io_params(rdata->lseg, &rdata->args.pages, _fix_verify_io_params(hdr->lseg, &rdata->args.pages,
&rdata->args.pgbase, &rdata->args.pgbase,
rdata->args.offset, rdata->args.count); rdata->args.offset, rdata->args.count);
dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n", dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n",
__func__, rdata->inode->i_ino, offset, count, rdata->res.eof); __func__, inode->i_ino, offset, count, rdata->res.eof);
err = objio_read_pagelist(rdata); err = objio_read_pagelist(rdata);
out: out:
if (unlikely(err)) { if (unlikely(err)) {
rdata->pnfs_error = err; hdr->pnfs_error = err;
dprintk("%s: Returned Error %d\n", __func__, err); dprintk("%s: Returned Error %d\n", __func__, err);
return PNFS_NOT_ATTEMPTED; return PNFS_NOT_ATTEMPTED;
} }
...@@ -340,7 +342,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -340,7 +342,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
wdata->res.count = status; wdata->res.count = status;
wdata->verf.committed = oir->committed; wdata->verf.committed = oir->committed;
} else { } else {
wdata->pnfs_error = status; wdata->header->pnfs_error = status;
} }
objlayout_iodone(oir); objlayout_iodone(oir);
/* must not use oir after this point */ /* must not use oir after this point */
...@@ -363,15 +365,16 @@ enum pnfs_try_status ...@@ -363,15 +365,16 @@ enum pnfs_try_status
objlayout_write_pagelist(struct nfs_write_data *wdata, objlayout_write_pagelist(struct nfs_write_data *wdata,
int how) int how)
{ {
struct nfs_pgio_header *hdr = wdata->header;
int err; int err;
_fix_verify_io_params(wdata->lseg, &wdata->args.pages, _fix_verify_io_params(hdr->lseg, &wdata->args.pages,
&wdata->args.pgbase, &wdata->args.pgbase,
wdata->args.offset, wdata->args.count); wdata->args.offset, wdata->args.count);
err = objio_write_pagelist(wdata, how); err = objio_write_pagelist(wdata, how);
if (unlikely(err)) { if (unlikely(err)) {
wdata->pnfs_error = err; hdr->pnfs_error = err;
dprintk("%s: Returned Error %d\n", __func__, err); dprintk("%s: Returned Error %d\n", __func__, err);
return PNFS_NOT_ATTEMPTED; return PNFS_NOT_ATTEMPTED;
} }
......
...@@ -1191,13 +1191,15 @@ static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head * ...@@ -1191,13 +1191,15 @@ static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *
static void pnfs_ld_handle_write_error(struct nfs_write_data *data) static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
{ {
dprintk("pnfs write error = %d\n", data->pnfs_error); struct nfs_pgio_header *hdr = data->header;
if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
dprintk("pnfs write error = %d\n", hdr->pnfs_error);
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
PNFS_LAYOUTRET_ON_ERROR) { PNFS_LAYOUTRET_ON_ERROR) {
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(data->inode)->flags); clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
pnfs_return_layout(data->inode); pnfs_return_layout(hdr->inode);
} }
data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, &hdr->pages);
} }
/* /*
...@@ -1205,13 +1207,15 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) ...@@ -1205,13 +1207,15 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
*/ */
void pnfs_ld_write_done(struct nfs_write_data *data) void pnfs_ld_write_done(struct nfs_write_data *data)
{ {
if (likely(!data->pnfs_error)) { struct nfs_pgio_header *hdr = data->header;
if (!hdr->pnfs_error) {
pnfs_set_layoutcommit(data); pnfs_set_layoutcommit(data);
data->mds_ops->rpc_call_done(&data->task, data); hdr->mds_ops->rpc_call_done(&data->task, data);
} else } else
pnfs_ld_handle_write_error(data); pnfs_ld_handle_write_error(data);
put_lseg(data->lseg); put_lseg(hdr->lseg);
data->mds_ops->rpc_release(data); hdr->mds_ops->rpc_release(data);
} }
EXPORT_SYMBOL_GPL(pnfs_ld_write_done); EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
...@@ -1219,12 +1223,14 @@ static void ...@@ -1219,12 +1223,14 @@ static void
pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
struct nfs_write_data *data) struct nfs_write_data *data)
{ {
list_splice_tail_init(&data->pages, &desc->pg_list); struct nfs_pgio_header *hdr = data->header;
if (data->req && list_empty(&data->req->wb_list))
nfs_list_add_request(data->req, &desc->pg_list); list_splice_tail_init(&hdr->pages, &desc->pg_list);
if (hdr->req && list_empty(&hdr->req->wb_list))
nfs_list_add_request(hdr->req, &desc->pg_list);
nfs_pageio_reset_write_mds(desc); nfs_pageio_reset_write_mds(desc);
desc->pg_recoalesce = 1; desc->pg_recoalesce = 1;
put_lseg(data->lseg); put_lseg(hdr->lseg);
nfs_writedata_release(data); nfs_writedata_release(data);
} }
...@@ -1234,20 +1240,21 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata, ...@@ -1234,20 +1240,21 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata,
struct pnfs_layout_segment *lseg, struct pnfs_layout_segment *lseg,
int how) int how)
{ {
struct inode *inode = wdata->inode; struct nfs_pgio_header *hdr = wdata->header;
struct inode *inode = hdr->inode;
enum pnfs_try_status trypnfs; enum pnfs_try_status trypnfs;
struct nfs_server *nfss = NFS_SERVER(inode); struct nfs_server *nfss = NFS_SERVER(inode);
wdata->mds_ops = call_ops; hdr->mds_ops = call_ops;
wdata->lseg = get_lseg(lseg); hdr->lseg = get_lseg(lseg);
dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__,
inode->i_ino, wdata->args.count, wdata->args.offset, how); inode->i_ino, wdata->args.count, wdata->args.offset, how);
trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how);
if (trypnfs == PNFS_NOT_ATTEMPTED) { if (trypnfs == PNFS_NOT_ATTEMPTED) {
put_lseg(wdata->lseg); put_lseg(hdr->lseg);
wdata->lseg = NULL; hdr->lseg = NULL;
} else } else
nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); nfs_inc_stats(inode, NFSIOS_PNFS_WRITE);
...@@ -1318,13 +1325,15 @@ static int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *h ...@@ -1318,13 +1325,15 @@ static int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *h
static void pnfs_ld_handle_read_error(struct nfs_read_data *data) static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
{ {
dprintk("pnfs read error = %d\n", data->pnfs_error); struct nfs_pgio_header *hdr = data->header;
if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
dprintk("pnfs read error = %d\n", hdr->pnfs_error);
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
PNFS_LAYOUTRET_ON_ERROR) { PNFS_LAYOUTRET_ON_ERROR) {
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(data->inode)->flags); clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
pnfs_return_layout(data->inode); pnfs_return_layout(hdr->inode);
} }
data->task.tk_status = pnfs_read_done_resend_to_mds(data->inode, &data->pages); data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, &hdr->pages);
} }
/* /*
...@@ -1332,13 +1341,15 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) ...@@ -1332,13 +1341,15 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
*/ */
void pnfs_ld_read_done(struct nfs_read_data *data) void pnfs_ld_read_done(struct nfs_read_data *data)
{ {
if (likely(!data->pnfs_error)) { struct nfs_pgio_header *hdr = data->header;
if (likely(!hdr->pnfs_error)) {
__nfs4_read_done_cb(data); __nfs4_read_done_cb(data);
data->mds_ops->rpc_call_done(&data->task, data); hdr->mds_ops->rpc_call_done(&data->task, data);
} else } else
pnfs_ld_handle_read_error(data); pnfs_ld_handle_read_error(data);
put_lseg(data->lseg); put_lseg(hdr->lseg);
data->mds_ops->rpc_release(data); hdr->mds_ops->rpc_release(data);
} }
EXPORT_SYMBOL_GPL(pnfs_ld_read_done); EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
...@@ -1346,9 +1357,11 @@ static void ...@@ -1346,9 +1357,11 @@ static void
pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
struct nfs_read_data *data) struct nfs_read_data *data)
{ {
list_splice_tail_init(&data->pages, &desc->pg_list); struct nfs_pgio_header *hdr = data->header;
if (data->req && list_empty(&data->req->wb_list))
nfs_list_add_request(data->req, &desc->pg_list); list_splice_tail_init(&hdr->pages, &desc->pg_list);
if (hdr->req && list_empty(&hdr->req->wb_list))
nfs_list_add_request(hdr->req, &desc->pg_list);
nfs_pageio_reset_read_mds(desc); nfs_pageio_reset_read_mds(desc);
desc->pg_recoalesce = 1; desc->pg_recoalesce = 1;
nfs_readdata_release(data); nfs_readdata_release(data);
...@@ -1362,20 +1375,21 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, ...@@ -1362,20 +1375,21 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
struct pnfs_layout_segment *lseg) struct pnfs_layout_segment *lseg)
{ {
struct inode *inode = rdata->inode; struct nfs_pgio_header *hdr = rdata->header;
struct inode *inode = hdr->inode;
struct nfs_server *nfss = NFS_SERVER(inode); struct nfs_server *nfss = NFS_SERVER(inode);
enum pnfs_try_status trypnfs; enum pnfs_try_status trypnfs;
rdata->mds_ops = call_ops; hdr->mds_ops = call_ops;
rdata->lseg = get_lseg(lseg); hdr->lseg = get_lseg(lseg);
dprintk("%s: Reading ino:%lu %u@%llu\n", dprintk("%s: Reading ino:%lu %u@%llu\n",
__func__, inode->i_ino, rdata->args.count, rdata->args.offset); __func__, inode->i_ino, rdata->args.count, rdata->args.offset);
trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata);
if (trypnfs == PNFS_NOT_ATTEMPTED) { if (trypnfs == PNFS_NOT_ATTEMPTED) {
put_lseg(rdata->lseg); put_lseg(hdr->lseg);
rdata->lseg = NULL; hdr->lseg = NULL;
} else { } else {
nfs_inc_stats(inode, NFSIOS_PNFS_READ); nfs_inc_stats(inode, NFSIOS_PNFS_READ);
} }
...@@ -1450,30 +1464,32 @@ EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); ...@@ -1450,30 +1464,32 @@ EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
void void
pnfs_set_layoutcommit(struct nfs_write_data *wdata) pnfs_set_layoutcommit(struct nfs_write_data *wdata)
{ {
struct nfs_inode *nfsi = NFS_I(wdata->inode); struct nfs_pgio_header *hdr = wdata->header;
struct inode *inode = hdr->inode;
struct nfs_inode *nfsi = NFS_I(inode);
loff_t end_pos = wdata->mds_offset + wdata->res.count; loff_t end_pos = wdata->mds_offset + wdata->res.count;
bool mark_as_dirty = false; bool mark_as_dirty = false;
spin_lock(&nfsi->vfs_inode.i_lock); spin_lock(&inode->i_lock);
if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
mark_as_dirty = true; mark_as_dirty = true;
dprintk("%s: Set layoutcommit for inode %lu ", dprintk("%s: Set layoutcommit for inode %lu ",
__func__, wdata->inode->i_ino); __func__, inode->i_ino);
} }
if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) { if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &hdr->lseg->pls_flags)) {
/* references matched in nfs4_layoutcommit_release */ /* references matched in nfs4_layoutcommit_release */
get_lseg(wdata->lseg); get_lseg(hdr->lseg);
} }
if (end_pos > nfsi->layout->plh_lwb) if (end_pos > nfsi->layout->plh_lwb)
nfsi->layout->plh_lwb = end_pos; nfsi->layout->plh_lwb = end_pos;
spin_unlock(&nfsi->vfs_inode.i_lock); spin_unlock(&inode->i_lock);
dprintk("%s: lseg %p end_pos %llu\n", dprintk("%s: lseg %p end_pos %llu\n",
__func__, wdata->lseg, nfsi->layout->plh_lwb); __func__, hdr->lseg, nfsi->layout->plh_lwb);
/* if pnfs_layoutcommit_inode() runs between inode locks, the next one /* if pnfs_layoutcommit_inode() runs between inode locks, the next one
* will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */ * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
if (mark_as_dirty) if (mark_as_dirty)
mark_inode_dirty_sync(wdata->inode); mark_inode_dirty_sync(inode);
} }
EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
......
...@@ -641,12 +641,14 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -641,12 +641,14 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
{ {
struct inode *inode = data->header->inode;
if (nfs_async_handle_expired_key(task)) if (nfs_async_handle_expired_key(task))
return -EAGAIN; return -EAGAIN;
nfs_invalidate_atime(data->inode); nfs_invalidate_atime(inode);
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
nfs_refresh_inode(data->inode, data->res.fattr); nfs_refresh_inode(inode, data->res.fattr);
/* Emulate the eof flag, which isn't normally needed in NFSv2 /* Emulate the eof flag, which isn't normally needed in NFSv2
* as it is guaranteed to always return the file attributes * as it is guaranteed to always return the file attributes
*/ */
...@@ -668,11 +670,13 @@ static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_dat ...@@ -668,11 +670,13 @@ static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_dat
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
{ {
struct inode *inode = data->header->inode;
if (nfs_async_handle_expired_key(task)) if (nfs_async_handle_expired_key(task))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
return 0; return 0;
} }
......
...@@ -35,19 +35,24 @@ static const struct rpc_call_ops nfs_read_full_ops; ...@@ -35,19 +35,24 @@ static const struct rpc_call_ops nfs_read_full_ops;
static struct kmem_cache *nfs_rdata_cachep; static struct kmem_cache *nfs_rdata_cachep;
struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) struct nfs_read_header *nfs_readhdr_alloc(unsigned int pagecount)
{ {
struct nfs_read_data *p; struct nfs_read_header *p;
p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
if (p) { if (p) {
INIT_LIST_HEAD(&p->pages); struct nfs_pgio_header *hdr = &p->header;
p->npages = pagecount; struct nfs_read_data *data = &p->rpc_data;
if (pagecount <= ARRAY_SIZE(p->page_array))
p->pagevec = p->page_array; INIT_LIST_HEAD(&hdr->pages);
INIT_LIST_HEAD(&data->list);
data->npages = pagecount;
data->header = hdr;
if (pagecount <= ARRAY_SIZE(data->page_array))
data->pagevec = data->page_array;
else { else {
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); data->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
if (!p->pagevec) { if (!data->pagevec) {
kmem_cache_free(nfs_rdata_cachep, p); kmem_cache_free(nfs_rdata_cachep, p);
p = NULL; p = NULL;
} }
...@@ -56,17 +61,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) ...@@ -56,17 +61,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
return p; return p;
} }
void nfs_readdata_free(struct nfs_read_data *p) void nfs_readhdr_free(struct nfs_pgio_header *hdr)
{ {
if (p && (p->pagevec != &p->page_array[0])) struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header);
kfree(p->pagevec);
kmem_cache_free(nfs_rdata_cachep, p); kmem_cache_free(nfs_rdata_cachep, rhdr);
} }
void nfs_readdata_release(struct nfs_read_data *rdata) void nfs_readdata_release(struct nfs_read_data *rdata)
{ {
put_nfs_open_context(rdata->args.context); put_nfs_open_context(rdata->args.context);
nfs_readdata_free(rdata); if (rdata->pagevec != rdata->page_array)
kfree(rdata->pagevec);
nfs_readhdr_free(rdata->header);
} }
static static
...@@ -173,13 +180,13 @@ int nfs_initiate_read(struct rpc_clnt *clnt, ...@@ -173,13 +180,13 @@ int nfs_initiate_read(struct rpc_clnt *clnt,
struct nfs_read_data *data, struct nfs_read_data *data,
const struct rpc_call_ops *call_ops) const struct rpc_call_ops *call_ops)
{ {
struct inode *inode = data->inode; struct inode *inode = data->header->inode;
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
struct rpc_task *task; struct rpc_task *task;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_argp = &data->args, .rpc_argp = &data->args,
.rpc_resp = &data->res, .rpc_resp = &data->res,
.rpc_cred = data->cred, .rpc_cred = data->header->cred,
}; };
struct rpc_task_setup task_setup_data = { struct rpc_task_setup task_setup_data = {
.task = &data->task, .task = &data->task,
...@@ -216,11 +223,11 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read); ...@@ -216,11 +223,11 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read);
static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
unsigned int count, unsigned int offset) unsigned int count, unsigned int offset)
{ {
struct inode *inode = req->wb_context->dentry->d_inode; struct inode *inode = data->header->inode;
data->req = req; data->header->req = req;
data->inode = inode; data->header->inode = inode;
data->cred = req->wb_context->cred; data->header->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset; data->args.offset = req_offset(req) + offset;
...@@ -239,7 +246,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, ...@@ -239,7 +246,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
static int nfs_do_read(struct nfs_read_data *data, static int nfs_do_read(struct nfs_read_data *data,
const struct rpc_call_ops *call_ops) const struct rpc_call_ops *call_ops)
{ {
struct inode *inode = data->args.context->dentry->d_inode; struct inode *inode = data->header->inode;
return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops); return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops);
} }
...@@ -293,6 +300,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head ...@@ -293,6 +300,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
{ {
struct nfs_page *req = nfs_list_entry(desc->pg_list.next); struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
struct page *page = req->wb_page; struct page *page = req->wb_page;
struct nfs_read_header *rhdr;
struct nfs_read_data *data; struct nfs_read_data *data;
size_t rsize = desc->pg_bsize, nbytes; size_t rsize = desc->pg_bsize, nbytes;
unsigned int offset; unsigned int offset;
...@@ -306,9 +314,10 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head ...@@ -306,9 +314,10 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
do { do {
size_t len = min(nbytes,rsize); size_t len = min(nbytes,rsize);
data = nfs_readdata_alloc(1); rhdr = nfs_readhdr_alloc(1);
if (!data) if (!rhdr)
goto out_bad; goto out_bad;
data = &rhdr->rpc_data;
data->pagevec[0] = page; data->pagevec[0] = page;
nfs_read_rpcsetup(req, data, len, offset); nfs_read_rpcsetup(req, data, len, offset);
list_add(&data->list, res); list_add(&data->list, res);
...@@ -333,26 +342,28 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head * ...@@ -333,26 +342,28 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *
{ {
struct nfs_page *req; struct nfs_page *req;
struct page **pages; struct page **pages;
struct nfs_read_header *rhdr;
struct nfs_read_data *data; struct nfs_read_data *data;
struct list_head *head = &desc->pg_list; struct list_head *head = &desc->pg_list;
int ret = 0; int ret = 0;
data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, rhdr = nfs_readhdr_alloc(nfs_page_array_len(desc->pg_base,
desc->pg_count)); desc->pg_count));
if (!data) { if (!rhdr) {
nfs_async_read_error(head); nfs_async_read_error(head);
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
data = &rhdr->rpc_data;
pages = data->pagevec; pages = data->pagevec;
while (!list_empty(head)) { while (!list_empty(head)) {
req = nfs_list_entry(head->next); req = nfs_list_entry(head->next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages); nfs_list_add_request(req, &rhdr->header.pages);
*pages++ = req->wb_page; *pages++ = req->wb_page;
} }
req = nfs_list_entry(data->pages.next); req = nfs_list_entry(rhdr->header.pages.next);
nfs_read_rpcsetup(req, data, desc->pg_count, 0); nfs_read_rpcsetup(req, data, desc->pg_count, 0);
list_add(&data->list, res); list_add(&data->list, res);
...@@ -390,20 +401,21 @@ static const struct nfs_pageio_ops nfs_pageio_read_ops = { ...@@ -390,20 +401,21 @@ static const struct nfs_pageio_ops nfs_pageio_read_ops = {
*/ */
int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
{ {
struct inode *inode = data->header->inode;
int status; int status;
dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid,
task->tk_status); task->tk_status);
status = NFS_PROTO(data->inode)->read_done(task, data); status = NFS_PROTO(inode)->read_done(task, data);
if (status != 0) if (status != 0)
return status; return status;
nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count);
if (task->tk_status == -ESTALE) { if (task->tk_status == -ESTALE) {
set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
nfs_mark_for_revalidate(data->inode); nfs_mark_for_revalidate(inode);
} }
return 0; return 0;
} }
...@@ -417,7 +429,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data ...@@ -417,7 +429,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
return; return;
/* This is a short read! */ /* This is a short read! */
nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD);
/* Has the server at least made some progress? */ /* Has the server at least made some progress? */
if (resp->count == 0) if (resp->count == 0)
return; return;
...@@ -449,7 +461,7 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) ...@@ -449,7 +461,7 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata)
static void nfs_readpage_release_partial(void *calldata) static void nfs_readpage_release_partial(void *calldata)
{ {
struct nfs_read_data *data = calldata; struct nfs_read_data *data = calldata;
struct nfs_page *req = data->req; struct nfs_page *req = data->header->req;
struct page *page = req->wb_page; struct page *page = req->wb_page;
int status = data->task.tk_status; int status = data->task.tk_status;
...@@ -461,13 +473,13 @@ static void nfs_readpage_release_partial(void *calldata) ...@@ -461,13 +473,13 @@ static void nfs_readpage_release_partial(void *calldata)
SetPageUptodate(page); SetPageUptodate(page);
nfs_readpage_release(req); nfs_readpage_release(req);
} }
nfs_readdata_release(calldata); nfs_readdata_release(data);
} }
void nfs_read_prepare(struct rpc_task *task, void *calldata) void nfs_read_prepare(struct rpc_task *task, void *calldata)
{ {
struct nfs_read_data *data = calldata; struct nfs_read_data *data = calldata;
NFS_PROTO(data->inode)->read_rpc_prepare(task, data); NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
} }
static const struct rpc_call_ops nfs_read_partial_ops = { static const struct rpc_call_ops nfs_read_partial_ops = {
...@@ -524,9 +536,10 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) ...@@ -524,9 +536,10 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
static void nfs_readpage_release_full(void *calldata) static void nfs_readpage_release_full(void *calldata)
{ {
struct nfs_read_data *data = calldata; struct nfs_read_data *data = calldata;
struct nfs_pgio_header *hdr = data->header;
while (!list_empty(&data->pages)) { while (!list_empty(&hdr->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next); struct nfs_page *req = nfs_list_entry(hdr->pages.next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
nfs_readpage_release(req); nfs_readpage_release(req);
...@@ -685,7 +698,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -685,7 +698,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
int __init nfs_init_readpagecache(void) int __init nfs_init_readpagecache(void)
{ {
nfs_rdata_cachep = kmem_cache_create("nfs_read_data", nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
sizeof(struct nfs_read_data), sizeof(struct nfs_read_header),
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL); NULL);
if (nfs_rdata_cachep == NULL) if (nfs_rdata_cachep == NULL)
......
This diff is collapsed.
...@@ -568,12 +568,6 @@ nfs_have_writebacks(struct inode *inode) ...@@ -568,12 +568,6 @@ nfs_have_writebacks(struct inode *inode)
return NFS_I(inode)->npages != 0; return NFS_I(inode)->npages != 0;
} }
/*
* Allocate nfs_write_data structures
*/
extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages);
extern void nfs_writedata_free(struct nfs_write_data *);
/* /*
* linux/fs/nfs/read.c * linux/fs/nfs/read.c
*/ */
...@@ -584,12 +578,6 @@ extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); ...@@ -584,12 +578,6 @@ extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *);
extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, extern int nfs_readpage_async(struct nfs_open_context *, struct inode *,
struct page *); struct page *);
/*
* Allocate nfs_read_data structures
*/
extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages);
extern void nfs_readdata_free(struct nfs_read_data *);
/* /*
* linux/fs/nfs3proc.c * linux/fs/nfs3proc.c
*/ */
......
...@@ -1168,52 +1168,58 @@ struct nfs_page; ...@@ -1168,52 +1168,58 @@ struct nfs_page;
#define NFS_PAGEVEC_SIZE (8U) #define NFS_PAGEVEC_SIZE (8U)
struct nfs_read_data { struct nfs_read_data {
struct nfs_pgio_header *header;
struct list_head list;
struct rpc_task task; struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
struct nfs_fattr fattr; /* fattr storage */ struct nfs_fattr fattr; /* fattr storage */
struct list_head pages; /* Coalesced read requests */
struct list_head list; /* lists of struct nfs_read_data */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec; struct page **pagevec;
unsigned int npages; /* Max length of pagevec */ unsigned int npages; /* Max length of pagevec */
struct nfs_readargs args; struct nfs_readargs args;
struct nfs_readres res; struct nfs_readres res;
unsigned long timestamp; /* For lease renewal */ unsigned long timestamp; /* For lease renewal */
struct pnfs_layout_segment *lseg;
struct nfs_client *ds_clp; /* pNFS data server */
const struct rpc_call_ops *mds_ops;
int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data); int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);
__u64 mds_offset; __u64 mds_offset;
int pnfs_error;
struct page *page_array[NFS_PAGEVEC_SIZE]; struct page *page_array[NFS_PAGEVEC_SIZE];
struct nfs_client *ds_clp; /* pNFS data server */
};
struct nfs_pgio_header {
struct inode *inode;
struct rpc_cred *cred;
struct list_head pages;
struct nfs_page *req;
struct pnfs_layout_segment *lseg;
const struct rpc_call_ops *mds_ops;
int pnfs_error;
};
struct nfs_read_header {
struct nfs_pgio_header header;
struct nfs_read_data rpc_data;
}; };
struct nfs_direct_req; struct nfs_direct_req;
struct nfs_write_data { struct nfs_write_data {
struct nfs_pgio_header *header;
struct list_head list;
struct rpc_task task; struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct nfs_writeverf verf; struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */
struct list_head list; /* lists of struct nfs_write_data */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec; struct page **pagevec;
unsigned int npages; /* Max length of pagevec */ unsigned int npages; /* Max length of pagevec */
struct nfs_writeargs args; /* argument struct */ struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */ struct nfs_writeres res; /* result struct */
struct pnfs_layout_segment *lseg;
struct nfs_client *ds_clp; /* pNFS data server */
const struct rpc_call_ops *mds_ops;
int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data);
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */ unsigned long timestamp; /* For lease renewal */
#endif int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data);
__u64 mds_offset; /* Filelayout dense stripe */ __u64 mds_offset; /* Filelayout dense stripe */
int pnfs_error;
struct page *page_array[NFS_PAGEVEC_SIZE]; struct page *page_array[NFS_PAGEVEC_SIZE];
struct nfs_client *ds_clp; /* pNFS data server */
};
struct nfs_write_header {
struct nfs_pgio_header header;
struct nfs_write_data rpc_data;
}; };
struct nfs_commit_data { struct nfs_commit_data {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment