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

TOMOYO Linux Cross Reference
Linux/mm/slob.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ 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.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * SLOB Allocator: Simple List Of Blocks
  4  *
  5  * Matt Mackall <mpm@selenic.com> 12/30/03
  6  *
  7  * NUMA support by Paul Mundt, 2007.
  8  *
  9  * How SLOB works:
 10  *
 11  * The core of SLOB is a traditional K&R style heap allocator, with
 12  * support for returning aligned objects. The granularity of this
 13  * allocator is as little as 2 bytes, however typically most architectures
 14  * will require 4 bytes on 32-bit and 8 bytes on 64-bit.
 15  *
 16  * The slob heap is a set of linked list of pages from alloc_pages(),
 17  * and within each page, there is a singly-linked list of free blocks
 18  * (slob_t). The heap is grown on demand. To reduce fragmentation,
 19  * heap pages are segregated into three lists, with objects less than
 20  * 256 bytes, objects less than 1024 bytes, and all other objects.
 21  *
 22  * Allocation from heap involves first searching for a page with
 23  * sufficient free blocks (using a next-fit-like approach) followed by
 24  * a first-fit scan of the page. Deallocation inserts objects back
 25  * into the free list in address order, so this is effectively an
 26  * address-ordered first fit.
 27  *
 28  * Above this is an implementation of kmalloc/kfree. Blocks returned
 29  * from kmalloc are prepended with a 4-byte header with the kmalloc size.
 30  * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
 31  * alloc_pages() directly, allocating compound pages so the page order
 32  * does not have to be separately tracked.
 33  * These objects are detected in kfree() because PageSlab()
 34  * is false for them.
 35  *
 36  * SLAB is emulated on top of SLOB by simply calling constructors and
 37  * destructors for every SLAB allocation. Objects are returned with the
 38  * 4-byte alignment unless the SLAB_HWCACHE_ALIGN flag is set, in which
 39  * case the low-level allocator will fragment blocks to create the proper
 40  * alignment. Again, objects of page-size or greater are allocated by
 41  * calling alloc_pages(). As SLAB objects know their size, no separate
 42  * size bookkeeping is necessary and there is essentially no allocation
 43  * space overhead, and compound pages aren't needed for multi-page
 44  * allocations.
 45  *
 46  * NUMA support in SLOB is fairly simplistic, pushing most of the real
 47  * logic down to the page allocator, and simply doing the node accounting
 48  * on the upper levels. In the event that a node id is explicitly
 49  * provided, __alloc_pages_node() with the specified node id is used
 50  * instead. The common case (or when the node id isn't explicitly provided)
 51  * will default to the current node, as per numa_node_id().
 52  *
 53  * Node aware pages are still inserted in to the global freelist, and
 54  * these are scanned for by matching against the node id encoded in the
 55  * page flags. As a result, block allocations that can be satisfied from
 56  * the freelist will only be done so on pages residing on the same node,
 57  * in order to prevent random node placement.
 58  */
 59 
 60 #include <linux/kernel.h>
 61 #include <linux/slab.h>
 62 
 63 #include <linux/mm.h>
 64 #include <linux/swap.h> /* struct reclaim_state */
 65 #include <linux/cache.h>
 66 #include <linux/init.h>
 67 #include <linux/export.h>
 68 #include <linux/rcupdate.h>
 69 #include <linux/list.h>
 70 #include <linux/kmemleak.h>
 71 
 72 #include <trace/events/kmem.h>
 73 
 74 #include <linux/atomic.h>
 75 
 76 #include "slab.h"
 77 /*
 78  * slob_block has a field 'units', which indicates size of block if +ve,
 79  * or offset of next block if -ve (in SLOB_UNITs).
 80  *
 81  * Free blocks of size 1 unit simply contain the offset of the next block.
 82  * Those with larger size contain their size in the first SLOB_UNIT of
 83  * memory, and the offset of the next free block in the second SLOB_UNIT.
 84  */
 85 #if PAGE_SIZE <= (32767 * 2)
 86 typedef s16 slobidx_t;
 87 #else
 88 typedef s32 slobidx_t;
 89 #endif
 90 
 91 struct slob_block {
 92         slobidx_t units;
 93 };
 94 typedef struct slob_block slob_t;
 95 
 96 /*
 97  * All partially free slob pages go on these lists.
 98  */
 99 #define SLOB_BREAK1 256
100 #define SLOB_BREAK2 1024
101 static LIST_HEAD(free_slob_small);
102 static LIST_HEAD(free_slob_medium);
103 static LIST_HEAD(free_slob_large);
104 
105 /*
106  * slob_page_free: true for pages on free_slob_pages list.
107  */
108 static inline int slob_page_free(struct page *sp)
109 {
110         return PageSlobFree(sp);
111 }
112 
113 static void set_slob_page_free(struct page *sp, struct list_head *list)
114 {
115         list_add(&sp->slab_list, list);
116         __SetPageSlobFree(sp);
117 }
118 
119 static inline void clear_slob_page_free(struct page *sp)
120 {
121         list_del(&sp->slab_list);
122         __ClearPageSlobFree(sp);
123 }
124 
125 #define SLOB_UNIT sizeof(slob_t)
126 #define SLOB_UNITS(size) DIV_ROUND_UP(size, SLOB_UNIT)
127 
128 /*
129  * struct slob_rcu is inserted at the tail of allocated slob blocks, which
130  * were created with a SLAB_TYPESAFE_BY_RCU slab. slob_rcu is used to free
131  * the block using call_rcu.
132  */
133 struct slob_rcu {
134         struct rcu_head head;
135         int size;
136 };
137 
138 /*
139  * slob_lock protects all slob allocator structures.
140  */
141 static DEFINE_SPINLOCK(slob_lock);
142 
143 /*
144  * Encode the given size and next info into a free slob block s.
145  */
146 static void set_slob(slob_t *s, slobidx_t size, slob_t *next)
147 {
148         slob_t *base = (slob_t *)((unsigned long)s & PAGE_MASK);
149         slobidx_t offset = next - base;
150 
151         if (size > 1) {
152                 s[0].units = size;
153                 s[1].units = offset;
154         } else
155                 s[0].units = -offset;
156 }
157 
158 /*
159  * Return the size of a slob block.
160  */
161 static slobidx_t slob_units(slob_t *s)
162 {
163         if (s->units > 0)
164                 return s->units;
165         return 1;
166 }
167 
168 /*
169  * Return the next free slob block pointer after this one.
170  */
171 static slob_t *slob_next(slob_t *s)
172 {
173         slob_t *base = (slob_t *)((unsigned long)s & PAGE_MASK);
174         slobidx_t next;
175 
176         if (s[0].units < 0)
177                 next = -s[0].units;
178         else
179                 next = s[1].units;
180         return base+next;
181 }
182 
183 /*
184  * Returns true if s is the last free block in its page.
185  */
186 static int slob_last(slob_t *s)
187 {
188         return !((unsigned long)slob_next(s) & ~PAGE_MASK);
189 }
190 
191 static void *slob_new_pages(gfp_t gfp, int order, int node)
192 {
193         void *page;
194 
195 #ifdef CONFIG_NUMA
196         if (node != NUMA_NO_NODE)
197                 page = __alloc_pages_node(node, gfp, order);
198         else
199 #endif
200                 page = alloc_pages(gfp, order);
201 
202         if (!page)
203                 return NULL;
204 
205         return page_address(page);
206 }
207 
208 static void slob_free_pages(void *b, int order)
209 {
210         if (current->reclaim_state)
211                 current->reclaim_state->reclaimed_slab += 1 << order;
212         free_pages((unsigned long)b, order);
213 }
214 
215 /*
216  * slob_page_alloc() - Allocate a slob block within a given slob_page sp.
217  * @sp: Page to look in.
218  * @size: Size of the allocation.
219  * @align: Allocation alignment.
220  * @page_removed_from_list: Return parameter.
221  *
222  * Tries to find a chunk of memory at least @size bytes big within @page.
223  *
224  * Return: Pointer to memory if allocated, %NULL otherwise.  If the
225  *         allocation fills up @page then the page is removed from the
226  *         freelist, in this case @page_removed_from_list will be set to
227  *         true (set to false otherwise).
228  */
229 static void *slob_page_alloc(struct page *sp, size_t size, int align,
230                              bool *page_removed_from_list)
231 {
232         slob_t *prev, *cur, *aligned = NULL;
233         int delta = 0, units = SLOB_UNITS(size);
234 
235         *page_removed_from_list = false;
236         for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
237                 slobidx_t avail = slob_units(cur);
238 
239                 if (align) {
240                         aligned = (slob_t *)ALIGN((unsigned long)cur, align);
241                         delta = aligned - cur;
242                 }
243                 if (avail >= units + delta) { /* room enough? */
244                         slob_t *next;
245 
246                         if (delta) { /* need to fragment head to align? */
247                                 next = slob_next(cur);
248                                 set_slob(aligned, avail - delta, next);
249                                 set_slob(cur, delta, aligned);
250                                 prev = cur;
251                                 cur = aligned;
252                                 avail = slob_units(cur);
253                         }
254 
255                         next = slob_next(cur);
256                         if (avail == units) { /* exact fit? unlink. */
257                                 if (prev)
258                                         set_slob(prev, slob_units(prev), next);
259                                 else
260                                         sp->freelist = next;
261                         } else { /* fragment */
262                                 if (prev)
263                                         set_slob(prev, slob_units(prev), cur + units);
264                                 else
265                                         sp->freelist = cur + units;
266                                 set_slob(cur + units, avail - units, next);
267                         }
268 
269                         sp->units -= units;
270                         if (!sp->units) {
271                                 clear_slob_page_free(sp);
272                                 *page_removed_from_list = true;
273                         }
274                         return cur;
275                 }
276                 if (slob_last(cur))
277                         return NULL;
278         }
279 }
280 
281 /*
282  * slob_alloc: entry point into the slob allocator.
283  */
284 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
285 {
286         struct page *sp;
287         struct list_head *slob_list;
288         slob_t *b = NULL;
289         unsigned long flags;
290         bool _unused;
291 
292         if (size < SLOB_BREAK1)
293                 slob_list = &free_slob_small;
294         else if (size < SLOB_BREAK2)
295                 slob_list = &free_slob_medium;
296         else
297                 slob_list = &free_slob_large;
298 
299         spin_lock_irqsave(&slob_lock, flags);
300         /* Iterate through each partially free page, try to find room */
301         list_for_each_entry(sp, slob_list, slab_list) {
302                 bool page_removed_from_list = false;
303 #ifdef CONFIG_NUMA
304                 /*
305                  * If there's a node specification, search for a partial
306                  * page with a matching node id in the freelist.
307                  */
308                 if (node != NUMA_NO_NODE && page_to_nid(sp) != node)
309                         continue;
310 #endif
311                 /* Enough room on this page? */
312                 if (sp->units < SLOB_UNITS(size))
313                         continue;
314 
315                 b = slob_page_alloc(sp, size, align, &page_removed_from_list);
316                 if (!b)
317                         continue;
318 
319                 /*
320                  * If slob_page_alloc() removed sp from the list then we
321                  * cannot call list functions on sp.  If so allocation
322                  * did not fragment the page anyway so optimisation is
323                  * unnecessary.
324                  */
325                 if (!page_removed_from_list) {
326                         /*
327                          * Improve fragment distribution and reduce our average
328                          * search time by starting our next search here. (see
329                          * Knuth vol 1, sec 2.5, pg 449)
330                          */
331                         if (!list_is_first(&sp->slab_list, slob_list))
332                                 list_rotate_to_front(&sp->slab_list, slob_list);
333                 }
334                 break;
335         }
336         spin_unlock_irqrestore(&slob_lock, flags);
337 
338         /* Not enough space: must allocate a new page */
339         if (!b) {
340                 b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
341                 if (!b)
342                         return NULL;
343                 sp = virt_to_page(b);
344                 __SetPageSlab(sp);
345 
346                 spin_lock_irqsave(&slob_lock, flags);
347                 sp->units = SLOB_UNITS(PAGE_SIZE);
348                 sp->freelist = b;
349                 INIT_LIST_HEAD(&sp->slab_list);
350                 set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
351                 set_slob_page_free(sp, slob_list);
352                 b = slob_page_alloc(sp, size, align, &_unused);
353                 BUG_ON(!b);
354                 spin_unlock_irqrestore(&slob_lock, flags);
355         }
356         if (unlikely(gfp & __GFP_ZERO))
357                 memset(b, 0, size);
358         return b;
359 }
360 
361 /*
362  * slob_free: entry point into the slob allocator.
363  */
364 static void slob_free(void *block, int size)
365 {
366         struct page *sp;
367         slob_t *prev, *next, *b = (slob_t *)block;
368         slobidx_t units;
369         unsigned long flags;
370         struct list_head *slob_list;
371 
372         if (unlikely(ZERO_OR_NULL_PTR(block)))
373                 return;
374         BUG_ON(!size);
375 
376         sp = virt_to_page(block);
377         units = SLOB_UNITS(size);
378 
379         spin_lock_irqsave(&slob_lock, flags);
380 
381         if (sp->units + units == SLOB_UNITS(PAGE_SIZE)) {
382                 /* Go directly to page allocator. Do not pass slob allocator */
383                 if (slob_page_free(sp))
384                         clear_slob_page_free(sp);
385                 spin_unlock_irqrestore(&slob_lock, flags);
386                 __ClearPageSlab(sp);
387                 page_mapcount_reset(sp);
388                 slob_free_pages(b, 0);
389                 return;
390         }
391 
392         if (!slob_page_free(sp)) {
393                 /* This slob page is about to become partially free. Easy! */
394                 sp->units = units;
395                 sp->freelist = b;
396                 set_slob(b, units,
397                         (void *)((unsigned long)(b +
398                                         SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
399                 if (size < SLOB_BREAK1)
400                         slob_list = &free_slob_small;
401                 else if (size < SLOB_BREAK2)
402                         slob_list = &free_slob_medium;
403                 else
404                         slob_list = &free_slob_large;
405                 set_slob_page_free(sp, slob_list);
406                 goto out;
407         }
408 
409         /*
410          * Otherwise the page is already partially free, so find reinsertion
411          * point.
412          */
413         sp->units += units;
414 
415         if (b < (slob_t *)sp->freelist) {
416                 if (b + units == sp->freelist) {
417                         units += slob_units(sp->freelist);
418                         sp->freelist = slob_next(sp->freelist);
419                 }
420                 set_slob(b, units, sp->freelist);
421                 sp->freelist = b;
422         } else {
423                 prev = sp->freelist;
424                 next = slob_next(prev);
425                 while (b > next) {
426                         prev = next;
427                         next = slob_next(prev);
428                 }
429 
430                 if (!slob_last(prev) && b + units == next) {
431                         units += slob_units(next);
432                         set_slob(b, units, slob_next(next));
433                 } else
434                         set_slob(b, units, next);
435 
436                 if (prev + slob_units(prev) == b) {
437                         units = slob_units(b) + slob_units(prev);
438                         set_slob(prev, units, slob_next(b));
439                 } else
440                         set_slob(prev, slob_units(prev), b);
441         }
442 out:
443         spin_unlock_irqrestore(&slob_lock, flags);
444 }
445 
446 /*
447  * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend.
448  */
449 
450 static __always_inline void *
451 __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
452 {
453         unsigned int *m;
454         int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
455         void *ret;
456 
457         gfp &= gfp_allowed_mask;
458 
459         fs_reclaim_acquire(gfp);
460         fs_reclaim_release(gfp);
461 
462         if (size < PAGE_SIZE - align) {
463                 if (!size)
464                         return ZERO_SIZE_PTR;
465 
466                 m = slob_alloc(size + align, gfp, align, node);
467 
468                 if (!m)
469                         return NULL;
470                 *m = size;
471                 ret = (void *)m + align;
472 
473                 trace_kmalloc_node(caller, ret,
474                                    size, size + align, gfp, node);
475         } else {
476                 unsigned int order = get_order(size);
477 
478                 if (likely(order))
479                         gfp |= __GFP_COMP;
480                 ret = slob_new_pages(gfp, order, node);
481 
482                 trace_kmalloc_node(caller, ret,
483                                    size, PAGE_SIZE << order, gfp, node);
484         }
485 
486         kmemleak_alloc(ret, size, 1, gfp);
487         return ret;
488 }
489 
490 void *__kmalloc(size_t size, gfp_t gfp)
491 {
492         return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, _RET_IP_);
493 }
494 EXPORT_SYMBOL(__kmalloc);
495 
496 void *__kmalloc_track_caller(size_t size, gfp_t gfp, unsigned long caller)
497 {
498         return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, caller);
499 }
500 
501 #ifdef CONFIG_NUMA
502 void *__kmalloc_node_track_caller(size_t size, gfp_t gfp,
503                                         int node, unsigned long caller)
504 {
505         return __do_kmalloc_node(size, gfp, node, caller);
506 }
507 #endif
508 
509 void kfree(const void *block)
510 {
511         struct page *sp;
512 
513         trace_kfree(_RET_IP_, block);
514 
515         if (unlikely(ZERO_OR_NULL_PTR(block)))
516                 return;
517         kmemleak_free(block);
518 
519         sp = virt_to_page(block);
520         if (PageSlab(sp)) {
521                 int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
522                 unsigned int *m = (unsigned int *)(block - align);
523                 slob_free(m, *m + align);
524         } else
525                 __free_pages(sp, compound_order(sp));
526 }
527 EXPORT_SYMBOL(kfree);
528 
529 /* can't use ksize for kmem_cache_alloc memory, only kmalloc */
530 size_t __ksize(const void *block)
531 {
532         struct page *sp;
533         int align;
534         unsigned int *m;
535 
536         BUG_ON(!block);
537         if (unlikely(block == ZERO_SIZE_PTR))
538                 return 0;
539 
540         sp = virt_to_page(block);
541         if (unlikely(!PageSlab(sp)))
542                 return PAGE_SIZE << compound_order(sp);
543 
544         align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
545         m = (unsigned int *)(block - align);
546         return SLOB_UNITS(*m) * SLOB_UNIT;
547 }
548 EXPORT_SYMBOL(__ksize);
549 
550 int __kmem_cache_create(struct kmem_cache *c, slab_flags_t flags)
551 {
552         if (flags & SLAB_TYPESAFE_BY_RCU) {
553                 /* leave room for rcu footer at the end of object */
554                 c->size += sizeof(struct slob_rcu);
555         }
556         c->flags = flags;
557         return 0;
558 }
559 
560 static void *slob_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
561 {
562         void *b;
563 
564         flags &= gfp_allowed_mask;
565 
566         fs_reclaim_acquire(flags);
567         fs_reclaim_release(flags);
568 
569         if (c->size < PAGE_SIZE) {
570                 b = slob_alloc(c->size, flags, c->align, node);
571                 trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
572                                             SLOB_UNITS(c->size) * SLOB_UNIT,
573                                             flags, node);
574         } else {
575                 b = slob_new_pages(flags, get_order(c->size), node);
576                 trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
577                                             PAGE_SIZE << get_order(c->size),
578                                             flags, node);
579         }
580 
581         if (b && c->ctor) {
582                 WARN_ON_ONCE(flags & __GFP_ZERO);
583                 c->ctor(b);
584         }
585 
586         kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags);
587         return b;
588 }
589 
590 void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
591 {
592         return slob_alloc_node(cachep, flags, NUMA_NO_NODE);
593 }
594 EXPORT_SYMBOL(kmem_cache_alloc);
595 
596 #ifdef CONFIG_NUMA
597 void *__kmalloc_node(size_t size, gfp_t gfp, int node)
598 {
599         return __do_kmalloc_node(size, gfp, node, _RET_IP_);
600 }
601 EXPORT_SYMBOL(__kmalloc_node);
602 
603 void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t gfp, int node)
604 {
605         return slob_alloc_node(cachep, gfp, node);
606 }
607 EXPORT_SYMBOL(kmem_cache_alloc_node);
608 #endif
609 
610 static void __kmem_cache_free(void *b, int size)
611 {
612         if (size < PAGE_SIZE)
613                 slob_free(b, size);
614         else
615                 slob_free_pages(b, get_order(size));
616 }
617 
618 static void kmem_rcu_free(struct rcu_head *head)
619 {
620         struct slob_rcu *slob_rcu = (struct slob_rcu *)head;
621         void *b = (void *)slob_rcu - (slob_rcu->size - sizeof(struct slob_rcu));
622 
623         __kmem_cache_free(b, slob_rcu->size);
624 }
625 
626 void kmem_cache_free(struct kmem_cache *c, void *b)
627 {
628         kmemleak_free_recursive(b, c->flags);
629         if (unlikely(c->flags & SLAB_TYPESAFE_BY_RCU)) {
630                 struct slob_rcu *slob_rcu;
631                 slob_rcu = b + (c->size - sizeof(struct slob_rcu));
632                 slob_rcu->size = c->size;
633                 call_rcu(&slob_rcu->head, kmem_rcu_free);
634         } else {
635                 __kmem_cache_free(b, c->size);
636         }
637 
638         trace_kmem_cache_free(_RET_IP_, b);
639 }
640 EXPORT_SYMBOL(kmem_cache_free);
641 
642 void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
643 {
644         __kmem_cache_free_bulk(s, size, p);
645 }
646 EXPORT_SYMBOL(kmem_cache_free_bulk);
647 
648 int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
649                                                                 void **p)
650 {
651         return __kmem_cache_alloc_bulk(s, flags, size, p);
652 }
653 EXPORT_SYMBOL(kmem_cache_alloc_bulk);
654 
655 int __kmem_cache_shutdown(struct kmem_cache *c)
656 {
657         /* No way to check for remaining objects */
658         return 0;
659 }
660 
661 void __kmem_cache_release(struct kmem_cache *c)
662 {
663 }
664 
665 int __kmem_cache_shrink(struct kmem_cache *d)
666 {
667         return 0;
668 }
669 
670 struct kmem_cache kmem_cache_boot = {
671         .name = "kmem_cache",
672         .size = sizeof(struct kmem_cache),
673         .flags = SLAB_PANIC,
674         .align = ARCH_KMALLOC_MINALIGN,
675 };
676 
677 void __init kmem_cache_init(void)
678 {
679         kmem_cache = &kmem_cache_boot;
680         slab_state = UP;
681 }
682 
683 void __init kmem_cache_init_late(void)
684 {
685         slab_state = FULL;
686 }
687 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp