This source file includes following definitions.
- lc_try_lock
- lc_create
- lc_free_by_index
- lc_destroy
- lc_reset
- lc_seq_printf_stats
- lc_hash_slot
- __lc_find
- lc_find
- lc_is_used
- lc_del
- lc_prepare_for_change
- lc_unused_element_available
- __lc_get
- lc_get
- lc_get_cumulative
- lc_try_get
- lc_committed
- lc_put
- lc_element_by_index
- lc_index_of
- lc_set
- lc_seq_dump_details
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <linux/module.h>
15 #include <linux/bitops.h>
16 #include <linux/slab.h>
17 #include <linux/string.h>
18 #include <linux/seq_file.h>
19 #include <linux/lru_cache.h>
20
21 MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
22 "Lars Ellenberg <lars@linbit.com>");
23 MODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
24 MODULE_LICENSE("GPL");
25
26
27
28 #define PARANOIA_ENTRY() do { \
29 BUG_ON(!lc); \
30 BUG_ON(!lc->nr_elements); \
31 BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
32 } while (0)
33
34 #define RETURN(x...) do { \
35 clear_bit_unlock(__LC_PARANOIA, &lc->flags); \
36 return x ; } while (0)
37
38
39 #define PARANOIA_LC_ELEMENT(lc, e) do { \
40 struct lru_cache *lc_ = (lc); \
41 struct lc_element *e_ = (e); \
42 unsigned i = e_->lc_index; \
43 BUG_ON(i >= lc_->nr_elements); \
44 BUG_ON(lc_->lc_element[i] != e_); } while (0)
45
46
47
48
49
50
51
52
53
54
55 int lc_try_lock(struct lru_cache *lc)
56 {
57 unsigned long val;
58 do {
59 val = cmpxchg(&lc->flags, 0, LC_LOCKED);
60 } while (unlikely (val == LC_PARANOIA));
61
62 return 0 == val;
63 #if 0
64
65
66 unsigned long old, new, val;
67 do {
68 old = lc->flags & LC_PARANOIA;
69 new = old | LC_LOCKED;
70 val = cmpxchg(&lc->flags, old, new);
71 } while (unlikely (val == (old ^ LC_PARANOIA)));
72 return old == val;
73 #endif
74 }
75
76
77
78
79
80
81
82
83
84
85
86
87 struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
88 unsigned max_pending_changes,
89 unsigned e_count, size_t e_size, size_t e_off)
90 {
91 struct hlist_head *slot = NULL;
92 struct lc_element **element = NULL;
93 struct lru_cache *lc;
94 struct lc_element *e;
95 unsigned cache_obj_size = kmem_cache_size(cache);
96 unsigned i;
97
98 WARN_ON(cache_obj_size < e_size);
99 if (cache_obj_size < e_size)
100 return NULL;
101
102
103
104 if (e_count > LC_MAX_ACTIVE)
105 return NULL;
106
107 slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
108 if (!slot)
109 goto out_fail;
110 element = kcalloc(e_count, sizeof(struct lc_element *), GFP_KERNEL);
111 if (!element)
112 goto out_fail;
113
114 lc = kzalloc(sizeof(*lc), GFP_KERNEL);
115 if (!lc)
116 goto out_fail;
117
118 INIT_LIST_HEAD(&lc->in_use);
119 INIT_LIST_HEAD(&lc->lru);
120 INIT_LIST_HEAD(&lc->free);
121 INIT_LIST_HEAD(&lc->to_be_changed);
122
123 lc->name = name;
124 lc->element_size = e_size;
125 lc->element_off = e_off;
126 lc->nr_elements = e_count;
127 lc->max_pending_changes = max_pending_changes;
128 lc->lc_cache = cache;
129 lc->lc_element = element;
130 lc->lc_slot = slot;
131
132
133 for (i = 0; i < e_count; i++) {
134 void *p = kmem_cache_alloc(cache, GFP_KERNEL);
135 if (!p)
136 break;
137 memset(p, 0, lc->element_size);
138 e = p + e_off;
139 e->lc_index = i;
140 e->lc_number = LC_FREE;
141 e->lc_new_number = LC_FREE;
142 list_add(&e->list, &lc->free);
143 element[i] = e;
144 }
145 if (i == e_count)
146 return lc;
147
148
149 for (i--; i; i--) {
150 void *p = element[i];
151 kmem_cache_free(cache, p - e_off);
152 }
153 kfree(lc);
154 out_fail:
155 kfree(element);
156 kfree(slot);
157 return NULL;
158 }
159
160 static void lc_free_by_index(struct lru_cache *lc, unsigned i)
161 {
162 void *p = lc->lc_element[i];
163 WARN_ON(!p);
164 if (p) {
165 p -= lc->element_off;
166 kmem_cache_free(lc->lc_cache, p);
167 }
168 }
169
170
171
172
173
174 void lc_destroy(struct lru_cache *lc)
175 {
176 unsigned i;
177 if (!lc)
178 return;
179 for (i = 0; i < lc->nr_elements; i++)
180 lc_free_by_index(lc, i);
181 kfree(lc->lc_element);
182 kfree(lc->lc_slot);
183 kfree(lc);
184 }
185
186
187
188
189
190
191
192
193 void lc_reset(struct lru_cache *lc)
194 {
195 unsigned i;
196
197 INIT_LIST_HEAD(&lc->in_use);
198 INIT_LIST_HEAD(&lc->lru);
199 INIT_LIST_HEAD(&lc->free);
200 INIT_LIST_HEAD(&lc->to_be_changed);
201 lc->used = 0;
202 lc->hits = 0;
203 lc->misses = 0;
204 lc->starving = 0;
205 lc->locked = 0;
206 lc->changed = 0;
207 lc->pending_changes = 0;
208 lc->flags = 0;
209 memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
210
211 for (i = 0; i < lc->nr_elements; i++) {
212 struct lc_element *e = lc->lc_element[i];
213 void *p = e;
214 p -= lc->element_off;
215 memset(p, 0, lc->element_size);
216
217 e->lc_index = i;
218 e->lc_number = LC_FREE;
219 e->lc_new_number = LC_FREE;
220 list_add(&e->list, &lc->free);
221 }
222 }
223
224
225
226
227
228
229 void lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
230 {
231
232
233
234
235
236
237
238 seq_printf(seq, "\t%s: used:%u/%u hits:%lu misses:%lu starving:%lu locked:%lu changed:%lu\n",
239 lc->name, lc->used, lc->nr_elements,
240 lc->hits, lc->misses, lc->starving, lc->locked, lc->changed);
241 }
242
243 static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
244 {
245 return lc->lc_slot + (enr % lc->nr_elements);
246 }
247
248
249 static struct lc_element *__lc_find(struct lru_cache *lc, unsigned int enr,
250 bool include_changing)
251 {
252 struct lc_element *e;
253
254 BUG_ON(!lc);
255 BUG_ON(!lc->nr_elements);
256 hlist_for_each_entry(e, lc_hash_slot(lc, enr), colision) {
257
258
259
260 if (e->lc_new_number != enr)
261 continue;
262 if (e->lc_new_number == e->lc_number || include_changing)
263 return e;
264 break;
265 }
266 return NULL;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
281 {
282 return __lc_find(lc, enr, 0);
283 }
284
285
286
287
288
289
290
291
292
293
294
295 bool lc_is_used(struct lru_cache *lc, unsigned int enr)
296 {
297 struct lc_element *e = __lc_find(lc, enr, 1);
298 return e && e->refcnt;
299 }
300
301
302
303
304
305
306
307
308
309 void lc_del(struct lru_cache *lc, struct lc_element *e)
310 {
311 PARANOIA_ENTRY();
312 PARANOIA_LC_ELEMENT(lc, e);
313 BUG_ON(e->refcnt);
314
315 e->lc_number = e->lc_new_number = LC_FREE;
316 hlist_del_init(&e->colision);
317 list_move(&e->list, &lc->free);
318 RETURN();
319 }
320
321 static struct lc_element *lc_prepare_for_change(struct lru_cache *lc, unsigned new_number)
322 {
323 struct list_head *n;
324 struct lc_element *e;
325
326 if (!list_empty(&lc->free))
327 n = lc->free.next;
328 else if (!list_empty(&lc->lru))
329 n = lc->lru.prev;
330 else
331 return NULL;
332
333 e = list_entry(n, struct lc_element, list);
334 PARANOIA_LC_ELEMENT(lc, e);
335
336 e->lc_new_number = new_number;
337 if (!hlist_unhashed(&e->colision))
338 __hlist_del(&e->colision);
339 hlist_add_head(&e->colision, lc_hash_slot(lc, new_number));
340 list_move(&e->list, &lc->to_be_changed);
341
342 return e;
343 }
344
345 static int lc_unused_element_available(struct lru_cache *lc)
346 {
347 if (!list_empty(&lc->free))
348 return 1;
349 if (!list_empty(&lc->lru))
350 return 1;
351
352 return 0;
353 }
354
355
356 enum {
357 LC_GET_MAY_CHANGE = 1,
358 LC_GET_MAY_USE_UNCOMMITTED = 2,
359 };
360
361 static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsigned int flags)
362 {
363 struct lc_element *e;
364
365 PARANOIA_ENTRY();
366 if (lc->flags & LC_STARVING) {
367 ++lc->starving;
368 RETURN(NULL);
369 }
370
371 e = __lc_find(lc, enr, 1);
372
373
374
375
376 if (e) {
377 if (e->lc_new_number != e->lc_number) {
378
379
380
381
382 if (!(flags & LC_GET_MAY_USE_UNCOMMITTED))
383 RETURN(NULL);
384
385
386 ++e->refcnt;
387 ++lc->hits;
388 RETURN(e);
389 }
390
391 ++lc->hits;
392 if (e->refcnt++ == 0)
393 lc->used++;
394 list_move(&e->list, &lc->in_use);
395 RETURN(e);
396 }
397
398
399 ++lc->misses;
400 if (!(flags & LC_GET_MAY_CHANGE))
401 RETURN(NULL);
402
403
404
405 test_and_set_bit(__LC_DIRTY, &lc->flags);
406
407
408
409
410 if (test_bit(__LC_LOCKED, &lc->flags)) {
411 ++lc->locked;
412 RETURN(NULL);
413 }
414
415
416
417
418 if (!lc_unused_element_available(lc)) {
419 __set_bit(__LC_STARVING, &lc->flags);
420 RETURN(NULL);
421 }
422
423
424
425
426 if (lc->pending_changes >= lc->max_pending_changes)
427 RETURN(NULL);
428
429 e = lc_prepare_for_change(lc, enr);
430 BUG_ON(!e);
431
432 clear_bit(__LC_STARVING, &lc->flags);
433 BUG_ON(++e->refcnt != 1);
434 lc->used++;
435 lc->pending_changes++;
436
437 RETURN(e);
438 }
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
481 {
482 return __lc_get(lc, enr, LC_GET_MAY_CHANGE);
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500 struct lc_element *lc_get_cumulative(struct lru_cache *lc, unsigned int enr)
501 {
502 return __lc_get(lc, enr, LC_GET_MAY_CHANGE|LC_GET_MAY_USE_UNCOMMITTED);
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521 struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
522 {
523 return __lc_get(lc, enr, 0);
524 }
525
526
527
528
529
530
531
532
533
534 void lc_committed(struct lru_cache *lc)
535 {
536 struct lc_element *e, *tmp;
537
538 PARANOIA_ENTRY();
539 list_for_each_entry_safe(e, tmp, &lc->to_be_changed, list) {
540
541 ++lc->changed;
542 e->lc_number = e->lc_new_number;
543 list_move(&e->list, &lc->in_use);
544 }
545 lc->pending_changes = 0;
546 RETURN();
547 }
548
549
550
551
552
553
554
555
556
557
558
559 unsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
560 {
561 PARANOIA_ENTRY();
562 PARANOIA_LC_ELEMENT(lc, e);
563 BUG_ON(e->refcnt == 0);
564 BUG_ON(e->lc_number != e->lc_new_number);
565 if (--e->refcnt == 0) {
566
567 list_move(&e->list, &lc->lru);
568 lc->used--;
569 clear_bit_unlock(__LC_STARVING, &lc->flags);
570 }
571 RETURN(e->refcnt);
572 }
573
574
575
576
577
578
579 struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
580 {
581 BUG_ON(i >= lc->nr_elements);
582 BUG_ON(lc->lc_element[i] == NULL);
583 BUG_ON(lc->lc_element[i]->lc_index != i);
584 return lc->lc_element[i];
585 }
586
587
588
589
590
591
592 unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
593 {
594 PARANOIA_LC_ELEMENT(lc, e);
595 return e->lc_index;
596 }
597
598
599
600
601
602
603
604
605
606 void lc_set(struct lru_cache *lc, unsigned int enr, int index)
607 {
608 struct lc_element *e;
609 struct list_head *lh;
610
611 if (index < 0 || index >= lc->nr_elements)
612 return;
613
614 e = lc_element_by_index(lc, index);
615 BUG_ON(e->lc_number != e->lc_new_number);
616 BUG_ON(e->refcnt != 0);
617
618 e->lc_number = e->lc_new_number = enr;
619 hlist_del_init(&e->colision);
620 if (enr == LC_FREE)
621 lh = &lc->free;
622 else {
623 hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
624 lh = &lc->lru;
625 }
626 list_move(&e->list, lh);
627 }
628
629
630
631
632
633
634
635
636
637
638 void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
639 void (*detail) (struct seq_file *, struct lc_element *))
640 {
641 unsigned int nr_elements = lc->nr_elements;
642 struct lc_element *e;
643 int i;
644
645 seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext);
646 for (i = 0; i < nr_elements; i++) {
647 e = lc_element_by_index(lc, i);
648 if (e->lc_number != e->lc_new_number)
649 seq_printf(seq, "\t%5d: %6d %8d %6d ",
650 i, e->lc_number, e->lc_new_number, e->refcnt);
651 else
652 seq_printf(seq, "\t%5d: %6d %-8s %6d ",
653 i, e->lc_number, "-\"-", e->refcnt);
654 if (detail)
655 detail(seq, e);
656 seq_putc(seq, '\n');
657 }
658 }
659
660 EXPORT_SYMBOL(lc_create);
661 EXPORT_SYMBOL(lc_reset);
662 EXPORT_SYMBOL(lc_destroy);
663 EXPORT_SYMBOL(lc_set);
664 EXPORT_SYMBOL(lc_del);
665 EXPORT_SYMBOL(lc_try_get);
666 EXPORT_SYMBOL(lc_find);
667 EXPORT_SYMBOL(lc_get);
668 EXPORT_SYMBOL(lc_put);
669 EXPORT_SYMBOL(lc_committed);
670 EXPORT_SYMBOL(lc_element_by_index);
671 EXPORT_SYMBOL(lc_index_of);
672 EXPORT_SYMBOL(lc_seq_printf_stats);
673 EXPORT_SYMBOL(lc_seq_dump_details);
674 EXPORT_SYMBOL(lc_try_lock);
675 EXPORT_SYMBOL(lc_is_used);
676 EXPORT_SYMBOL(lc_get_cumulative);