~ [ 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-6.4.16)


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

~ [ 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