Skip to content

Commit 129e582

Browse files
kinglongmeeJ. Bruce Fields
authored andcommitted
sunrpc: Switch to using hash list instead single list
Switch using list_head for cache_head in cache_detail, it is useful of remove an cache_head entry directly from cache_detail. v8, using hash list, not head list Signed-off-by: Kinglong Mee <[email protected]> Reviewed-by: NeilBrown <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent c8c081b commit 129e582

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

include/linux/sunrpc/cache.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
*
4747
*/
4848
struct cache_head {
49-
struct cache_head * next;
49+
struct hlist_node cache_list;
5050
time_t expiry_time; /* After time time, don't use the data */
5151
time_t last_refresh; /* If CACHE_PENDING, this is when upcall
5252
* was sent, else this is when update was received
@@ -73,7 +73,7 @@ struct cache_detail_pipefs {
7373
struct cache_detail {
7474
struct module * owner;
7575
int hash_size;
76-
struct cache_head ** hash_table;
76+
struct hlist_head * hash_table;
7777
rwlock_t hash_lock;
7878

7979
atomic_t inuse; /* active user-space update or lookup */

net/sunrpc/cache.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static void cache_revisit_request(struct cache_head *item);
4444
static void cache_init(struct cache_head *h)
4545
{
4646
time_t now = seconds_since_boot();
47-
h->next = NULL;
47+
INIT_HLIST_NODE(&h->cache_list);
4848
h->flags = 0;
4949
kref_init(&h->ref);
5050
h->expiry_time = now + CACHE_NEW_EXPIRY;
@@ -54,15 +54,14 @@ static void cache_init(struct cache_head *h)
5454
struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
5555
struct cache_head *key, int hash)
5656
{
57-
struct cache_head **head, **hp;
58-
struct cache_head *new = NULL, *freeme = NULL;
57+
struct cache_head *new = NULL, *freeme = NULL, *tmp = NULL;
58+
struct hlist_head *head;
5959

6060
head = &detail->hash_table[hash];
6161

6262
read_lock(&detail->hash_lock);
6363

64-
for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
65-
struct cache_head *tmp = *hp;
64+
hlist_for_each_entry(tmp, head, cache_list) {
6665
if (detail->match(tmp, key)) {
6766
if (cache_is_expired(detail, tmp))
6867
/* This entry is expired, we will discard it. */
@@ -88,12 +87,10 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
8887
write_lock(&detail->hash_lock);
8988

9089
/* check if entry appeared while we slept */
91-
for (hp=head; *hp != NULL ; hp = &(*hp)->next) {
92-
struct cache_head *tmp = *hp;
90+
hlist_for_each_entry(tmp, head, cache_list) {
9391
if (detail->match(tmp, key)) {
9492
if (cache_is_expired(detail, tmp)) {
95-
*hp = tmp->next;
96-
tmp->next = NULL;
93+
hlist_del_init(&tmp->cache_list);
9794
detail->entries --;
9895
freeme = tmp;
9996
break;
@@ -104,8 +101,8 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
104101
return tmp;
105102
}
106103
}
107-
new->next = *head;
108-
*head = new;
104+
105+
hlist_add_head(&new->cache_list, head);
109106
detail->entries++;
110107
cache_get(new);
111108
write_unlock(&detail->hash_lock);
@@ -143,7 +140,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
143140
* If 'old' is not VALID, we update it directly,
144141
* otherwise we need to replace it
145142
*/
146-
struct cache_head **head;
147143
struct cache_head *tmp;
148144

149145
if (!test_bit(CACHE_VALID, &old->flags)) {
@@ -168,15 +164,13 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
168164
}
169165
cache_init(tmp);
170166
detail->init(tmp, old);
171-
head = &detail->hash_table[hash];
172167

173168
write_lock(&detail->hash_lock);
174169
if (test_bit(CACHE_NEGATIVE, &new->flags))
175170
set_bit(CACHE_NEGATIVE, &tmp->flags);
176171
else
177172
detail->update(tmp, new);
178-
tmp->next = *head;
179-
*head = tmp;
173+
hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]);
180174
detail->entries++;
181175
cache_get(tmp);
182176
cache_fresh_locked(tmp, new->expiry_time);
@@ -416,28 +410,29 @@ static int cache_clean(void)
416410
/* find a non-empty bucket in the table */
417411
while (current_detail &&
418412
current_index < current_detail->hash_size &&
419-
current_detail->hash_table[current_index] == NULL)
413+
hlist_empty(&current_detail->hash_table[current_index]))
420414
current_index++;
421415

422416
/* find a cleanable entry in the bucket and clean it, or set to next bucket */
423417

424418
if (current_detail && current_index < current_detail->hash_size) {
425-
struct cache_head *ch, **cp;
419+
struct cache_head *ch = NULL;
426420
struct cache_detail *d;
421+
struct hlist_head *head;
422+
struct hlist_node *tmp;
427423

428424
write_lock(&current_detail->hash_lock);
429425

430426
/* Ok, now to clean this strand */
431427

432-
cp = & current_detail->hash_table[current_index];
433-
for (ch = *cp ; ch ; cp = & ch->next, ch = *cp) {
428+
head = &current_detail->hash_table[current_index];
429+
hlist_for_each_entry_safe(ch, tmp, head, cache_list) {
434430
if (current_detail->nextcheck > ch->expiry_time)
435431
current_detail->nextcheck = ch->expiry_time+1;
436432
if (!cache_is_expired(current_detail, ch))
437433
continue;
438434

439-
*cp = ch->next;
440-
ch->next = NULL;
435+
hlist_del_init(&ch->cache_list);
441436
current_detail->entries--;
442437
rv = 1;
443438
break;
@@ -1284,19 +1279,20 @@ void *cache_seq_start(struct seq_file *m, loff_t *pos)
12841279
hash = n >> 32;
12851280
entry = n & ((1LL<<32) - 1);
12861281

1287-
for (ch=cd->hash_table[hash]; ch; ch=ch->next)
1282+
hlist_for_each_entry(ch, &cd->hash_table[hash], cache_list)
12881283
if (!entry--)
12891284
return ch;
12901285
n &= ~((1LL<<32) - 1);
12911286
do {
12921287
hash++;
12931288
n += 1LL<<32;
12941289
} while(hash < cd->hash_size &&
1295-
cd->hash_table[hash]==NULL);
1290+
hlist_empty(&cd->hash_table[hash]));
12961291
if (hash >= cd->hash_size)
12971292
return NULL;
12981293
*pos = n+1;
1299-
return cd->hash_table[hash];
1294+
return hlist_entry_safe(cd->hash_table[hash].first,
1295+
struct cache_head, cache_list);
13001296
}
13011297
EXPORT_SYMBOL_GPL(cache_seq_start);
13021298

@@ -1308,23 +1304,25 @@ void *cache_seq_next(struct seq_file *m, void *p, loff_t *pos)
13081304

13091305
if (p == SEQ_START_TOKEN)
13101306
hash = 0;
1311-
else if (ch->next == NULL) {
1307+
else if (ch->cache_list.next == NULL) {
13121308
hash++;
13131309
*pos += 1LL<<32;
13141310
} else {
13151311
++*pos;
1316-
return ch->next;
1312+
return hlist_entry_safe(ch->cache_list.next,
1313+
struct cache_head, cache_list);
13171314
}
13181315
*pos &= ~((1LL<<32) - 1);
13191316
while (hash < cd->hash_size &&
1320-
cd->hash_table[hash] == NULL) {
1317+
hlist_empty(&cd->hash_table[hash])) {
13211318
hash++;
13221319
*pos += 1LL<<32;
13231320
}
13241321
if (hash >= cd->hash_size)
13251322
return NULL;
13261323
++*pos;
1327-
return cd->hash_table[hash];
1324+
return hlist_entry_safe(cd->hash_table[hash].first,
1325+
struct cache_head, cache_list);
13281326
}
13291327
EXPORT_SYMBOL_GPL(cache_seq_next);
13301328

@@ -1666,17 +1664,21 @@ EXPORT_SYMBOL_GPL(cache_unregister_net);
16661664
struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net)
16671665
{
16681666
struct cache_detail *cd;
1667+
int i;
16691668

16701669
cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL);
16711670
if (cd == NULL)
16721671
return ERR_PTR(-ENOMEM);
16731672

1674-
cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *),
1673+
cd->hash_table = kzalloc(cd->hash_size * sizeof(struct hlist_head),
16751674
GFP_KERNEL);
16761675
if (cd->hash_table == NULL) {
16771676
kfree(cd);
16781677
return ERR_PTR(-ENOMEM);
16791678
}
1679+
1680+
for (i = 0; i < cd->hash_size; i++)
1681+
INIT_HLIST_HEAD(&cd->hash_table[i]);
16801682
cd->net = net;
16811683
return cd;
16821684
}

0 commit comments

Comments
 (0)