~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/mbcache.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /fs/mbcache.c (Version linux-6.12-rc7) and /fs/mbcache.c (Version linux-5.1.21)


  1 // SPDX-License-Identifier: GPL-2.0-only       << 
  2 #include <linux/spinlock.h>                         1 #include <linux/spinlock.h>
  3 #include <linux/slab.h>                             2 #include <linux/slab.h>
  4 #include <linux/list.h>                             3 #include <linux/list.h>
  5 #include <linux/list_bl.h>                          4 #include <linux/list_bl.h>
  6 #include <linux/module.h>                           5 #include <linux/module.h>
  7 #include <linux/sched.h>                            6 #include <linux/sched.h>
  8 #include <linux/workqueue.h>                        7 #include <linux/workqueue.h>
  9 #include <linux/mbcache.h>                          8 #include <linux/mbcache.h>
 10                                                     9 
 11 /*                                                 10 /*
 12  * Mbcache is a simple key-value store. Keys n     11  * Mbcache is a simple key-value store. Keys need not be unique, however
 13  * key-value pairs are expected to be unique (     12  * key-value pairs are expected to be unique (we use this fact in
 14  * mb_cache_entry_delete_or_get()).            !!  13  * mb_cache_entry_delete()).
 15  *                                                 14  *
 16  * Ext2 and ext4 use this cache for deduplicat     15  * Ext2 and ext4 use this cache for deduplication of extended attribute blocks.
 17  * Ext4 also uses it for deduplication of xatt     16  * Ext4 also uses it for deduplication of xattr values stored in inodes.
 18  * They use hash of data as a key and provide      17  * They use hash of data as a key and provide a value that may represent a
 19  * block or inode number. That's why keys need     18  * block or inode number. That's why keys need not be unique (hash of different
 20  * data may be the same). However user provide     19  * data may be the same). However user provided value always uniquely
 21  * identifies a cache entry.                       20  * identifies a cache entry.
 22  *                                                 21  *
 23  * We provide functions for creation and remov     22  * We provide functions for creation and removal of entries, search by key,
 24  * and a special "delete entry with given key-     23  * and a special "delete entry with given key-value pair" operation. Fixed
 25  * size hash table is used for fast key lookup     24  * size hash table is used for fast key lookups.
 26  */                                                25  */
 27                                                    26 
 28 struct mb_cache {                                  27 struct mb_cache {
 29         /* Hash table of entries */                28         /* Hash table of entries */
 30         struct hlist_bl_head    *c_hash;           29         struct hlist_bl_head    *c_hash;
 31         /* log2 of hash table size */              30         /* log2 of hash table size */
 32         int                     c_bucket_bits;     31         int                     c_bucket_bits;
 33         /* Maximum entries in cache to avoid d     32         /* Maximum entries in cache to avoid degrading hash too much */
 34         unsigned long           c_max_entries;     33         unsigned long           c_max_entries;
 35         /* Protects c_list, c_entry_count */       34         /* Protects c_list, c_entry_count */
 36         spinlock_t              c_list_lock;       35         spinlock_t              c_list_lock;
 37         struct list_head        c_list;            36         struct list_head        c_list;
 38         /* Number of entries in cache */           37         /* Number of entries in cache */
 39         unsigned long           c_entry_count;     38         unsigned long           c_entry_count;
 40         struct shrinker         *c_shrink;     !!  39         struct shrinker         c_shrink;
 41         /* Work for shrinking when the cache h     40         /* Work for shrinking when the cache has too many entries */
 42         struct work_struct      c_shrink_work;     41         struct work_struct      c_shrink_work;
 43 };                                                 42 };
 44                                                    43 
 45 static struct kmem_cache *mb_entry_cache;          44 static struct kmem_cache *mb_entry_cache;
 46                                                    45 
 47 static unsigned long mb_cache_shrink(struct mb     46 static unsigned long mb_cache_shrink(struct mb_cache *cache,
 48                                      unsigned      47                                      unsigned long nr_to_scan);
 49                                                    48 
 50 static inline struct hlist_bl_head *mb_cache_e     49 static inline struct hlist_bl_head *mb_cache_entry_head(struct mb_cache *cache,
 51                                                    50                                                         u32 key)
 52 {                                                  51 {
 53         return &cache->c_hash[hash_32(key, cac     52         return &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
 54 }                                                  53 }
 55                                                    54 
 56 /*                                                 55 /*
 57  * Number of entries to reclaim synchronously      56  * Number of entries to reclaim synchronously when there are too many entries
 58  * in cache                                        57  * in cache
 59  */                                                58  */
 60 #define SYNC_SHRINK_BATCH 64                       59 #define SYNC_SHRINK_BATCH 64
 61                                                    60 
 62 /*                                                 61 /*
 63  * mb_cache_entry_create - create entry in cac     62  * mb_cache_entry_create - create entry in cache
 64  * @cache - cache where the entry should be cr     63  * @cache - cache where the entry should be created
 65  * @mask - gfp mask with which the entry shoul     64  * @mask - gfp mask with which the entry should be allocated
 66  * @key - key of the entry                         65  * @key - key of the entry
 67  * @value - value of the entry                     66  * @value - value of the entry
 68  * @reusable - is the entry reusable by others     67  * @reusable - is the entry reusable by others?
 69  *                                                 68  *
 70  * Creates entry in @cache with key @key and v     69  * Creates entry in @cache with key @key and value @value. The function returns
 71  * -EBUSY if entry with the same key and value     70  * -EBUSY if entry with the same key and value already exists in cache.
 72  * Otherwise 0 is returned.                        71  * Otherwise 0 is returned.
 73  */                                                72  */
 74 int mb_cache_entry_create(struct mb_cache *cac     73 int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
 75                           u64 value, bool reus     74                           u64 value, bool reusable)
 76 {                                                  75 {
 77         struct mb_cache_entry *entry, *dup;        76         struct mb_cache_entry *entry, *dup;
 78         struct hlist_bl_node *dup_node;            77         struct hlist_bl_node *dup_node;
 79         struct hlist_bl_head *head;                78         struct hlist_bl_head *head;
 80                                                    79 
 81         /* Schedule background reclaim if ther     80         /* Schedule background reclaim if there are too many entries */
 82         if (cache->c_entry_count >= cache->c_m     81         if (cache->c_entry_count >= cache->c_max_entries)
 83                 schedule_work(&cache->c_shrink     82                 schedule_work(&cache->c_shrink_work);
 84         /* Do some sync reclaim if background      83         /* Do some sync reclaim if background reclaim cannot keep up */
 85         if (cache->c_entry_count >= 2*cache->c     84         if (cache->c_entry_count >= 2*cache->c_max_entries)
 86                 mb_cache_shrink(cache, SYNC_SH     85                 mb_cache_shrink(cache, SYNC_SHRINK_BATCH);
 87                                                    86 
 88         entry = kmem_cache_alloc(mb_entry_cach     87         entry = kmem_cache_alloc(mb_entry_cache, mask);
 89         if (!entry)                                88         if (!entry)
 90                 return -ENOMEM;                    89                 return -ENOMEM;
 91                                                    90 
 92         INIT_LIST_HEAD(&entry->e_list);            91         INIT_LIST_HEAD(&entry->e_list);
 93         /*                                     !!  92         /* One ref for hash, one ref returned */
 94          * We create entry with two references !!  93         atomic_set(&entry->e_refcnt, 1);
 95          * hash table, the other reference is  << 
 96          * mb_cache_entry_delete_or_get() unti << 
 97          * avoids nesting of cache->c_list_loc << 
 98          * is problematic for RT.              << 
 99          */                                    << 
100         atomic_set(&entry->e_refcnt, 2);       << 
101         entry->e_key = key;                        94         entry->e_key = key;
102         entry->e_value = value;                    95         entry->e_value = value;
103         entry->e_flags = 0;                    !!  96         entry->e_reusable = reusable;
104         if (reusable)                          !!  97         entry->e_referenced = 0;
105                 set_bit(MBE_REUSABLE_B, &entry << 
106         head = mb_cache_entry_head(cache, key)     98         head = mb_cache_entry_head(cache, key);
107         hlist_bl_lock(head);                       99         hlist_bl_lock(head);
108         hlist_bl_for_each_entry(dup, dup_node,    100         hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
109                 if (dup->e_key == key && dup->    101                 if (dup->e_key == key && dup->e_value == value) {
110                         hlist_bl_unlock(head);    102                         hlist_bl_unlock(head);
111                         kmem_cache_free(mb_ent    103                         kmem_cache_free(mb_entry_cache, entry);
112                         return -EBUSY;            104                         return -EBUSY;
113                 }                                 105                 }
114         }                                         106         }
115         hlist_bl_add_head(&entry->e_hash_list,    107         hlist_bl_add_head(&entry->e_hash_list, head);
116         hlist_bl_unlock(head);                    108         hlist_bl_unlock(head);
                                                   >> 109 
117         spin_lock(&cache->c_list_lock);           110         spin_lock(&cache->c_list_lock);
118         list_add_tail(&entry->e_list, &cache->    111         list_add_tail(&entry->e_list, &cache->c_list);
                                                   >> 112         /* Grab ref for LRU list */
                                                   >> 113         atomic_inc(&entry->e_refcnt);
119         cache->c_entry_count++;                   114         cache->c_entry_count++;
120         spin_unlock(&cache->c_list_lock);         115         spin_unlock(&cache->c_list_lock);
121         mb_cache_entry_put(cache, entry);      << 
122                                                   116 
123         return 0;                                 117         return 0;
124 }                                                 118 }
125 EXPORT_SYMBOL(mb_cache_entry_create);             119 EXPORT_SYMBOL(mb_cache_entry_create);
126                                                   120 
127 void __mb_cache_entry_free(struct mb_cache *ca !! 121 void __mb_cache_entry_free(struct mb_cache_entry *entry)
128 {                                                 122 {
129         struct hlist_bl_head *head;            << 
130                                                << 
131         head = mb_cache_entry_head(cache, entr << 
132         hlist_bl_lock(head);                   << 
133         hlist_bl_del(&entry->e_hash_list);     << 
134         hlist_bl_unlock(head);                 << 
135         kmem_cache_free(mb_entry_cache, entry)    123         kmem_cache_free(mb_entry_cache, entry);
136 }                                                 124 }
137 EXPORT_SYMBOL(__mb_cache_entry_free);             125 EXPORT_SYMBOL(__mb_cache_entry_free);
138                                                   126 
139 /*                                             << 
140  * mb_cache_entry_wait_unused - wait to be the << 
141  *                                             << 
142  * @entry - entry to work on                   << 
143  *                                             << 
144  * Wait to be the last user of the entry.      << 
145  */                                            << 
146 void mb_cache_entry_wait_unused(struct mb_cach << 
147 {                                              << 
148         wait_var_event(&entry->e_refcnt, atomi << 
149 }                                              << 
150 EXPORT_SYMBOL(mb_cache_entry_wait_unused);     << 
151                                                << 
152 static struct mb_cache_entry *__entry_find(str    127 static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
153                                            str    128                                            struct mb_cache_entry *entry,
154                                            u32    129                                            u32 key)
155 {                                                 130 {
156         struct mb_cache_entry *old_entry = ent    131         struct mb_cache_entry *old_entry = entry;
157         struct hlist_bl_node *node;               132         struct hlist_bl_node *node;
158         struct hlist_bl_head *head;               133         struct hlist_bl_head *head;
159                                                   134 
160         head = mb_cache_entry_head(cache, key)    135         head = mb_cache_entry_head(cache, key);
161         hlist_bl_lock(head);                      136         hlist_bl_lock(head);
162         if (entry && !hlist_bl_unhashed(&entry    137         if (entry && !hlist_bl_unhashed(&entry->e_hash_list))
163                 node = entry->e_hash_list.next    138                 node = entry->e_hash_list.next;
164         else                                      139         else
165                 node = hlist_bl_first(head);      140                 node = hlist_bl_first(head);
166         while (node) {                            141         while (node) {
167                 entry = hlist_bl_entry(node, s    142                 entry = hlist_bl_entry(node, struct mb_cache_entry,
168                                        e_hash_    143                                        e_hash_list);
169                 if (entry->e_key == key &&     !! 144                 if (entry->e_key == key && entry->e_reusable) {
170                     test_bit(MBE_REUSABLE_B, & !! 145                         atomic_inc(&entry->e_refcnt);
171                     atomic_inc_not_zero(&entry << 
172                         goto out;                 146                         goto out;
                                                   >> 147                 }
173                 node = node->next;                148                 node = node->next;
174         }                                         149         }
175         entry = NULL;                             150         entry = NULL;
176 out:                                              151 out:
177         hlist_bl_unlock(head);                    152         hlist_bl_unlock(head);
178         if (old_entry)                            153         if (old_entry)
179                 mb_cache_entry_put(cache, old_    154                 mb_cache_entry_put(cache, old_entry);
180                                                   155 
181         return entry;                             156         return entry;
182 }                                                 157 }
183                                                   158 
184 /*                                                159 /*
185  * mb_cache_entry_find_first - find the first     160  * mb_cache_entry_find_first - find the first reusable entry with the given key
186  * @cache: cache where we should search           161  * @cache: cache where we should search
187  * @key: key to look for                          162  * @key: key to look for
188  *                                                163  *
189  * Search in @cache for a reusable entry with     164  * Search in @cache for a reusable entry with key @key. Grabs reference to the
190  * first reusable entry found and returns the     165  * first reusable entry found and returns the entry.
191  */                                               166  */
192 struct mb_cache_entry *mb_cache_entry_find_fir    167 struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache,
193                                                   168                                                  u32 key)
194 {                                                 169 {
195         return __entry_find(cache, NULL, key);    170         return __entry_find(cache, NULL, key);
196 }                                                 171 }
197 EXPORT_SYMBOL(mb_cache_entry_find_first);         172 EXPORT_SYMBOL(mb_cache_entry_find_first);
198                                                   173 
199 /*                                                174 /*
200  * mb_cache_entry_find_next - find next reusab    175  * mb_cache_entry_find_next - find next reusable entry with the same key
201  * @cache: cache where we should search           176  * @cache: cache where we should search
202  * @entry: entry to start search from             177  * @entry: entry to start search from
203  *                                                178  *
204  * Finds next reusable entry in the hash chain    179  * Finds next reusable entry in the hash chain which has the same key as @entry.
205  * If @entry is unhashed (which can happen whe    180  * If @entry is unhashed (which can happen when deletion of entry races with the
206  * search), finds the first reusable entry in     181  * search), finds the first reusable entry in the hash chain. The function drops
207  * reference to @entry and returns with a refe    182  * reference to @entry and returns with a reference to the found entry.
208  */                                               183  */
209 struct mb_cache_entry *mb_cache_entry_find_nex    184 struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache,
210                                                   185                                                 struct mb_cache_entry *entry)
211 {                                                 186 {
212         return __entry_find(cache, entry, entr    187         return __entry_find(cache, entry, entry->e_key);
213 }                                                 188 }
214 EXPORT_SYMBOL(mb_cache_entry_find_next);          189 EXPORT_SYMBOL(mb_cache_entry_find_next);
215                                                   190 
216 /*                                                191 /*
217  * mb_cache_entry_get - get a cache entry by v    192  * mb_cache_entry_get - get a cache entry by value (and key)
218  * @cache - cache we work with                    193  * @cache - cache we work with
219  * @key - key                                     194  * @key - key
220  * @value - value                                 195  * @value - value
221  */                                               196  */
222 struct mb_cache_entry *mb_cache_entry_get(stru    197 struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
223                                           u64     198                                           u64 value)
224 {                                                 199 {
225         struct hlist_bl_node *node;               200         struct hlist_bl_node *node;
226         struct hlist_bl_head *head;               201         struct hlist_bl_head *head;
227         struct mb_cache_entry *entry;             202         struct mb_cache_entry *entry;
228                                                   203 
229         head = mb_cache_entry_head(cache, key)    204         head = mb_cache_entry_head(cache, key);
230         hlist_bl_lock(head);                      205         hlist_bl_lock(head);
231         hlist_bl_for_each_entry(entry, node, h    206         hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
232                 if (entry->e_key == key && ent !! 207                 if (entry->e_key == key && entry->e_value == value) {
233                     atomic_inc_not_zero(&entry !! 208                         atomic_inc(&entry->e_refcnt);
234                         goto out;                 209                         goto out;
                                                   >> 210                 }
235         }                                         211         }
236         entry = NULL;                             212         entry = NULL;
237 out:                                              213 out:
238         hlist_bl_unlock(head);                    214         hlist_bl_unlock(head);
239         return entry;                             215         return entry;
240 }                                                 216 }
241 EXPORT_SYMBOL(mb_cache_entry_get);                217 EXPORT_SYMBOL(mb_cache_entry_get);
242                                                   218 
243 /* mb_cache_entry_delete_or_get - remove a cac !! 219 /* mb_cache_entry_delete - remove a cache entry
244  * @cache - cache we work with                    220  * @cache - cache we work with
245  * @key - key                                     221  * @key - key
246  * @value - value                                 222  * @value - value
247  *                                                223  *
248  * Remove entry from cache @cache with key @ke !! 224  * Remove entry from cache @cache with key @key and value @value.
249  * happens only if the entry is unused. The fu << 
250  * entry was successfully removed or there's n << 
251  * function grabs reference of the entry that  << 
252  * still has users and return it.              << 
253  */                                               225  */
254 struct mb_cache_entry *mb_cache_entry_delete_o !! 226 void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value)
255                                                << 
256 {                                                 227 {
                                                   >> 228         struct hlist_bl_node *node;
                                                   >> 229         struct hlist_bl_head *head;
257         struct mb_cache_entry *entry;             230         struct mb_cache_entry *entry;
258                                                   231 
259         entry = mb_cache_entry_get(cache, key, !! 232         head = mb_cache_entry_head(cache, key);
260         if (!entry)                            !! 233         hlist_bl_lock(head);
261                 return NULL;                   !! 234         hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
262                                                !! 235                 if (entry->e_key == key && entry->e_value == value) {
263         /*                                     !! 236                         /* We keep hash list reference to keep entry alive */
264          * Drop the ref we got from mb_cache_e !! 237                         hlist_bl_del_init(&entry->e_hash_list);
265          * ref if we are the last user         !! 238                         hlist_bl_unlock(head);
266          */                                    !! 239                         spin_lock(&cache->c_list_lock);
267         if (atomic_cmpxchg(&entry->e_refcnt, 2 !! 240                         if (!list_empty(&entry->e_list)) {
268                 return entry;                  !! 241                                 list_del_init(&entry->e_list);
269                                                !! 242                                 if (!WARN_ONCE(cache->c_entry_count == 0,
270         spin_lock(&cache->c_list_lock);        !! 243                 "mbcache: attempt to decrement c_entry_count past zero"))
271         if (!list_empty(&entry->e_list))       !! 244                                         cache->c_entry_count--;
272                 list_del_init(&entry->e_list); !! 245                                 atomic_dec(&entry->e_refcnt);
273         cache->c_entry_count--;                !! 246                         }
274         spin_unlock(&cache->c_list_lock);      !! 247                         spin_unlock(&cache->c_list_lock);
275         __mb_cache_entry_free(cache, entry);   !! 248                         mb_cache_entry_put(cache, entry);
276         return NULL;                           !! 249                         return;
                                                   >> 250                 }
                                                   >> 251         }
                                                   >> 252         hlist_bl_unlock(head);
277 }                                                 253 }
278 EXPORT_SYMBOL(mb_cache_entry_delete_or_get);   !! 254 EXPORT_SYMBOL(mb_cache_entry_delete);
279                                                   255 
280 /* mb_cache_entry_touch - cache entry got used    256 /* mb_cache_entry_touch - cache entry got used
281  * @cache - cache the entry belongs to            257  * @cache - cache the entry belongs to
282  * @entry - entry that got used                   258  * @entry - entry that got used
283  *                                                259  *
284  * Marks entry as used to give hit higher chan    260  * Marks entry as used to give hit higher chances of surviving in cache.
285  */                                               261  */
286 void mb_cache_entry_touch(struct mb_cache *cac    262 void mb_cache_entry_touch(struct mb_cache *cache,
287                           struct mb_cache_entr    263                           struct mb_cache_entry *entry)
288 {                                                 264 {
289         set_bit(MBE_REFERENCED_B, &entry->e_fl !! 265         entry->e_referenced = 1;
290 }                                                 266 }
291 EXPORT_SYMBOL(mb_cache_entry_touch);              267 EXPORT_SYMBOL(mb_cache_entry_touch);
292                                                   268 
293 static unsigned long mb_cache_count(struct shr    269 static unsigned long mb_cache_count(struct shrinker *shrink,
294                                     struct shr    270                                     struct shrink_control *sc)
295 {                                                 271 {
296         struct mb_cache *cache = shrink->priva !! 272         struct mb_cache *cache = container_of(shrink, struct mb_cache,
                                                   >> 273                                               c_shrink);
297                                                   274 
298         return cache->c_entry_count;              275         return cache->c_entry_count;
299 }                                                 276 }
300                                                   277 
301 /* Shrink number of entries in cache */           278 /* Shrink number of entries in cache */
302 static unsigned long mb_cache_shrink(struct mb    279 static unsigned long mb_cache_shrink(struct mb_cache *cache,
303                                      unsigned     280                                      unsigned long nr_to_scan)
304 {                                                 281 {
305         struct mb_cache_entry *entry;             282         struct mb_cache_entry *entry;
                                                   >> 283         struct hlist_bl_head *head;
306         unsigned long shrunk = 0;                 284         unsigned long shrunk = 0;
307                                                   285 
308         spin_lock(&cache->c_list_lock);           286         spin_lock(&cache->c_list_lock);
309         while (nr_to_scan-- && !list_empty(&ca    287         while (nr_to_scan-- && !list_empty(&cache->c_list)) {
310                 entry = list_first_entry(&cach    288                 entry = list_first_entry(&cache->c_list,
311                                          struc    289                                          struct mb_cache_entry, e_list);
312                 /* Drop initial hash reference !! 290                 if (entry->e_referenced) {
313                 if (test_bit(MBE_REFERENCED_B, !! 291                         entry->e_referenced = 0;
314                     atomic_cmpxchg(&entry->e_r << 
315                         clear_bit(MBE_REFERENC << 
316                         list_move_tail(&entry-    292                         list_move_tail(&entry->e_list, &cache->c_list);
317                         continue;                 293                         continue;
318                 }                                 294                 }
319                 list_del_init(&entry->e_list);    295                 list_del_init(&entry->e_list);
320                 cache->c_entry_count--;           296                 cache->c_entry_count--;
                                                   >> 297                 /*
                                                   >> 298                  * We keep LRU list reference so that entry doesn't go away
                                                   >> 299                  * from under us.
                                                   >> 300                  */
321                 spin_unlock(&cache->c_list_loc    301                 spin_unlock(&cache->c_list_lock);
322                 __mb_cache_entry_free(cache, e !! 302                 head = mb_cache_entry_head(cache, entry->e_key);
323                 shrunk++;                      !! 303                 hlist_bl_lock(head);
                                                   >> 304                 if (!hlist_bl_unhashed(&entry->e_hash_list)) {
                                                   >> 305                         hlist_bl_del_init(&entry->e_hash_list);
                                                   >> 306                         atomic_dec(&entry->e_refcnt);
                                                   >> 307                 }
                                                   >> 308                 hlist_bl_unlock(head);
                                                   >> 309                 if (mb_cache_entry_put(cache, entry))
                                                   >> 310                         shrunk++;
324                 cond_resched();                   311                 cond_resched();
325                 spin_lock(&cache->c_list_lock)    312                 spin_lock(&cache->c_list_lock);
326         }                                         313         }
327         spin_unlock(&cache->c_list_lock);         314         spin_unlock(&cache->c_list_lock);
328                                                   315 
329         return shrunk;                            316         return shrunk;
330 }                                                 317 }
331                                                   318 
332 static unsigned long mb_cache_scan(struct shri    319 static unsigned long mb_cache_scan(struct shrinker *shrink,
333                                    struct shri    320                                    struct shrink_control *sc)
334 {                                                 321 {
335         struct mb_cache *cache = shrink->priva !! 322         struct mb_cache *cache = container_of(shrink, struct mb_cache,
                                                   >> 323                                               c_shrink);
336         return mb_cache_shrink(cache, sc->nr_t    324         return mb_cache_shrink(cache, sc->nr_to_scan);
337 }                                                 325 }
338                                                   326 
339 /* We shrink 1/X of the cache when we have too    327 /* We shrink 1/X of the cache when we have too many entries in it */
340 #define SHRINK_DIVISOR 16                         328 #define SHRINK_DIVISOR 16
341                                                   329 
342 static void mb_cache_shrink_worker(struct work    330 static void mb_cache_shrink_worker(struct work_struct *work)
343 {                                                 331 {
344         struct mb_cache *cache = container_of(    332         struct mb_cache *cache = container_of(work, struct mb_cache,
345                                                   333                                               c_shrink_work);
346         mb_cache_shrink(cache, cache->c_max_en    334         mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR);
347 }                                                 335 }
348                                                   336 
349 /*                                                337 /*
350  * mb_cache_create - create cache                 338  * mb_cache_create - create cache
351  * @bucket_bits: log2 of the hash table size      339  * @bucket_bits: log2 of the hash table size
352  *                                                340  *
353  * Create cache for keys with 2^bucket_bits ha    341  * Create cache for keys with 2^bucket_bits hash entries.
354  */                                               342  */
355 struct mb_cache *mb_cache_create(int bucket_bi    343 struct mb_cache *mb_cache_create(int bucket_bits)
356 {                                                 344 {
357         struct mb_cache *cache;                   345         struct mb_cache *cache;
358         unsigned long bucket_count = 1UL << bu    346         unsigned long bucket_count = 1UL << bucket_bits;
359         unsigned long i;                          347         unsigned long i;
360                                                   348 
361         cache = kzalloc(sizeof(struct mb_cache    349         cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL);
362         if (!cache)                               350         if (!cache)
363                 goto err_out;                     351                 goto err_out;
364         cache->c_bucket_bits = bucket_bits;       352         cache->c_bucket_bits = bucket_bits;
365         cache->c_max_entries = bucket_count <<    353         cache->c_max_entries = bucket_count << 4;
366         INIT_LIST_HEAD(&cache->c_list);           354         INIT_LIST_HEAD(&cache->c_list);
367         spin_lock_init(&cache->c_list_lock);      355         spin_lock_init(&cache->c_list_lock);
368         cache->c_hash = kmalloc_array(bucket_c    356         cache->c_hash = kmalloc_array(bucket_count,
369                                       sizeof(s    357                                       sizeof(struct hlist_bl_head),
370                                       GFP_KERN    358                                       GFP_KERNEL);
371         if (!cache->c_hash) {                     359         if (!cache->c_hash) {
372                 kfree(cache);                     360                 kfree(cache);
373                 goto err_out;                     361                 goto err_out;
374         }                                         362         }
375         for (i = 0; i < bucket_count; i++)        363         for (i = 0; i < bucket_count; i++)
376                 INIT_HLIST_BL_HEAD(&cache->c_h    364                 INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
377                                                   365 
378         cache->c_shrink = shrinker_alloc(0, "m !! 366         cache->c_shrink.count_objects = mb_cache_count;
379         if (!cache->c_shrink) {                !! 367         cache->c_shrink.scan_objects = mb_cache_scan;
                                                   >> 368         cache->c_shrink.seeks = DEFAULT_SEEKS;
                                                   >> 369         if (register_shrinker(&cache->c_shrink)) {
380                 kfree(cache->c_hash);             370                 kfree(cache->c_hash);
381                 kfree(cache);                     371                 kfree(cache);
382                 goto err_out;                     372                 goto err_out;
383         }                                         373         }
384                                                   374 
385         cache->c_shrink->count_objects = mb_ca << 
386         cache->c_shrink->scan_objects = mb_cac << 
387         cache->c_shrink->private_data = cache; << 
388                                                << 
389         shrinker_register(cache->c_shrink);    << 
390                                                << 
391         INIT_WORK(&cache->c_shrink_work, mb_ca    375         INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
392                                                   376 
393         return cache;                             377         return cache;
394                                                   378 
395 err_out:                                          379 err_out:
396         return NULL;                              380         return NULL;
397 }                                                 381 }
398 EXPORT_SYMBOL(mb_cache_create);                   382 EXPORT_SYMBOL(mb_cache_create);
399                                                   383 
400 /*                                                384 /*
401  * mb_cache_destroy - destroy cache               385  * mb_cache_destroy - destroy cache
402  * @cache: the cache to destroy                   386  * @cache: the cache to destroy
403  *                                                387  *
404  * Free all entries in cache and cache itself.    388  * Free all entries in cache and cache itself. Caller must make sure nobody
405  * (except shrinker) can reach @cache when cal    389  * (except shrinker) can reach @cache when calling this.
406  */                                               390  */
407 void mb_cache_destroy(struct mb_cache *cache)     391 void mb_cache_destroy(struct mb_cache *cache)
408 {                                                 392 {
409         struct mb_cache_entry *entry, *next;      393         struct mb_cache_entry *entry, *next;
410                                                   394 
411         shrinker_free(cache->c_shrink);        !! 395         unregister_shrinker(&cache->c_shrink);
412                                                   396 
413         /*                                        397         /*
414          * We don't bother with any locking. C    398          * We don't bother with any locking. Cache must not be used at this
415          * point.                                 399          * point.
416          */                                       400          */
417         list_for_each_entry_safe(entry, next,     401         list_for_each_entry_safe(entry, next, &cache->c_list, e_list) {
                                                   >> 402                 if (!hlist_bl_unhashed(&entry->e_hash_list)) {
                                                   >> 403                         hlist_bl_del_init(&entry->e_hash_list);
                                                   >> 404                         atomic_dec(&entry->e_refcnt);
                                                   >> 405                 } else
                                                   >> 406                         WARN_ON(1);
418                 list_del(&entry->e_list);         407                 list_del(&entry->e_list);
419                 WARN_ON(atomic_read(&entry->e_    408                 WARN_ON(atomic_read(&entry->e_refcnt) != 1);
420                 mb_cache_entry_put(cache, entr    409                 mb_cache_entry_put(cache, entry);
421         }                                         410         }
422         kfree(cache->c_hash);                     411         kfree(cache->c_hash);
423         kfree(cache);                             412         kfree(cache);
424 }                                                 413 }
425 EXPORT_SYMBOL(mb_cache_destroy);                  414 EXPORT_SYMBOL(mb_cache_destroy);
426                                                   415 
427 static int __init mbcache_init(void)              416 static int __init mbcache_init(void)
428 {                                                 417 {
429         mb_entry_cache = KMEM_CACHE(mb_cache_e !! 418         mb_entry_cache = kmem_cache_create("mbcache",
                                                   >> 419                                 sizeof(struct mb_cache_entry), 0,
                                                   >> 420                                 SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
430         if (!mb_entry_cache)                      421         if (!mb_entry_cache)
431                 return -ENOMEM;                   422                 return -ENOMEM;
432         return 0;                                 423         return 0;
433 }                                                 424 }
434                                                   425 
435 static void __exit mbcache_exit(void)             426 static void __exit mbcache_exit(void)
436 {                                                 427 {
437         kmem_cache_destroy(mb_entry_cache);       428         kmem_cache_destroy(mb_entry_cache);
438 }                                                 429 }
439                                                   430 
440 module_init(mbcache_init)                         431 module_init(mbcache_init)
441 module_exit(mbcache_exit)                         432 module_exit(mbcache_exit)
442                                                   433 
443 MODULE_AUTHOR("Jan Kara <jack@suse.cz>");         434 MODULE_AUTHOR("Jan Kara <jack@suse.cz>");
444 MODULE_DESCRIPTION("Meta block cache (for exte    435 MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
445 MODULE_LICENSE("GPL");                            436 MODULE_LICENSE("GPL");
446                                                   437 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php