~ [ 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.5.19)


  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()).
 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         /* One ref for hash, one ref returned */
 94          * We create entry with two references !!  94         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;                        95         entry->e_key = key;
102         entry->e_value = value;                    96         entry->e_value = value;
103         entry->e_flags = 0;                    !!  97         entry->e_reusable = reusable;
104         if (reusable)                          !!  98         entry->e_referenced = 0;
105                 set_bit(MBE_REUSABLE_B, &entry << 
106         head = mb_cache_entry_head(cache, key)     99         head = mb_cache_entry_head(cache, key);
107         hlist_bl_lock(head);                      100         hlist_bl_lock(head);
108         hlist_bl_for_each_entry(dup, dup_node,    101         hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
109                 if (dup->e_key == key && dup->    102                 if (dup->e_key == key && dup->e_value == value) {
110                         hlist_bl_unlock(head);    103                         hlist_bl_unlock(head);
111                         kmem_cache_free(mb_ent    104                         kmem_cache_free(mb_entry_cache, entry);
112                         return -EBUSY;            105                         return -EBUSY;
113                 }                                 106                 }
114         }                                         107         }
115         hlist_bl_add_head(&entry->e_hash_list,    108         hlist_bl_add_head(&entry->e_hash_list, head);
116         hlist_bl_unlock(head);                    109         hlist_bl_unlock(head);
                                                   >> 110 
117         spin_lock(&cache->c_list_lock);           111         spin_lock(&cache->c_list_lock);
118         list_add_tail(&entry->e_list, &cache->    112         list_add_tail(&entry->e_list, &cache->c_list);
                                                   >> 113         /* Grab ref for LRU list */
                                                   >> 114         atomic_inc(&entry->e_refcnt);
119         cache->c_entry_count++;                   115         cache->c_entry_count++;
120         spin_unlock(&cache->c_list_lock);         116         spin_unlock(&cache->c_list_lock);
121         mb_cache_entry_put(cache, entry);      << 
122                                                   117 
123         return 0;                                 118         return 0;
124 }                                                 119 }
125 EXPORT_SYMBOL(mb_cache_entry_create);             120 EXPORT_SYMBOL(mb_cache_entry_create);
126                                                   121 
127 void __mb_cache_entry_free(struct mb_cache *ca !! 122 void __mb_cache_entry_free(struct mb_cache_entry *entry)
128 {                                                 123 {
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)    124         kmem_cache_free(mb_entry_cache, entry);
136 }                                                 125 }
137 EXPORT_SYMBOL(__mb_cache_entry_free);             126 EXPORT_SYMBOL(__mb_cache_entry_free);
138                                                   127 
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    128 static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
153                                            str    129                                            struct mb_cache_entry *entry,
154                                            u32    130                                            u32 key)
155 {                                                 131 {
156         struct mb_cache_entry *old_entry = ent    132         struct mb_cache_entry *old_entry = entry;
157         struct hlist_bl_node *node;               133         struct hlist_bl_node *node;
158         struct hlist_bl_head *head;               134         struct hlist_bl_head *head;
159                                                   135 
160         head = mb_cache_entry_head(cache, key)    136         head = mb_cache_entry_head(cache, key);
161         hlist_bl_lock(head);                      137         hlist_bl_lock(head);
162         if (entry && !hlist_bl_unhashed(&entry    138         if (entry && !hlist_bl_unhashed(&entry->e_hash_list))
163                 node = entry->e_hash_list.next    139                 node = entry->e_hash_list.next;
164         else                                      140         else
165                 node = hlist_bl_first(head);      141                 node = hlist_bl_first(head);
166         while (node) {                            142         while (node) {
167                 entry = hlist_bl_entry(node, s    143                 entry = hlist_bl_entry(node, struct mb_cache_entry,
168                                        e_hash_    144                                        e_hash_list);
169                 if (entry->e_key == key &&     !! 145                 if (entry->e_key == key && entry->e_reusable) {
170                     test_bit(MBE_REUSABLE_B, & !! 146                         atomic_inc(&entry->e_refcnt);
171                     atomic_inc_not_zero(&entry << 
172                         goto out;                 147                         goto out;
                                                   >> 148                 }
173                 node = node->next;                149                 node = node->next;
174         }                                         150         }
175         entry = NULL;                             151         entry = NULL;
176 out:                                              152 out:
177         hlist_bl_unlock(head);                    153         hlist_bl_unlock(head);
178         if (old_entry)                            154         if (old_entry)
179                 mb_cache_entry_put(cache, old_    155                 mb_cache_entry_put(cache, old_entry);
180                                                   156 
181         return entry;                             157         return entry;
182 }                                                 158 }
183                                                   159 
184 /*                                                160 /*
185  * mb_cache_entry_find_first - find the first     161  * mb_cache_entry_find_first - find the first reusable entry with the given key
186  * @cache: cache where we should search           162  * @cache: cache where we should search
187  * @key: key to look for                          163  * @key: key to look for
188  *                                                164  *
189  * Search in @cache for a reusable entry with     165  * Search in @cache for a reusable entry with key @key. Grabs reference to the
190  * first reusable entry found and returns the     166  * first reusable entry found and returns the entry.
191  */                                               167  */
192 struct mb_cache_entry *mb_cache_entry_find_fir    168 struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache,
193                                                   169                                                  u32 key)
194 {                                                 170 {
195         return __entry_find(cache, NULL, key);    171         return __entry_find(cache, NULL, key);
196 }                                                 172 }
197 EXPORT_SYMBOL(mb_cache_entry_find_first);         173 EXPORT_SYMBOL(mb_cache_entry_find_first);
198                                                   174 
199 /*                                                175 /*
200  * mb_cache_entry_find_next - find next reusab    176  * mb_cache_entry_find_next - find next reusable entry with the same key
201  * @cache: cache where we should search           177  * @cache: cache where we should search
202  * @entry: entry to start search from             178  * @entry: entry to start search from
203  *                                                179  *
204  * Finds next reusable entry in the hash chain    180  * Finds next reusable entry in the hash chain which has the same key as @entry.
205  * If @entry is unhashed (which can happen whe    181  * If @entry is unhashed (which can happen when deletion of entry races with the
206  * search), finds the first reusable entry in     182  * search), finds the first reusable entry in the hash chain. The function drops
207  * reference to @entry and returns with a refe    183  * reference to @entry and returns with a reference to the found entry.
208  */                                               184  */
209 struct mb_cache_entry *mb_cache_entry_find_nex    185 struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache,
210                                                   186                                                 struct mb_cache_entry *entry)
211 {                                                 187 {
212         return __entry_find(cache, entry, entr    188         return __entry_find(cache, entry, entry->e_key);
213 }                                                 189 }
214 EXPORT_SYMBOL(mb_cache_entry_find_next);          190 EXPORT_SYMBOL(mb_cache_entry_find_next);
215                                                   191 
216 /*                                                192 /*
217  * mb_cache_entry_get - get a cache entry by v    193  * mb_cache_entry_get - get a cache entry by value (and key)
218  * @cache - cache we work with                    194  * @cache - cache we work with
219  * @key - key                                     195  * @key - key
220  * @value - value                                 196  * @value - value
221  */                                               197  */
222 struct mb_cache_entry *mb_cache_entry_get(stru    198 struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
223                                           u64     199                                           u64 value)
224 {                                                 200 {
225         struct hlist_bl_node *node;               201         struct hlist_bl_node *node;
226         struct hlist_bl_head *head;               202         struct hlist_bl_head *head;
227         struct mb_cache_entry *entry;             203         struct mb_cache_entry *entry;
228                                                   204 
229         head = mb_cache_entry_head(cache, key)    205         head = mb_cache_entry_head(cache, key);
230         hlist_bl_lock(head);                      206         hlist_bl_lock(head);
231         hlist_bl_for_each_entry(entry, node, h    207         hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
232                 if (entry->e_key == key && ent !! 208                 if (entry->e_key == key && entry->e_value == value) {
233                     atomic_inc_not_zero(&entry !! 209                         atomic_inc(&entry->e_refcnt);
234                         goto out;                 210                         goto out;
                                                   >> 211                 }
235         }                                         212         }
236         entry = NULL;                             213         entry = NULL;
237 out:                                              214 out:
238         hlist_bl_unlock(head);                    215         hlist_bl_unlock(head);
239         return entry;                             216         return entry;
240 }                                                 217 }
241 EXPORT_SYMBOL(mb_cache_entry_get);                218 EXPORT_SYMBOL(mb_cache_entry_get);
242                                                   219 
243 /* mb_cache_entry_delete_or_get - remove a cac !! 220 /* mb_cache_entry_delete - remove a cache entry
244  * @cache - cache we work with                    221  * @cache - cache we work with
245  * @key - key                                     222  * @key - key
246  * @value - value                                 223  * @value - value
247  *                                                224  *
248  * Remove entry from cache @cache with key @ke !! 225  * 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  */                                               226  */
254 struct mb_cache_entry *mb_cache_entry_delete_o !! 227 void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value)
255                                                << 
256 {                                                 228 {
                                                   >> 229         struct hlist_bl_node *node;
                                                   >> 230         struct hlist_bl_head *head;
257         struct mb_cache_entry *entry;             231         struct mb_cache_entry *entry;
258                                                   232 
259         entry = mb_cache_entry_get(cache, key, !! 233         head = mb_cache_entry_head(cache, key);
260         if (!entry)                            !! 234         hlist_bl_lock(head);
261                 return NULL;                   !! 235         hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
262                                                !! 236                 if (entry->e_key == key && entry->e_value == value) {
263         /*                                     !! 237                         /* We keep hash list reference to keep entry alive */
264          * Drop the ref we got from mb_cache_e !! 238                         hlist_bl_del_init(&entry->e_hash_list);
265          * ref if we are the last user         !! 239                         hlist_bl_unlock(head);
266          */                                    !! 240                         spin_lock(&cache->c_list_lock);
267         if (atomic_cmpxchg(&entry->e_refcnt, 2 !! 241                         if (!list_empty(&entry->e_list)) {
268                 return entry;                  !! 242                                 list_del_init(&entry->e_list);
269                                                !! 243                                 if (!WARN_ONCE(cache->c_entry_count == 0,
270         spin_lock(&cache->c_list_lock);        !! 244                 "mbcache: attempt to decrement c_entry_count past zero"))
271         if (!list_empty(&entry->e_list))       !! 245                                         cache->c_entry_count--;
272                 list_del_init(&entry->e_list); !! 246                                 atomic_dec(&entry->e_refcnt);
273         cache->c_entry_count--;                !! 247                         }
274         spin_unlock(&cache->c_list_lock);      !! 248                         spin_unlock(&cache->c_list_lock);
275         __mb_cache_entry_free(cache, entry);   !! 249                         mb_cache_entry_put(cache, entry);
276         return NULL;                           !! 250                         return;
                                                   >> 251                 }
                                                   >> 252         }
                                                   >> 253         hlist_bl_unlock(head);
277 }                                                 254 }
278 EXPORT_SYMBOL(mb_cache_entry_delete_or_get);   !! 255 EXPORT_SYMBOL(mb_cache_entry_delete);
279                                                   256 
280 /* mb_cache_entry_touch - cache entry got used    257 /* mb_cache_entry_touch - cache entry got used
281  * @cache - cache the entry belongs to            258  * @cache - cache the entry belongs to
282  * @entry - entry that got used                   259  * @entry - entry that got used
283  *                                                260  *
284  * Marks entry as used to give hit higher chan    261  * Marks entry as used to give hit higher chances of surviving in cache.
285  */                                               262  */
286 void mb_cache_entry_touch(struct mb_cache *cac    263 void mb_cache_entry_touch(struct mb_cache *cache,
287                           struct mb_cache_entr    264                           struct mb_cache_entry *entry)
288 {                                                 265 {
289         set_bit(MBE_REFERENCED_B, &entry->e_fl !! 266         entry->e_referenced = 1;
290 }                                                 267 }
291 EXPORT_SYMBOL(mb_cache_entry_touch);              268 EXPORT_SYMBOL(mb_cache_entry_touch);
292                                                   269 
293 static unsigned long mb_cache_count(struct shr    270 static unsigned long mb_cache_count(struct shrinker *shrink,
294                                     struct shr    271                                     struct shrink_control *sc)
295 {                                                 272 {
296         struct mb_cache *cache = shrink->priva !! 273         struct mb_cache *cache = container_of(shrink, struct mb_cache,
                                                   >> 274                                               c_shrink);
297                                                   275 
298         return cache->c_entry_count;              276         return cache->c_entry_count;
299 }                                                 277 }
300                                                   278 
301 /* Shrink number of entries in cache */           279 /* Shrink number of entries in cache */
302 static unsigned long mb_cache_shrink(struct mb    280 static unsigned long mb_cache_shrink(struct mb_cache *cache,
303                                      unsigned     281                                      unsigned long nr_to_scan)
304 {                                                 282 {
305         struct mb_cache_entry *entry;             283         struct mb_cache_entry *entry;
                                                   >> 284         struct hlist_bl_head *head;
306         unsigned long shrunk = 0;                 285         unsigned long shrunk = 0;
307                                                   286 
308         spin_lock(&cache->c_list_lock);           287         spin_lock(&cache->c_list_lock);
309         while (nr_to_scan-- && !list_empty(&ca    288         while (nr_to_scan-- && !list_empty(&cache->c_list)) {
310                 entry = list_first_entry(&cach    289                 entry = list_first_entry(&cache->c_list,
311                                          struc    290                                          struct mb_cache_entry, e_list);
312                 /* Drop initial hash reference !! 291                 if (entry->e_referenced) {
313                 if (test_bit(MBE_REFERENCED_B, !! 292                         entry->e_referenced = 0;
314                     atomic_cmpxchg(&entry->e_r << 
315                         clear_bit(MBE_REFERENC << 
316                         list_move_tail(&entry-    293                         list_move_tail(&entry->e_list, &cache->c_list);
317                         continue;                 294                         continue;
318                 }                                 295                 }
319                 list_del_init(&entry->e_list);    296                 list_del_init(&entry->e_list);
320                 cache->c_entry_count--;           297                 cache->c_entry_count--;
                                                   >> 298                 /*
                                                   >> 299                  * We keep LRU list reference so that entry doesn't go away
                                                   >> 300                  * from under us.
                                                   >> 301                  */
321                 spin_unlock(&cache->c_list_loc    302                 spin_unlock(&cache->c_list_lock);
322                 __mb_cache_entry_free(cache, e !! 303                 head = mb_cache_entry_head(cache, entry->e_key);
323                 shrunk++;                      !! 304                 hlist_bl_lock(head);
                                                   >> 305                 if (!hlist_bl_unhashed(&entry->e_hash_list)) {
                                                   >> 306                         hlist_bl_del_init(&entry->e_hash_list);
                                                   >> 307                         atomic_dec(&entry->e_refcnt);
                                                   >> 308                 }
                                                   >> 309                 hlist_bl_unlock(head);
                                                   >> 310                 if (mb_cache_entry_put(cache, entry))
                                                   >> 311                         shrunk++;
324                 cond_resched();                   312                 cond_resched();
325                 spin_lock(&cache->c_list_lock)    313                 spin_lock(&cache->c_list_lock);
326         }                                         314         }
327         spin_unlock(&cache->c_list_lock);         315         spin_unlock(&cache->c_list_lock);
328                                                   316 
329         return shrunk;                            317         return shrunk;
330 }                                                 318 }
331                                                   319 
332 static unsigned long mb_cache_scan(struct shri    320 static unsigned long mb_cache_scan(struct shrinker *shrink,
333                                    struct shri    321                                    struct shrink_control *sc)
334 {                                                 322 {
335         struct mb_cache *cache = shrink->priva !! 323         struct mb_cache *cache = container_of(shrink, struct mb_cache,
                                                   >> 324                                               c_shrink);
336         return mb_cache_shrink(cache, sc->nr_t    325         return mb_cache_shrink(cache, sc->nr_to_scan);
337 }                                                 326 }
338                                                   327 
339 /* We shrink 1/X of the cache when we have too    328 /* We shrink 1/X of the cache when we have too many entries in it */
340 #define SHRINK_DIVISOR 16                         329 #define SHRINK_DIVISOR 16
341                                                   330 
342 static void mb_cache_shrink_worker(struct work    331 static void mb_cache_shrink_worker(struct work_struct *work)
343 {                                                 332 {
344         struct mb_cache *cache = container_of(    333         struct mb_cache *cache = container_of(work, struct mb_cache,
345                                                   334                                               c_shrink_work);
346         mb_cache_shrink(cache, cache->c_max_en    335         mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR);
347 }                                                 336 }
348                                                   337 
349 /*                                                338 /*
350  * mb_cache_create - create cache                 339  * mb_cache_create - create cache
351  * @bucket_bits: log2 of the hash table size      340  * @bucket_bits: log2 of the hash table size
352  *                                                341  *
353  * Create cache for keys with 2^bucket_bits ha    342  * Create cache for keys with 2^bucket_bits hash entries.
354  */                                               343  */
355 struct mb_cache *mb_cache_create(int bucket_bi    344 struct mb_cache *mb_cache_create(int bucket_bits)
356 {                                                 345 {
357         struct mb_cache *cache;                   346         struct mb_cache *cache;
358         unsigned long bucket_count = 1UL << bu    347         unsigned long bucket_count = 1UL << bucket_bits;
359         unsigned long i;                          348         unsigned long i;
360                                                   349 
361         cache = kzalloc(sizeof(struct mb_cache    350         cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL);
362         if (!cache)                               351         if (!cache)
363                 goto err_out;                     352                 goto err_out;
364         cache->c_bucket_bits = bucket_bits;       353         cache->c_bucket_bits = bucket_bits;
365         cache->c_max_entries = bucket_count <<    354         cache->c_max_entries = bucket_count << 4;
366         INIT_LIST_HEAD(&cache->c_list);           355         INIT_LIST_HEAD(&cache->c_list);
367         spin_lock_init(&cache->c_list_lock);      356         spin_lock_init(&cache->c_list_lock);
368         cache->c_hash = kmalloc_array(bucket_c    357         cache->c_hash = kmalloc_array(bucket_count,
369                                       sizeof(s    358                                       sizeof(struct hlist_bl_head),
370                                       GFP_KERN    359                                       GFP_KERNEL);
371         if (!cache->c_hash) {                     360         if (!cache->c_hash) {
372                 kfree(cache);                     361                 kfree(cache);
373                 goto err_out;                     362                 goto err_out;
374         }                                         363         }
375         for (i = 0; i < bucket_count; i++)        364         for (i = 0; i < bucket_count; i++)
376                 INIT_HLIST_BL_HEAD(&cache->c_h    365                 INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
377                                                   366 
378         cache->c_shrink = shrinker_alloc(0, "m !! 367         cache->c_shrink.count_objects = mb_cache_count;
379         if (!cache->c_shrink) {                !! 368         cache->c_shrink.scan_objects = mb_cache_scan;
                                                   >> 369         cache->c_shrink.seeks = DEFAULT_SEEKS;
                                                   >> 370         if (register_shrinker(&cache->c_shrink)) {
380                 kfree(cache->c_hash);             371                 kfree(cache->c_hash);
381                 kfree(cache);                     372                 kfree(cache);
382                 goto err_out;                     373                 goto err_out;
383         }                                         374         }
384                                                   375 
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    376         INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
392                                                   377 
393         return cache;                             378         return cache;
394                                                   379 
395 err_out:                                          380 err_out:
396         return NULL;                              381         return NULL;
397 }                                                 382 }
398 EXPORT_SYMBOL(mb_cache_create);                   383 EXPORT_SYMBOL(mb_cache_create);
399                                                   384 
400 /*                                                385 /*
401  * mb_cache_destroy - destroy cache               386  * mb_cache_destroy - destroy cache
402  * @cache: the cache to destroy                   387  * @cache: the cache to destroy
403  *                                                388  *
404  * Free all entries in cache and cache itself.    389  * Free all entries in cache and cache itself. Caller must make sure nobody
405  * (except shrinker) can reach @cache when cal    390  * (except shrinker) can reach @cache when calling this.
406  */                                               391  */
407 void mb_cache_destroy(struct mb_cache *cache)     392 void mb_cache_destroy(struct mb_cache *cache)
408 {                                                 393 {
409         struct mb_cache_entry *entry, *next;      394         struct mb_cache_entry *entry, *next;
410                                                   395 
411         shrinker_free(cache->c_shrink);        !! 396         unregister_shrinker(&cache->c_shrink);
412                                                   397 
413         /*                                        398         /*
414          * We don't bother with any locking. C    399          * We don't bother with any locking. Cache must not be used at this
415          * point.                                 400          * point.
416          */                                       401          */
417         list_for_each_entry_safe(entry, next,     402         list_for_each_entry_safe(entry, next, &cache->c_list, e_list) {
                                                   >> 403                 if (!hlist_bl_unhashed(&entry->e_hash_list)) {
                                                   >> 404                         hlist_bl_del_init(&entry->e_hash_list);
                                                   >> 405                         atomic_dec(&entry->e_refcnt);
                                                   >> 406                 } else
                                                   >> 407                         WARN_ON(1);
418                 list_del(&entry->e_list);         408                 list_del(&entry->e_list);
419                 WARN_ON(atomic_read(&entry->e_    409                 WARN_ON(atomic_read(&entry->e_refcnt) != 1);
420                 mb_cache_entry_put(cache, entr    410                 mb_cache_entry_put(cache, entry);
421         }                                         411         }
422         kfree(cache->c_hash);                     412         kfree(cache->c_hash);
423         kfree(cache);                             413         kfree(cache);
424 }                                                 414 }
425 EXPORT_SYMBOL(mb_cache_destroy);                  415 EXPORT_SYMBOL(mb_cache_destroy);
426                                                   416 
427 static int __init mbcache_init(void)              417 static int __init mbcache_init(void)
428 {                                                 418 {
429         mb_entry_cache = KMEM_CACHE(mb_cache_e !! 419         mb_entry_cache = kmem_cache_create("mbcache",
                                                   >> 420                                 sizeof(struct mb_cache_entry), 0,
                                                   >> 421                                 SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
430         if (!mb_entry_cache)                      422         if (!mb_entry_cache)
431                 return -ENOMEM;                   423                 return -ENOMEM;
432         return 0;                                 424         return 0;
433 }                                                 425 }
434                                                   426 
435 static void __exit mbcache_exit(void)             427 static void __exit mbcache_exit(void)
436 {                                                 428 {
437         kmem_cache_destroy(mb_entry_cache);       429         kmem_cache_destroy(mb_entry_cache);
438 }                                                 430 }
439                                                   431 
440 module_init(mbcache_init)                         432 module_init(mbcache_init)
441 module_exit(mbcache_exit)                         433 module_exit(mbcache_exit)
442                                                   434 
443 MODULE_AUTHOR("Jan Kara <jack@suse.cz>");         435 MODULE_AUTHOR("Jan Kara <jack@suse.cz>");
444 MODULE_DESCRIPTION("Meta block cache (for exte    436 MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
445 MODULE_LICENSE("GPL");                            437 MODULE_LICENSE("GPL");
446                                                   438 

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