mcache.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
  3. * All rights reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/module.h>
  16. #include <linux/slab.h>
  17. #include <linux/mempool.h>
  18. #include "netfs.h"
  19. static struct kmem_cache *pohmelfs_mcache_cache;
  20. static mempool_t *pohmelfs_mcache_pool;
  21. static inline int pohmelfs_mcache_cmp(u64 gen, u64 new)
  22. {
  23. if (gen < new)
  24. return 1;
  25. if (gen > new)
  26. return -1;
  27. return 0;
  28. }
  29. struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen)
  30. {
  31. struct rb_root *root = &psb->mcache_root;
  32. struct rb_node *n = root->rb_node;
  33. struct pohmelfs_mcache *tmp, *ret = NULL;
  34. int cmp;
  35. while (n) {
  36. tmp = rb_entry(n, struct pohmelfs_mcache, mcache_entry);
  37. cmp = pohmelfs_mcache_cmp(tmp->gen, gen);
  38. if (cmp < 0)
  39. n = n->rb_left;
  40. else if (cmp > 0)
  41. n = n->rb_right;
  42. else {
  43. ret = tmp;
  44. pohmelfs_mcache_get(ret);
  45. break;
  46. }
  47. }
  48. return ret;
  49. }
  50. static int pohmelfs_mcache_insert(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  51. {
  52. struct rb_root *root = &psb->mcache_root;
  53. struct rb_node **n = &root->rb_node, *parent = NULL;
  54. struct pohmelfs_mcache *ret = NULL, *tmp;
  55. int cmp;
  56. while (*n) {
  57. parent = *n;
  58. tmp = rb_entry(parent, struct pohmelfs_mcache, mcache_entry);
  59. cmp = pohmelfs_mcache_cmp(tmp->gen, m->gen);
  60. if (cmp < 0)
  61. n = &parent->rb_left;
  62. else if (cmp > 0)
  63. n = &parent->rb_right;
  64. else {
  65. ret = tmp;
  66. break;
  67. }
  68. }
  69. if (ret)
  70. return -EEXIST;
  71. rb_link_node(&m->mcache_entry, parent, n);
  72. rb_insert_color(&m->mcache_entry, root);
  73. return 0;
  74. }
  75. static int pohmelfs_mcache_remove(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  76. {
  77. if (m && m->mcache_entry.rb_parent_color) {
  78. rb_erase(&m->mcache_entry, &psb->mcache_root);
  79. m->mcache_entry.rb_parent_color = 0;
  80. return 1;
  81. }
  82. return 0;
  83. }
  84. void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  85. {
  86. mutex_lock(&psb->mcache_lock);
  87. pohmelfs_mcache_remove(psb, m);
  88. mutex_unlock(&psb->mcache_lock);
  89. }
  90. struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start,
  91. unsigned int size, void *data)
  92. {
  93. struct pohmelfs_mcache *m;
  94. int err = -ENOMEM;
  95. m = mempool_alloc(pohmelfs_mcache_pool, GFP_KERNEL);
  96. if (!m)
  97. goto err_out_exit;
  98. init_completion(&m->complete);
  99. m->err = 0;
  100. atomic_set(&m->refcnt, 1);
  101. m->data = data;
  102. m->start = start;
  103. m->size = size;
  104. m->gen = atomic_long_inc_return(&psb->mcache_gen);
  105. mutex_lock(&psb->mcache_lock);
  106. err = pohmelfs_mcache_insert(psb, m);
  107. mutex_unlock(&psb->mcache_lock);
  108. if (err)
  109. goto err_out_free;
  110. return m;
  111. err_out_free:
  112. mempool_free(m, pohmelfs_mcache_pool);
  113. err_out_exit:
  114. return ERR_PTR(err);
  115. }
  116. void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
  117. {
  118. pohmelfs_mcache_remove_locked(psb, m);
  119. mempool_free(m, pohmelfs_mcache_pool);
  120. }
  121. int __init pohmelfs_mcache_init(void)
  122. {
  123. pohmelfs_mcache_cache = kmem_cache_create("pohmelfs_mcache_cache",
  124. sizeof(struct pohmelfs_mcache),
  125. 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), NULL);
  126. if (!pohmelfs_mcache_cache)
  127. goto err_out_exit;
  128. pohmelfs_mcache_pool = mempool_create_slab_pool(256, pohmelfs_mcache_cache);
  129. if (!pohmelfs_mcache_pool)
  130. goto err_out_free;
  131. return 0;
  132. err_out_free:
  133. kmem_cache_destroy(pohmelfs_mcache_cache);
  134. err_out_exit:
  135. return -ENOMEM;
  136. }
  137. void pohmelfs_mcache_exit(void)
  138. {
  139. mempool_destroy(pohmelfs_mcache_pool);
  140. kmem_cache_destroy(pohmelfs_mcache_cache);
  141. }