📄 slob.c
字号:
*/ if (node != -1 && page_to_nid(&sp->page) != node) continue;#endif /* Enough room on this page? */ if (sp->units < SLOB_UNITS(size)) continue; /* Attempt to alloc */ prev = sp->list.prev; b = slob_page_alloc(sp, size, align); if (!b) continue; /* Improve fragment distribution and reduce our average * search time by starting our next search here. (see * Knuth vol 1, sec 2.5, pg 449) */ if (prev != slob_list->prev && slob_list->next != prev->next) list_move_tail(slob_list, prev->next); break; } spin_unlock_irqrestore(&slob_lock, flags); /* Not enough space: must allocate a new page */ if (!b) { b = slob_new_page(gfp & ~__GFP_ZERO, 0, node); if (!b) return 0; sp = (struct slob_page *)virt_to_page(b); set_slob_page(sp); spin_lock_irqsave(&slob_lock, flags); sp->units = SLOB_UNITS(PAGE_SIZE); sp->free = b; INIT_LIST_HEAD(&sp->list); set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE)); set_slob_page_free(sp, slob_list); b = slob_page_alloc(sp, size, align); BUG_ON(!b); spin_unlock_irqrestore(&slob_lock, flags); } if (unlikely((gfp & __GFP_ZERO) && b)) memset(b, 0, size); return b;}/* * slob_free: entry point into the slob allocator. */static void slob_free(void *block, int size){ struct slob_page *sp; slob_t *prev, *next, *b = (slob_t *)block; slobidx_t units; unsigned long flags; if (unlikely(ZERO_OR_NULL_PTR(block))) return; BUG_ON(!size); sp = (struct slob_page *)virt_to_page(block); units = SLOB_UNITS(size); spin_lock_irqsave(&slob_lock, flags); if (sp->units + units == SLOB_UNITS(PAGE_SIZE)) { /* Go directly to page allocator. Do not pass slob allocator */ if (slob_page_free(sp)) clear_slob_page_free(sp); clear_slob_page(sp); free_slob_page(sp); free_page((unsigned long)b); goto out; } if (!slob_page_free(sp)) { /* This slob page is about to become partially free. Easy! */ sp->units = units; sp->free = b; set_slob(b, units, (void *)((unsigned long)(b + SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK)); set_slob_page_free(sp, &free_slob_small); goto out; } /* * Otherwise the page is already partially free, so find reinsertion * point. */ sp->units += units; if (b < sp->free) { if (b + units == sp->free) { units += slob_units(sp->free); sp->free = slob_next(sp->free); } set_slob(b, units, sp->free); sp->free = b; } else { prev = sp->free; next = slob_next(prev); while (b > next) { prev = next; next = slob_next(prev); } if (!slob_last(prev) && b + units == next) { units += slob_units(next); set_slob(b, units, slob_next(next)); } else set_slob(b, units, next); if (prev + slob_units(prev) == b) { units = slob_units(b) + slob_units(prev); set_slob(prev, units, slob_next(b)); } else set_slob(prev, slob_units(prev), b); }out: spin_unlock_irqrestore(&slob_lock, flags);}/* * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend. */#ifndef ARCH_KMALLOC_MINALIGN#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long)#endif#ifndef ARCH_SLAB_MINALIGN#define ARCH_SLAB_MINALIGN __alignof__(unsigned long)#endifvoid *__kmalloc_node(size_t size, gfp_t gfp, int node){ unsigned int *m; int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); if (size < PAGE_SIZE - align) { if (!size) return ZERO_SIZE_PTR; m = slob_alloc(size + align, gfp, align, node); if (!m) return NULL; *m = size; return (void *)m + align; } else { void *ret; ret = slob_new_page(gfp | __GFP_COMP, get_order(size), node); if (ret) { struct page *page; page = virt_to_page(ret); page->private = size; } return ret; }}EXPORT_SYMBOL(__kmalloc_node);void kfree(const void *block){ struct slob_page *sp; if (unlikely(ZERO_OR_NULL_PTR(block))) return; sp = (struct slob_page *)virt_to_page(block); if (slob_page(sp)) { int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); unsigned int *m = (unsigned int *)(block - align); slob_free(m, *m + align); } else put_page(&sp->page);}EXPORT_SYMBOL(kfree);/* can't use ksize for kmem_cache_alloc memory, only kmalloc */size_t ksize(const void *block){ struct slob_page *sp; BUG_ON(!block); if (unlikely(block == ZERO_SIZE_PTR)) return 0; sp = (struct slob_page *)virt_to_page(block); if (slob_page(sp)) { int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); unsigned int *m = (unsigned int *)(block - align); return SLOB_UNITS(*m) * SLOB_UNIT; } else return sp->page.private;}EXPORT_SYMBOL(ksize);struct kmem_cache { unsigned int size, align; unsigned long flags; const char *name; void (*ctor)(void *);};struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *)){ struct kmem_cache *c; c = slob_alloc(sizeof(struct kmem_cache), GFP_KERNEL, ARCH_KMALLOC_MINALIGN, -1); if (c) { c->name = name; c->size = size; if (flags & SLAB_DESTROY_BY_RCU) { /* leave room for rcu footer at the end of object */ c->size += sizeof(struct slob_rcu); } c->flags = flags; c->ctor = ctor; /* ignore alignment unless it's forced */ c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; if (c->align < ARCH_SLAB_MINALIGN) c->align = ARCH_SLAB_MINALIGN; if (c->align < align) c->align = align; } else if (flags & SLAB_PANIC) panic("Cannot create slab cache %s\n", name); return c;}EXPORT_SYMBOL(kmem_cache_create);void kmem_cache_destroy(struct kmem_cache *c){ slob_free(c, sizeof(struct kmem_cache));}EXPORT_SYMBOL(kmem_cache_destroy);void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node){ void *b; if (c->size < PAGE_SIZE) b = slob_alloc(c->size, flags, c->align, node); else b = slob_new_page(flags, get_order(c->size), node); if (c->ctor) c->ctor(b); return b;}EXPORT_SYMBOL(kmem_cache_alloc_node);static void __kmem_cache_free(void *b, int size){ if (size < PAGE_SIZE) slob_free(b, size); else free_pages((unsigned long)b, get_order(size));}static void kmem_rcu_free(struct rcu_head *head){ struct slob_rcu *slob_rcu = (struct slob_rcu *)head; void *b = (void *)slob_rcu - (slob_rcu->size - sizeof(struct slob_rcu)); __kmem_cache_free(b, slob_rcu->size);}void kmem_cache_free(struct kmem_cache *c, void *b){ if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) { struct slob_rcu *slob_rcu; slob_rcu = b + (c->size - sizeof(struct slob_rcu)); INIT_RCU_HEAD(&slob_rcu->head); slob_rcu->size = c->size; call_rcu(&slob_rcu->head, kmem_rcu_free); } else { __kmem_cache_free(b, c->size); }}EXPORT_SYMBOL(kmem_cache_free);unsigned int kmem_cache_size(struct kmem_cache *c){ return c->size;}EXPORT_SYMBOL(kmem_cache_size);const char *kmem_cache_name(struct kmem_cache *c){ return c->name;}EXPORT_SYMBOL(kmem_cache_name);int kmem_cache_shrink(struct kmem_cache *d){ return 0;}EXPORT_SYMBOL(kmem_cache_shrink);int kmem_ptr_validate(struct kmem_cache *a, const void *b){ return 0;}static unsigned int slob_ready __read_mostly;int slab_is_available(void){ return slob_ready;}void __init kmem_cache_init(void){ slob_ready = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -