diff options
Diffstat (limited to 'net/sunrpc/cache.c')
| -rw-r--r-- | net/sunrpc/cache.c | 101 | 
1 files changed, 52 insertions, 49 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 80fe5c86efd1..a72de074172d 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -50,12 +50,6 @@ static void cache_init(struct cache_head *h)  	h->last_refresh = now;  } -static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) -{ -	return  (h->expiry_time < seconds_since_boot()) || -		(detail->flush_time > h->last_refresh); -} -  struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,  				       struct cache_head *key, int hash)  { @@ -201,7 +195,7 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)  	return sunrpc_cache_pipe_upcall(cd, h);  } -static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) +static inline int cache_is_valid(struct cache_head *h)  {  	if (!test_bit(CACHE_VALID, &h->flags))  		return -EAGAIN; @@ -227,16 +221,15 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h  	int rv;  	write_lock(&detail->hash_lock); -	rv = cache_is_valid(detail, h); -	if (rv != -EAGAIN) { -		write_unlock(&detail->hash_lock); -		return rv; +	rv = cache_is_valid(h); +	if (rv == -EAGAIN) { +		set_bit(CACHE_NEGATIVE, &h->flags); +		cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); +		rv = -ENOENT;  	} -	set_bit(CACHE_NEGATIVE, &h->flags); -	cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);  	write_unlock(&detail->hash_lock);  	cache_fresh_unlocked(h, detail); -	return -ENOENT; +	return rv;  }  /* @@ -260,7 +253,7 @@ int cache_check(struct cache_detail *detail,  	long refresh_age, age;  	/* First decide return status as best we can */ -	rv = cache_is_valid(detail, h); +	rv = cache_is_valid(h);  	/* now see if we want to start an upcall */  	refresh_age = (h->expiry_time - h->last_refresh); @@ -269,19 +262,17 @@ int cache_check(struct cache_detail *detail,  	if (rqstp == NULL) {  		if (rv == -EAGAIN)  			rv = -ENOENT; -	} else if (rv == -EAGAIN || age > refresh_age/2) { +	} else if (rv == -EAGAIN || +		   (h->expiry_time != 0 && age > refresh_age/2)) {  		dprintk("RPC:       Want update, refage=%ld, age=%ld\n",  				refresh_age, age);  		if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {  			switch (cache_make_upcall(detail, h)) {  			case -EINVAL: -				clear_bit(CACHE_PENDING, &h->flags); -				cache_revisit_request(h);  				rv = try_to_negate_entry(detail, h);  				break;  			case -EAGAIN: -				clear_bit(CACHE_PENDING, &h->flags); -				cache_revisit_request(h); +				cache_fresh_unlocked(h, detail);  				break;  			}  		} @@ -293,7 +284,7 @@ int cache_check(struct cache_detail *detail,  			 * Request was not deferred; handle it as best  			 * we can ourselves:  			 */ -			rv = cache_is_valid(detail, h); +			rv = cache_is_valid(h);  			if (rv == -EAGAIN)  				rv = -ETIMEDOUT;  		} @@ -310,7 +301,7 @@ EXPORT_SYMBOL_GPL(cache_check);   * a current pointer into that list and into the table   * for that entry.   * - * Each time clean_cache is called it finds the next non-empty entry + * Each time cache_clean is called it finds the next non-empty entry   * in the current table and walks the list in that entry   * looking for entries that can be removed.   * @@ -457,9 +448,8 @@ static int cache_clean(void)  			current_index ++;  		spin_unlock(&cache_list_lock);  		if (ch) { -			if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) -				cache_dequeue(current_detail, ch); -			cache_revisit_request(ch); +			set_bit(CACHE_CLEANED, &ch->flags); +			cache_fresh_unlocked(ch, d);  			cache_put(ch, d);  		}  	} else @@ -1036,23 +1026,32 @@ static int cache_release(struct inode *inode, struct file *filp,  static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch)  { -	struct cache_queue *cq; +	struct cache_queue *cq, *tmp; +	struct cache_request *cr; +	struct list_head dequeued; + +	INIT_LIST_HEAD(&dequeued);  	spin_lock(&queue_lock); -	list_for_each_entry(cq, &detail->queue, list) +	list_for_each_entry_safe(cq, tmp, &detail->queue, list)  		if (!cq->reader) { -			struct cache_request *cr = container_of(cq, struct cache_request, q); +			cr = container_of(cq, struct cache_request, q);  			if (cr->item != ch)  				continue; +			if (test_bit(CACHE_PENDING, &ch->flags)) +				/* Lost a race and it is pending again */ +				break;  			if (cr->readers != 0)  				continue; -			list_del(&cr->q.list); -			spin_unlock(&queue_lock); -			cache_put(cr->item, detail); -			kfree(cr->buf); -			kfree(cr); -			return; +			list_move(&cr->q.list, &dequeued);  		}  	spin_unlock(&queue_lock); +	while (!list_empty(&dequeued)) { +		cr = list_entry(dequeued.next, struct cache_request, q.list); +		list_del(&cr->q.list); +		cache_put(cr->item, detail); +		kfree(cr->buf); +		kfree(cr); +	}  }  /* @@ -1166,6 +1165,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)  	char *buf;  	struct cache_request *crq; +	int ret = 0;  	if (!detail->cache_request)  		return -EINVAL; @@ -1174,6 +1174,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)  		warn_no_listener(detail);  		return -EINVAL;  	} +	if (test_bit(CACHE_CLEANED, &h->flags)) +		/* Too late to make an upcall */ +		return -EAGAIN;  	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);  	if (!buf) @@ -1191,10 +1194,18 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)  	crq->len = 0;  	crq->readers = 0;  	spin_lock(&queue_lock); -	list_add_tail(&crq->q.list, &detail->queue); +	if (test_bit(CACHE_PENDING, &h->flags)) +		list_add_tail(&crq->q.list, &detail->queue); +	else +		/* Lost a race, no longer PENDING, so don't enqueue */ +		ret = -EAGAIN;  	spin_unlock(&queue_lock);  	wake_up(&queue_wait); -	return 0; +	if (ret == -EAGAIN) { +		kfree(buf); +		kfree(crq); +	} +	return ret;  }  EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); @@ -1812,19 +1823,11 @@ int sunrpc_cache_register_pipefs(struct dentry *parent,  				 const char *name, umode_t umode,  				 struct cache_detail *cd)  { -	struct qstr q; -	struct dentry *dir; -	int ret = 0; - -	q.name = name; -	q.len = strlen(name); -	q.hash = full_name_hash(q.name, q.len); -	dir = rpc_create_cache_dir(parent, &q, umode, cd); -	if (!IS_ERR(dir)) -		cd->u.pipefs.dir = dir; -	else -		ret = PTR_ERR(dir); -	return ret; +	struct dentry *dir = rpc_create_cache_dir(parent, name, umode, cd); +	if (IS_ERR(dir)) +		return PTR_ERR(dir); +	cd->u.pipefs.dir = dir; +	return 0;  }  EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);  | 
