0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/bitops.h>
0016 #include <linux/slab.h>
0017 #include <linux/string.h> /* for memset */
0018 #include <linux/seq_file.h> /* for seq_printf */
0019 #include <linux/lru_cache.h>
0020
0021 MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
0022 "Lars Ellenberg <lars@linbit.com>");
0023 MODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
0024 MODULE_LICENSE("GPL");
0025
0026
0027
0028 #define PARANOIA_ENTRY() do { \
0029 BUG_ON(!lc); \
0030 BUG_ON(!lc->nr_elements); \
0031 BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
0032 } while (0)
0033
0034 #define RETURN(x...) do { \
0035 clear_bit_unlock(__LC_PARANOIA, &lc->flags); \
0036 return x ; } while (0)
0037
0038
0039 #define PARANOIA_LC_ELEMENT(lc, e) do { \
0040 struct lru_cache *lc_ = (lc); \
0041 struct lc_element *e_ = (e); \
0042 unsigned i = e_->lc_index; \
0043 BUG_ON(i >= lc_->nr_elements); \
0044 BUG_ON(lc_->lc_element[i] != e_); } while (0)
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 int lc_try_lock(struct lru_cache *lc)
0056 {
0057 unsigned long val;
0058 do {
0059 val = cmpxchg(&lc->flags, 0, LC_LOCKED);
0060 } while (unlikely (val == LC_PARANOIA));
0061
0062 return 0 == val;
0063 #if 0
0064
0065
0066 unsigned long old, new, val;
0067 do {
0068 old = lc->flags & LC_PARANOIA;
0069 new = old | LC_LOCKED;
0070 val = cmpxchg(&lc->flags, old, new);
0071 } while (unlikely (val == (old ^ LC_PARANOIA)));
0072 return old == val;
0073 #endif
0074 }
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
0089 unsigned max_pending_changes,
0090 unsigned e_count, size_t e_size, size_t e_off)
0091 {
0092 struct hlist_head *slot = NULL;
0093 struct lc_element **element = NULL;
0094 struct lru_cache *lc;
0095 struct lc_element *e;
0096 unsigned cache_obj_size = kmem_cache_size(cache);
0097 unsigned i;
0098
0099 WARN_ON(cache_obj_size < e_size);
0100 if (cache_obj_size < e_size)
0101 return NULL;
0102
0103
0104
0105 if (e_count > LC_MAX_ACTIVE)
0106 return NULL;
0107
0108 slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
0109 if (!slot)
0110 goto out_fail;
0111 element = kcalloc(e_count, sizeof(struct lc_element *), GFP_KERNEL);
0112 if (!element)
0113 goto out_fail;
0114
0115 lc = kzalloc(sizeof(*lc), GFP_KERNEL);
0116 if (!lc)
0117 goto out_fail;
0118
0119 INIT_LIST_HEAD(&lc->in_use);
0120 INIT_LIST_HEAD(&lc->lru);
0121 INIT_LIST_HEAD(&lc->free);
0122 INIT_LIST_HEAD(&lc->to_be_changed);
0123
0124 lc->name = name;
0125 lc->element_size = e_size;
0126 lc->element_off = e_off;
0127 lc->nr_elements = e_count;
0128 lc->max_pending_changes = max_pending_changes;
0129 lc->lc_cache = cache;
0130 lc->lc_element = element;
0131 lc->lc_slot = slot;
0132
0133
0134 for (i = 0; i < e_count; i++) {
0135 void *p = kmem_cache_alloc(cache, GFP_KERNEL);
0136 if (!p)
0137 break;
0138 memset(p, 0, lc->element_size);
0139 e = p + e_off;
0140 e->lc_index = i;
0141 e->lc_number = LC_FREE;
0142 e->lc_new_number = LC_FREE;
0143 list_add(&e->list, &lc->free);
0144 element[i] = e;
0145 }
0146 if (i == e_count)
0147 return lc;
0148
0149
0150 while (i) {
0151 void *p = element[--i];
0152 kmem_cache_free(cache, p - e_off);
0153 }
0154 kfree(lc);
0155 out_fail:
0156 kfree(element);
0157 kfree(slot);
0158 return NULL;
0159 }
0160
0161 static void lc_free_by_index(struct lru_cache *lc, unsigned i)
0162 {
0163 void *p = lc->lc_element[i];
0164 WARN_ON(!p);
0165 if (p) {
0166 p -= lc->element_off;
0167 kmem_cache_free(lc->lc_cache, p);
0168 }
0169 }
0170
0171
0172
0173
0174
0175 void lc_destroy(struct lru_cache *lc)
0176 {
0177 unsigned i;
0178 if (!lc)
0179 return;
0180 for (i = 0; i < lc->nr_elements; i++)
0181 lc_free_by_index(lc, i);
0182 kfree(lc->lc_element);
0183 kfree(lc->lc_slot);
0184 kfree(lc);
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194 void lc_reset(struct lru_cache *lc)
0195 {
0196 unsigned i;
0197
0198 INIT_LIST_HEAD(&lc->in_use);
0199 INIT_LIST_HEAD(&lc->lru);
0200 INIT_LIST_HEAD(&lc->free);
0201 INIT_LIST_HEAD(&lc->to_be_changed);
0202 lc->used = 0;
0203 lc->hits = 0;
0204 lc->misses = 0;
0205 lc->starving = 0;
0206 lc->locked = 0;
0207 lc->changed = 0;
0208 lc->pending_changes = 0;
0209 lc->flags = 0;
0210 memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
0211
0212 for (i = 0; i < lc->nr_elements; i++) {
0213 struct lc_element *e = lc->lc_element[i];
0214 void *p = e;
0215 p -= lc->element_off;
0216 memset(p, 0, lc->element_size);
0217
0218 e->lc_index = i;
0219 e->lc_number = LC_FREE;
0220 e->lc_new_number = LC_FREE;
0221 list_add(&e->list, &lc->free);
0222 }
0223 }
0224
0225
0226
0227
0228
0229
0230 void lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
0231 {
0232
0233
0234
0235
0236
0237
0238
0239 seq_printf(seq, "\t%s: used:%u/%u hits:%lu misses:%lu starving:%lu locked:%lu changed:%lu\n",
0240 lc->name, lc->used, lc->nr_elements,
0241 lc->hits, lc->misses, lc->starving, lc->locked, lc->changed);
0242 }
0243
0244 static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
0245 {
0246 return lc->lc_slot + (enr % lc->nr_elements);
0247 }
0248
0249
0250 static struct lc_element *__lc_find(struct lru_cache *lc, unsigned int enr,
0251 bool include_changing)
0252 {
0253 struct lc_element *e;
0254
0255 BUG_ON(!lc);
0256 BUG_ON(!lc->nr_elements);
0257 hlist_for_each_entry(e, lc_hash_slot(lc, enr), colision) {
0258
0259
0260
0261 if (e->lc_new_number != enr)
0262 continue;
0263 if (e->lc_new_number == e->lc_number || include_changing)
0264 return e;
0265 break;
0266 }
0267 return NULL;
0268 }
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281 struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
0282 {
0283 return __lc_find(lc, enr, 0);
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 bool lc_is_used(struct lru_cache *lc, unsigned int enr)
0297 {
0298 struct lc_element *e = __lc_find(lc, enr, 1);
0299 return e && e->refcnt;
0300 }
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 void lc_del(struct lru_cache *lc, struct lc_element *e)
0311 {
0312 PARANOIA_ENTRY();
0313 PARANOIA_LC_ELEMENT(lc, e);
0314 BUG_ON(e->refcnt);
0315
0316 e->lc_number = e->lc_new_number = LC_FREE;
0317 hlist_del_init(&e->colision);
0318 list_move(&e->list, &lc->free);
0319 RETURN();
0320 }
0321
0322 static struct lc_element *lc_prepare_for_change(struct lru_cache *lc, unsigned new_number)
0323 {
0324 struct list_head *n;
0325 struct lc_element *e;
0326
0327 if (!list_empty(&lc->free))
0328 n = lc->free.next;
0329 else if (!list_empty(&lc->lru))
0330 n = lc->lru.prev;
0331 else
0332 return NULL;
0333
0334 e = list_entry(n, struct lc_element, list);
0335 PARANOIA_LC_ELEMENT(lc, e);
0336
0337 e->lc_new_number = new_number;
0338 if (!hlist_unhashed(&e->colision))
0339 __hlist_del(&e->colision);
0340 hlist_add_head(&e->colision, lc_hash_slot(lc, new_number));
0341 list_move(&e->list, &lc->to_be_changed);
0342
0343 return e;
0344 }
0345
0346 static int lc_unused_element_available(struct lru_cache *lc)
0347 {
0348 if (!list_empty(&lc->free))
0349 return 1;
0350 if (!list_empty(&lc->lru))
0351 return 1;
0352
0353 return 0;
0354 }
0355
0356
0357 enum {
0358 LC_GET_MAY_CHANGE = 1,
0359 LC_GET_MAY_USE_UNCOMMITTED = 2,
0360 };
0361
0362 static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsigned int flags)
0363 {
0364 struct lc_element *e;
0365
0366 PARANOIA_ENTRY();
0367 if (lc->flags & LC_STARVING) {
0368 ++lc->starving;
0369 RETURN(NULL);
0370 }
0371
0372 e = __lc_find(lc, enr, 1);
0373
0374
0375
0376
0377 if (e) {
0378 if (e->lc_new_number != e->lc_number) {
0379
0380
0381
0382
0383 if (!(flags & LC_GET_MAY_USE_UNCOMMITTED))
0384 RETURN(NULL);
0385
0386
0387 ++e->refcnt;
0388 ++lc->hits;
0389 RETURN(e);
0390 }
0391
0392 ++lc->hits;
0393 if (e->refcnt++ == 0)
0394 lc->used++;
0395 list_move(&e->list, &lc->in_use);
0396 RETURN(e);
0397 }
0398
0399
0400 ++lc->misses;
0401 if (!(flags & LC_GET_MAY_CHANGE))
0402 RETURN(NULL);
0403
0404
0405
0406 test_and_set_bit(__LC_DIRTY, &lc->flags);
0407
0408
0409
0410
0411 if (test_bit(__LC_LOCKED, &lc->flags)) {
0412 ++lc->locked;
0413 RETURN(NULL);
0414 }
0415
0416
0417
0418
0419 if (!lc_unused_element_available(lc)) {
0420 __set_bit(__LC_STARVING, &lc->flags);
0421 RETURN(NULL);
0422 }
0423
0424
0425
0426
0427 if (lc->pending_changes >= lc->max_pending_changes)
0428 RETURN(NULL);
0429
0430 e = lc_prepare_for_change(lc, enr);
0431 BUG_ON(!e);
0432
0433 clear_bit(__LC_STARVING, &lc->flags);
0434 BUG_ON(++e->refcnt != 1);
0435 lc->used++;
0436 lc->pending_changes++;
0437
0438 RETURN(e);
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
0482 {
0483 return __lc_get(lc, enr, LC_GET_MAY_CHANGE);
0484 }
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501 struct lc_element *lc_get_cumulative(struct lru_cache *lc, unsigned int enr)
0502 {
0503 return __lc_get(lc, enr, LC_GET_MAY_CHANGE|LC_GET_MAY_USE_UNCOMMITTED);
0504 }
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522 struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
0523 {
0524 return __lc_get(lc, enr, 0);
0525 }
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535 void lc_committed(struct lru_cache *lc)
0536 {
0537 struct lc_element *e, *tmp;
0538
0539 PARANOIA_ENTRY();
0540 list_for_each_entry_safe(e, tmp, &lc->to_be_changed, list) {
0541
0542 ++lc->changed;
0543 e->lc_number = e->lc_new_number;
0544 list_move(&e->list, &lc->in_use);
0545 }
0546 lc->pending_changes = 0;
0547 RETURN();
0548 }
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560 unsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
0561 {
0562 PARANOIA_ENTRY();
0563 PARANOIA_LC_ELEMENT(lc, e);
0564 BUG_ON(e->refcnt == 0);
0565 BUG_ON(e->lc_number != e->lc_new_number);
0566 if (--e->refcnt == 0) {
0567
0568 list_move(&e->list, &lc->lru);
0569 lc->used--;
0570 clear_bit_unlock(__LC_STARVING, &lc->flags);
0571 }
0572 RETURN(e->refcnt);
0573 }
0574
0575
0576
0577
0578
0579
0580 struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
0581 {
0582 BUG_ON(i >= lc->nr_elements);
0583 BUG_ON(lc->lc_element[i] == NULL);
0584 BUG_ON(lc->lc_element[i]->lc_index != i);
0585 return lc->lc_element[i];
0586 }
0587
0588
0589
0590
0591
0592
0593 unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
0594 {
0595 PARANOIA_LC_ELEMENT(lc, e);
0596 return e->lc_index;
0597 }
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607 void lc_set(struct lru_cache *lc, unsigned int enr, int index)
0608 {
0609 struct lc_element *e;
0610 struct list_head *lh;
0611
0612 if (index < 0 || index >= lc->nr_elements)
0613 return;
0614
0615 e = lc_element_by_index(lc, index);
0616 BUG_ON(e->lc_number != e->lc_new_number);
0617 BUG_ON(e->refcnt != 0);
0618
0619 e->lc_number = e->lc_new_number = enr;
0620 hlist_del_init(&e->colision);
0621 if (enr == LC_FREE)
0622 lh = &lc->free;
0623 else {
0624 hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
0625 lh = &lc->lru;
0626 }
0627 list_move(&e->list, lh);
0628 }
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639 void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
0640 void (*detail) (struct seq_file *, struct lc_element *))
0641 {
0642 unsigned int nr_elements = lc->nr_elements;
0643 struct lc_element *e;
0644 int i;
0645
0646 seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext);
0647 for (i = 0; i < nr_elements; i++) {
0648 e = lc_element_by_index(lc, i);
0649 if (e->lc_number != e->lc_new_number)
0650 seq_printf(seq, "\t%5d: %6d %8d %6d ",
0651 i, e->lc_number, e->lc_new_number, e->refcnt);
0652 else
0653 seq_printf(seq, "\t%5d: %6d %-8s %6d ",
0654 i, e->lc_number, "-\"-", e->refcnt);
0655 if (detail)
0656 detail(seq, e);
0657 seq_putc(seq, '\n');
0658 }
0659 }
0660
0661 EXPORT_SYMBOL(lc_create);
0662 EXPORT_SYMBOL(lc_reset);
0663 EXPORT_SYMBOL(lc_destroy);
0664 EXPORT_SYMBOL(lc_set);
0665 EXPORT_SYMBOL(lc_del);
0666 EXPORT_SYMBOL(lc_try_get);
0667 EXPORT_SYMBOL(lc_find);
0668 EXPORT_SYMBOL(lc_get);
0669 EXPORT_SYMBOL(lc_put);
0670 EXPORT_SYMBOL(lc_committed);
0671 EXPORT_SYMBOL(lc_element_by_index);
0672 EXPORT_SYMBOL(lc_index_of);
0673 EXPORT_SYMBOL(lc_seq_printf_stats);
0674 EXPORT_SYMBOL(lc_seq_dump_details);
0675 EXPORT_SYMBOL(lc_try_lock);
0676 EXPORT_SYMBOL(lc_is_used);
0677 EXPORT_SYMBOL(lc_get_cumulative);