[PATCH 11/12] sunrpc/cache: change deferred-request hash table to use hlist.

NeilBrown
2009-08-04T05:25:26Z

Being a hash table, hlist is the best option.

There is currently some ugliness were we treat "->next == NULL" as
a special case to avoid having to initialise the whole array.
This change nicely gets rid of that case.

Signed-off-by: NeilBrown <neilb@suse.de>
---

include/linux/sunrpc/cache.h | 2 +-
net/sunrpc/cache.c | 30 ++++++++++++------------------
2 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index ad62e8d..4749474 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -120,7 +120,7 @@ struct cache_req {
* delayed awaiting cache-fill
*/
struct cache_deferred_req {
- struct list_head hash; /* on hash chain */
+ struct hlist_node hash; /* on hash chain */
struct list_head recent; /* on fifo */
struct cache_head *item; /* cache item we wait on */
void *owner; /* we might need to discard all defered requests
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index ba2e113..0087b75 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -556,7 +556,7 @@ EXPORT_SYMBOL_GPL(cache_purge);

static DEFINE_SPINLOCK(cache_defer_lock);
static LIST_HEAD(cache_defer_list);
-static struct list_head cache_defer_hash[DFR_HASHSIZE];
+static struct hlist_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;

struct thread_deferred_req {
@@ -600,9 +600,7 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)

list_add(&dreq->recent, &cache_defer_list);

- if (cache_defer_hash[hash].next == NULL)
- INIT_LIST_HEAD(&cache_defer_hash[hash]);
- list_add(&dreq->hash, &cache_defer_hash[hash]);
+ hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);

/* it is in, now maybe clean up */
discard = NULL;
@@ -610,7 +608,7 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
discard = list_entry(cache_defer_list.prev,
struct cache_deferred_req, recent);
list_del_init(&dreq->recent);
- list_del_init(&dreq->hash);
+ hlist_del_init(&dreq->hash);
cache_defer_cnt--;
}
spin_unlock(&cache_defer_lock);
@@ -629,12 +627,12 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
wait_event_interruptible_timeout(
sleeper.wait,
!test_bit(CACHE_PENDING, &item->flags)
- || list_empty(&sleeper.handle.hash),
+ || hlist_unhashed(&sleeper.handle.hash),
req->thread_wait);
spin_lock(&cache_defer_lock);
- if (!list_empty(&sleeper.handle.hash)) {
+ if (!hlist_unhashed(&sleeper.handle.hash)) {
list_del_init(&sleeper.handle.recent);
- list_del_init(&sleeper.handle.hash);
+ hlist_del_init(&sleeper.handle.hash);
cache_defer_cnt--;
}
spin_unlock(&cache_defer_lock);
@@ -655,24 +653,20 @@ static void cache_revisit_request(struct cache_head *item)
struct cache_deferred_req *dreq;
struct list_head pending;

- struct list_head *lp;
+ struct hlist_node *lp, *tmp;
int hash = DFR_HASH(item);

INIT_LIST_HEAD(&pending);
spin_lock(&cache_defer_lock);

- lp = cache_defer_hash[hash].next;
- if (lp) {
- while (lp != &cache_defer_hash[hash]) {
- dreq = list_entry(lp, struct cache_deferred_req, hash);
- lp = lp->next;
+ hlist_for_each_entry_safe(dreq, lp, tmp,
+ &cache_defer_hash[hash], hash)
if (dreq->item == item) {
- list_del_init(&dreq->hash);
+ hlist_del_init(&dreq->hash);
list_move(&dreq->recent, &pending);
cache_defer_cnt--;
}
- }
- }
+
spin_unlock(&cache_defer_lock);

while (!list_empty(&pending)) {
@@ -693,7 +687,7 @@ void cache_clean_deferred(void *owner)

list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
if (dreq->owner == owner) {
- list_del_init(&dreq->hash);
+ hlist_del_init(&dreq->hash);
list_move(&dreq->recent, &pending);
cache_defer_cnt--;
}