diff options
Diffstat (limited to 'net/sunrpc/cache.c')
| -rw-r--r-- | net/sunrpc/cache.c | 55 | 
1 files changed, 31 insertions, 24 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index f3897d10f64..25d58e76601 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -196,9 +196,9 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_update);  static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)  { -	if (!cd->cache_upcall) -		return -EINVAL; -	return cd->cache_upcall(cd, h); +	if (cd->cache_upcall) +		return cd->cache_upcall(cd, h); +	return sunrpc_cache_pipe_upcall(cd, h);  }  static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) @@ -670,13 +670,13 @@ static void cache_revisit_request(struct cache_head *item)  {  	struct cache_deferred_req *dreq;  	struct list_head pending; -	struct hlist_node *lp, *tmp; +	struct hlist_node *tmp;  	int hash = DFR_HASH(item);  	INIT_LIST_HEAD(&pending);  	spin_lock(&cache_defer_lock); -	hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash) +	hlist_for_each_entry_safe(dreq, tmp, &cache_defer_hash[hash], hash)  		if (dreq->item == item) {  			__unhash_deferred_req(dreq);  			list_add(&dreq->recent, &pending); @@ -750,6 +750,18 @@ struct cache_reader {  	int			offset;	/* if non-0, we have a refcnt on next request */  }; +static int cache_request(struct cache_detail *detail, +			       struct cache_request *crq) +{ +	char *bp = crq->buf; +	int len = PAGE_SIZE; + +	detail->cache_request(detail, crq->item, &bp, &len); +	if (len < 0) +		return -EAGAIN; +	return PAGE_SIZE - len; +} +  static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,  			  loff_t *ppos, struct cache_detail *cd)  { @@ -784,6 +796,13 @@ static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,  		rq->readers++;  	spin_unlock(&queue_lock); +	if (rq->len == 0) { +		err = cache_request(cd, rq); +		if (err < 0) +			goto out; +		rq->len = err; +	} +  	if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) {  		err = -EAGAIN;  		spin_lock(&queue_lock); @@ -1140,17 +1159,14 @@ static bool cache_listeners_exist(struct cache_detail *detail)   *   * Each request is at most one page long.   */ -int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h, -		void (*cache_request)(struct cache_detail *, -				      struct cache_head *, -				      char **, -				      int *)) +int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)  {  	char *buf;  	struct cache_request *crq; -	char *bp; -	int len; + +	if (!detail->cache_request) +		return -EINVAL;  	if (!cache_listeners_exist(detail)) {  		warn_no_listener(detail); @@ -1167,19 +1183,10 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,  		return -EAGAIN;  	} -	bp = buf; len = PAGE_SIZE; - -	cache_request(detail, h, &bp, &len); - -	if (len < 0) { -		kfree(buf); -		kfree(crq); -		return -EAGAIN; -	}  	crq->q.reader = 0;  	crq->item = cache_get(h);  	crq->buf = buf; -	crq->len = PAGE_SIZE - len; +	crq->len = 0;  	crq->readers = 0;  	spin_lock(&queue_lock);  	list_add_tail(&crq->q.list, &detail->queue); @@ -1605,7 +1612,7 @@ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)  	if (p == NULL)  		goto out_nomem; -	if (cd->cache_upcall || cd->cache_parse) { +	if (cd->cache_request || cd->cache_parse) {  		p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR,  				     cd->u.procfs.proc_ent,  				     &cache_file_operations_procfs, cd); @@ -1614,7 +1621,7 @@ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)  			goto out_nomem;  	}  	if (cd->cache_show) { -		p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, +		p = proc_create_data("content", S_IFREG|S_IRUSR,  				cd->u.procfs.proc_ent,  				&content_file_operations_procfs, cd);  		cd->u.procfs.content_ent = p;  |