diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
| -rw-r--r-- | fs/nfs/pagelist.c | 124 | 
1 files changed, 75 insertions, 49 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index e9f39fa5964b..6ef5278326b6 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only  /*   * linux/fs/nfs/pagelist.c   * @@ -16,8 +17,8 @@  #include <linux/nfs.h>  #include <linux/nfs3.h>  #include <linux/nfs4.h> -#include <linux/nfs_page.h>  #include <linux/nfs_fs.h> +#include <linux/nfs_page.h>  #include <linux/nfs_mount.h>  #include <linux/export.h> @@ -47,7 +48,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,  	hdr->req = nfs_list_entry(mirror->pg_list.next);  	hdr->inode = desc->pg_inode; -	hdr->cred = hdr->req->wb_context->cred; +	hdr->cred = nfs_req_openctx(hdr->req)->cred;  	hdr->io_start = req_offset(hdr->req);  	hdr->good_bytes = mirror->pg_count;  	hdr->io_completion = desc->pg_io_completion; @@ -295,25 +296,13 @@ out:  		nfs_release_request(head);  } -/** - * nfs_create_request - Create an NFS read/write request. - * @ctx: open context to use - * @page: page to write - * @last: last nfs request created for this page group or NULL if head - * @offset: starting offset within the page for the write - * @count: number of bytes to read/write - * - * The page must be locked by the caller. This makes sure we never - * create two different requests for the same page. - * User should ensure it is safe to sleep in this function. - */ -struct nfs_page * -nfs_create_request(struct nfs_open_context *ctx, struct page *page, -		   struct nfs_page *last, unsigned int offset, +static struct nfs_page * +__nfs_create_request(struct nfs_lock_context *l_ctx, struct page *page, +		   unsigned int pgbase, unsigned int offset,  		   unsigned int count)  {  	struct nfs_page		*req; -	struct nfs_lock_context *l_ctx; +	struct nfs_open_context *ctx = l_ctx->open_context;  	if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))  		return ERR_PTR(-EBADF); @@ -322,13 +311,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,  	if (req == NULL)  		return ERR_PTR(-ENOMEM); -	/* get lock context early so we can deal with alloc failures */ -	l_ctx = nfs_get_lock_context(ctx); -	if (IS_ERR(l_ctx)) { -		nfs_page_free(req); -		return ERR_CAST(l_ctx); -	}  	req->wb_lock_context = l_ctx; +	refcount_inc(&l_ctx->count);  	atomic_inc(&l_ctx->io_count);  	/* Initialize the request struct. Initially, we assume a @@ -340,15 +324,59 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,  		get_page(page);  	}  	req->wb_offset  = offset; -	req->wb_pgbase	= offset; +	req->wb_pgbase	= pgbase;  	req->wb_bytes   = count; -	req->wb_context = get_nfs_open_context(ctx);  	kref_init(&req->wb_kref); -	nfs_page_group_init(req, last); +	req->wb_nio = 0;  	return req;  }  /** + * nfs_create_request - Create an NFS read/write request. + * @ctx: open context to use + * @page: page to write + * @offset: starting offset within the page for the write + * @count: number of bytes to read/write + * + * The page must be locked by the caller. This makes sure we never + * create two different requests for the same page. + * User should ensure it is safe to sleep in this function. + */ +struct nfs_page * +nfs_create_request(struct nfs_open_context *ctx, struct page *page, +		   unsigned int offset, unsigned int count) +{ +	struct nfs_lock_context *l_ctx = nfs_get_lock_context(ctx); +	struct nfs_page *ret; + +	if (IS_ERR(l_ctx)) +		return ERR_CAST(l_ctx); +	ret = __nfs_create_request(l_ctx, page, offset, offset, count); +	if (!IS_ERR(ret)) +		nfs_page_group_init(ret, NULL); +	nfs_put_lock_context(l_ctx); +	return ret; +} + +static struct nfs_page * +nfs_create_subreq(struct nfs_page *req, struct nfs_page *last, +		  unsigned int pgbase, unsigned int offset, +		  unsigned int count) +{ +	struct nfs_page *ret; + +	ret = __nfs_create_request(req->wb_lock_context, req->wb_page, +			pgbase, offset, count); +	if (!IS_ERR(ret)) { +		nfs_lock_request(ret); +		ret->wb_index = req->wb_index; +		nfs_page_group_init(ret, last); +		ret->wb_nio = req->wb_nio; +	} +	return ret; +} + +/**   * nfs_unlock_request - Unlock request and wake up sleepers.   * @req: pointer to request   */ @@ -386,8 +414,8 @@ void nfs_unlock_and_release_request(struct nfs_page *req)  static void nfs_clear_request(struct nfs_page *req)  {  	struct page *page = req->wb_page; -	struct nfs_open_context *ctx = req->wb_context;  	struct nfs_lock_context *l_ctx = req->wb_lock_context; +	struct nfs_open_context *ctx;  	if (page != NULL) {  		put_page(page); @@ -396,16 +424,13 @@ static void nfs_clear_request(struct nfs_page *req)  	if (l_ctx != NULL) {  		if (atomic_dec_and_test(&l_ctx->io_count)) {  			wake_up_var(&l_ctx->io_count); +			ctx = l_ctx->open_context;  			if (test_bit(NFS_CONTEXT_UNLOCK, &ctx->flags))  				rpc_wake_up(&NFS_SERVER(d_inode(ctx->dentry))->uoc_rpcwaitq);  		}  		nfs_put_lock_context(l_ctx);  		req->wb_lock_context = NULL;  	} -	if (ctx != NULL) { -		put_nfs_open_context(ctx); -		req->wb_context = NULL; -	}  }  /** @@ -550,7 +575,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,  	hdr->args.pgbase = req->wb_pgbase;  	hdr->args.pages  = hdr->page_array.pagevec;  	hdr->args.count  = count; -	hdr->args.context = get_nfs_open_context(req->wb_context); +	hdr->args.context = get_nfs_open_context(nfs_req_openctx(req));  	hdr->args.lock_context = req->wb_lock_context;  	hdr->args.stable  = NFS_UNSTABLE;  	switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { @@ -698,6 +723,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,  	desc->pg_mirrors_dynamic = NULL;  	desc->pg_mirrors = desc->pg_mirrors_static;  	nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize); +	desc->pg_maxretrans = 0;  }  /** @@ -906,9 +932,9 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,  	struct file_lock_context *flctx;  	if (prev) { -		if (!nfs_match_open_context(req->wb_context, prev->wb_context)) +		if (!nfs_match_open_context(nfs_req_openctx(req), nfs_req_openctx(prev)))  			return false; -		flctx = d_inode(req->wb_context->dentry)->i_flctx; +		flctx = d_inode(nfs_req_openctx(req)->dentry)->i_flctx;  		if (flctx != NULL &&  		    !(list_empty_careful(&flctx->flc_posix) &&  		      list_empty_careful(&flctx->flc_flock)) && @@ -957,6 +983,15 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,  			return 0;  		mirror->pg_base = req->wb_pgbase;  	} + +	if (desc->pg_maxretrans && req->wb_nio > desc->pg_maxretrans) { +		if (NFS_SERVER(desc->pg_inode)->flags & NFS_MOUNT_SOFTERR) +			desc->pg_error = -ETIMEDOUT; +		else +			desc->pg_error = -EIO; +		return 0; +	} +  	if (!nfs_can_coalesce_requests(prev, req, desc))  		return 0;  	nfs_list_move_request(req, &mirror->pg_list); @@ -1049,14 +1084,10 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,  		pgbase += subreq->wb_bytes;  		if (bytes_left) { -			subreq = nfs_create_request(req->wb_context, -					req->wb_page, -					subreq, pgbase, bytes_left); +			subreq = nfs_create_subreq(req, subreq, pgbase, +					offset, bytes_left);  			if (IS_ERR(subreq))  				goto err_ptr; -			nfs_lock_request(subreq); -			subreq->wb_offset  = offset; -			subreq->wb_index = req->wb_index;  		}  	} while (bytes_left > 0); @@ -1158,19 +1189,14 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,  			     lastreq = lastreq->wb_this_page)  				; -			dupreq = nfs_create_request(req->wb_context, -					req->wb_page, lastreq, pgbase, bytes); +			dupreq = nfs_create_subreq(req, lastreq, +					pgbase, offset, bytes); +			nfs_page_group_unlock(req);  			if (IS_ERR(dupreq)) { -				nfs_page_group_unlock(req);  				desc->pg_error = PTR_ERR(dupreq);  				goto out_failed;  			} - -			nfs_lock_request(dupreq); -			nfs_page_group_unlock(req); -			dupreq->wb_offset = offset; -			dupreq->wb_index = req->wb_index;  		} else  			dupreq = req;  |