Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+43 −36
Original line number Original line Diff line number Diff line
@@ -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)
			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)
{
{
	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)
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)
			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)
						 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)
		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)
	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)
	} 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)
{
{
	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)
	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)
{
{
	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 @@ check_page:
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)
	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)
	/* 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 @@ fill_invalid_ext:
			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 @@ fill_invalid_ext:
					__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 @@ fill_invalid_ext:
			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 @@ fill_invalid_ext:
						 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 @@ next_page:
			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 @@ next_page:
								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 @@ next_page:
			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 @@ next_page:
					 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;
		}
		}
+50 −23
Original line number Original line Diff line number Diff line
@@ -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 = {
	.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,
	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,
		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,


		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 @@ out:
	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)
	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)
	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)
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 @@ out_unlock:
	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,
	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,
		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,


		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;
+4 −0
Original line number Original line Diff line number Diff line
@@ -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);
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,
+9 −5
Original line number Original line Diff line number Diff line
@@ -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


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;
}
}


+23 −17
Original line number Original line Diff line number Diff line
@@ -148,6 +148,7 @@ wait_on_recovery:
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,
		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,
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)
	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,
		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)
	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 = {
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)
	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)
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)
		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;
Loading