diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
| -rw-r--r-- | fs/nfs/pagelist.c | 20 | 
1 files changed, 15 insertions, 5 deletions
| diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 745a612dbe22..0be5050638f7 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -29,8 +29,6 @@  static struct kmem_cache *nfs_page_cachep;  static const struct rpc_call_ops nfs_pgio_common_ops; -static void nfs_free_request(struct nfs_page *); -  static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount)  {  	p->npages = pagecount; @@ -232,20 +230,28 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)  	WARN_ON_ONCE(prev == req);  	if (!prev) { +		/* a head request */  		req->wb_head = req;  		req->wb_this_page = req;  	} else { +		/* a subrequest */  		WARN_ON_ONCE(prev->wb_this_page != prev->wb_head);  		WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags));  		req->wb_head = prev->wb_head;  		req->wb_this_page = prev->wb_this_page;  		prev->wb_this_page = req; +		/* All subrequests take a ref on the head request until +		 * nfs_page_group_destroy is called */ +		kref_get(&req->wb_head->wb_kref); +  		/* grab extra ref if head request has extra ref from  		 * the write/commit path to handle handoff between write  		 * and commit lists */ -		if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) +		if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) { +			set_bit(PG_INODE_REF, &req->wb_flags);  			kref_get(&req->wb_kref); +		}  	}  } @@ -262,6 +268,10 @@ nfs_page_group_destroy(struct kref *kref)  	struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);  	struct nfs_page *tmp, *next; +	/* subrequests must release the ref on the head request */ +	if (req->wb_head != req) +		nfs_release_request(req->wb_head); +  	if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN))  		return; @@ -387,7 +397,7 @@ static void nfs_clear_request(struct nfs_page *req)   *   * Note: Should never be called with the spinlock held!   */ -static void nfs_free_request(struct nfs_page *req) +void nfs_free_request(struct nfs_page *req)  {  	WARN_ON_ONCE(req->wb_this_page != req); @@ -917,7 +927,6 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,  			nfs_pageio_doio(desc);  			if (desc->pg_error < 0)  				return 0; -			desc->pg_moreio = 0;  			if (desc->pg_recoalesce)  				return 0;  			/* retry add_request for this subreq */ @@ -964,6 +973,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)  		desc->pg_count = 0;  		desc->pg_base = 0;  		desc->pg_recoalesce = 0; +		desc->pg_moreio = 0;  		while (!list_empty(&head)) {  			struct nfs_page *req; |