diff options
Diffstat (limited to 'fs/netfs/objects.c')
| -rw-r--r-- | fs/netfs/objects.c | 59 | 
1 files changed, 39 insertions, 20 deletions
diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c index 8acc03a64059..1a4e2ce735ce 100644 --- a/fs/netfs/objects.c +++ b/fs/netfs/objects.c @@ -6,6 +6,8 @@   */  #include <linux/slab.h> +#include <linux/mempool.h> +#include <linux/delay.h>  #include "internal.h"  /* @@ -20,17 +22,22 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,  	struct inode *inode = file ? file_inode(file) : mapping->host;  	struct netfs_inode *ctx = netfs_inode(inode);  	struct netfs_io_request *rreq; +	mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool; +	struct kmem_cache *cache = mempool->pool_data;  	bool is_unbuffered = (origin == NETFS_UNBUFFERED_WRITE ||  			      origin == NETFS_DIO_READ ||  			      origin == NETFS_DIO_WRITE);  	bool cached = !is_unbuffered && netfs_is_cache_enabled(ctx);  	int ret; -	rreq = kzalloc(ctx->ops->io_request_size ?: sizeof(struct netfs_io_request), -		       GFP_KERNEL); -	if (!rreq) -		return ERR_PTR(-ENOMEM); +	for (;;) { +		rreq = mempool_alloc(mempool, GFP_KERNEL); +		if (rreq) +			break; +		msleep(10); +	} +	memset(rreq, 0, kmem_cache_size(cache));  	rreq->start	= start;  	rreq->len	= len;  	rreq->upper_len	= len; @@ -56,7 +63,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,  	if (rreq->netfs_ops->init_request) {  		ret = rreq->netfs_ops->init_request(rreq, file);  		if (ret < 0) { -			kfree(rreq); +			mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);  			return ERR_PTR(ret);  		}  	} @@ -88,6 +95,14 @@ void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)  	}  } +static void netfs_free_request_rcu(struct rcu_head *rcu) +{ +	struct netfs_io_request *rreq = container_of(rcu, struct netfs_io_request, rcu); + +	mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool); +	netfs_stat_d(&netfs_n_rh_rreq); +} +  static void netfs_free_request(struct work_struct *work)  {  	struct netfs_io_request *rreq = @@ -110,8 +125,7 @@ static void netfs_free_request(struct work_struct *work)  		}  		kvfree(rreq->direct_bv);  	} -	kfree_rcu(rreq, rcu); -	netfs_stat_d(&netfs_n_rh_rreq); +	call_rcu(&rreq->rcu, netfs_free_request_rcu);  }  void netfs_put_request(struct netfs_io_request *rreq, bool was_async, @@ -143,20 +157,25 @@ void netfs_put_request(struct netfs_io_request *rreq, bool was_async,  struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq)  {  	struct netfs_io_subrequest *subreq; - -	subreq = kzalloc(rreq->netfs_ops->io_subrequest_size ?: -			 sizeof(struct netfs_io_subrequest), -			 GFP_KERNEL); -	if (subreq) { -		INIT_WORK(&subreq->work, NULL); -		INIT_LIST_HEAD(&subreq->rreq_link); -		refcount_set(&subreq->ref, 2); -		subreq->rreq = rreq; -		subreq->debug_index = atomic_inc_return(&rreq->subreq_counter); -		netfs_get_request(rreq, netfs_rreq_trace_get_subreq); -		netfs_stat(&netfs_n_rh_sreq); +	mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool; +	struct kmem_cache *cache = mempool->pool_data; + +	for (;;) { +		subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool, +				       GFP_KERNEL); +		if (subreq) +			break; +		msleep(10);  	} +	memset(subreq, 0, kmem_cache_size(cache)); +	INIT_WORK(&subreq->work, NULL); +	INIT_LIST_HEAD(&subreq->rreq_link); +	refcount_set(&subreq->ref, 2); +	subreq->rreq = rreq; +	subreq->debug_index = atomic_inc_return(&rreq->subreq_counter); +	netfs_get_request(rreq, netfs_rreq_trace_get_subreq); +	netfs_stat(&netfs_n_rh_sreq);  	return subreq;  } @@ -178,7 +197,7 @@ static void netfs_free_subrequest(struct netfs_io_subrequest *subreq,  	trace_netfs_sreq(subreq, netfs_sreq_trace_free);  	if (rreq->netfs_ops->free_subrequest)  		rreq->netfs_ops->free_subrequest(subreq); -	kfree(subreq); +	mempool_free(subreq, rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool);  	netfs_stat_d(&netfs_n_rh_sreq);  	netfs_put_request(rreq, was_async, netfs_rreq_trace_put_subreq);  }  | 
