📄 slab.c
字号:
int node; if (num_possible_nodes() == 1) { use_alien_caches = 0; numa_platform = 0; } for (i = 0; i < NUM_INIT_LISTS; i++) { kmem_list3_init(&initkmem_list3[i]); if (i < MAX_NUMNODES) cache_cache.nodelists[i] = NULL; } set_up_list3s(&cache_cache, CACHE_CACHE); /* * Fragmentation resistance on low memory - only use bigger * page orders on machines with more than 32MB of memory. */ if (num_physpages > (32 << 20) >> PAGE_SHIFT) slab_break_gfp_order = BREAK_GFP_ORDER_HI; /* Bootstrap is tricky, because several objects are allocated * from caches that do not exist yet: * 1) initialize the cache_cache cache: it contains the struct * kmem_cache structures of all caches, except cache_cache itself: * cache_cache is statically allocated. * Initially an __init data area is used for the head array and the * kmem_list3 structures, it's replaced with a kmalloc allocated * array at the end of the bootstrap. * 2) Create the first kmalloc cache. * The struct kmem_cache for the new cache is allocated normally. * An __init data area is used for the head array. * 3) Create the remaining kmalloc caches, with minimally sized * head arrays. * 4) Replace the __init data head arrays for cache_cache and the first * kmalloc cache with kmalloc allocated arrays. * 5) Replace the __init data for kmem_list3 for cache_cache and * the other cache's with kmalloc allocated memory. * 6) Resize the head arrays of the kmalloc caches to their final sizes. */ node = numa_node_id(); /* 1) create the cache_cache */ INIT_LIST_HEAD(&cache_chain); list_add(&cache_cache.next, &cache_chain); cache_cache.colour_off = cache_line_size(); cache_cache.array[smp_processor_id()] = &initarray_cache.cache; cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node]; /* * struct kmem_cache size depends on nr_node_ids, which * can be less than MAX_NUMNODES. */ cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) + nr_node_ids * sizeof(struct kmem_list3 *);#if DEBUG cache_cache.obj_size = cache_cache.buffer_size;#endif cache_cache.buffer_size = ALIGN(cache_cache.buffer_size, cache_line_size()); cache_cache.reciprocal_buffer_size = reciprocal_value(cache_cache.buffer_size); for (order = 0; order < MAX_ORDER; order++) { cache_estimate(order, cache_cache.buffer_size, cache_line_size(), 0, &left_over, &cache_cache.num); if (cache_cache.num) break; } BUG_ON(!cache_cache.num); cache_cache.gfporder = order; cache_cache.colour = left_over / cache_cache.colour_off; cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) + sizeof(struct slab), cache_line_size()); /* 2+3) create the kmalloc caches */ sizes = malloc_sizes; names = cache_names; /* * Initialize the caches that provide memory for the array cache and the * kmem_list3 structures first. Without this, further allocations will * bug. */ sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name, sizes[INDEX_AC].cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, NULL); if (INDEX_AC != INDEX_L3) { sizes[INDEX_L3].cs_cachep = kmem_cache_create(names[INDEX_L3].name, sizes[INDEX_L3].cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, NULL); } slab_early_init = 0; while (sizes->cs_size != ULONG_MAX) { /* * For performance, all the general caches are L1 aligned. * This should be particularly beneficial on SMP boxes, as it * eliminates "false sharing". * Note for systems short on memory removing the alignment will * allow tighter packing of the smaller caches. */ if (!sizes->cs_cachep) { sizes->cs_cachep = kmem_cache_create(names->name, sizes->cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, NULL); }#ifdef CONFIG_ZONE_DMA sizes->cs_dmacachep = kmem_cache_create( names->name_dma, sizes->cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC, NULL);#endif sizes++; names++; } /* 4) Replace the bootstrap head arrays */ { struct array_cache *ptr; ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); local_irq_disable(); BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache); memcpy(ptr, cpu_cache_get(&cache_cache), sizeof(struct arraycache_init)); /* * Do not assume that spinlocks can be initialized via memcpy: */ spin_lock_init(&ptr->lock); cache_cache.array[smp_processor_id()] = ptr; local_irq_enable(); ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); local_irq_disable(); BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep) != &initarray_generic.cache); memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep), sizeof(struct arraycache_init)); /* * Do not assume that spinlocks can be initialized via memcpy: */ spin_lock_init(&ptr->lock); malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = ptr; local_irq_enable(); } /* 5) Replace the bootstrap kmem_list3's */ { int nid; for_each_online_node(nid) { init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid); init_list(malloc_sizes[INDEX_AC].cs_cachep, &initkmem_list3[SIZE_AC + nid], nid); if (INDEX_AC != INDEX_L3) { init_list(malloc_sizes[INDEX_L3].cs_cachep, &initkmem_list3[SIZE_L3 + nid], nid); } } } /* 6) resize the head arrays to their final sizes */ { struct kmem_cache *cachep; mutex_lock(&cache_chain_mutex); list_for_each_entry(cachep, &cache_chain, next) if (enable_cpucache(cachep)) BUG(); mutex_unlock(&cache_chain_mutex); } /* Annotate slab for lockdep -- annotate the malloc caches */ init_lock_keys(); /* Done! */ g_cpucache_up = FULL; /* * Register a cpu startup notifier callback that initializes * cpu_cache_get for all new cpus */ register_cpu_notifier(&cpucache_notifier); /* * The reap timers are started later, with a module init call: That part * of the kernel is not yet operational. */}static int __init cpucache_init(void){ int cpu; /* * Register the timers that return unneeded pages to the page allocator */ for_each_online_cpu(cpu) start_cpu_timer(cpu); return 0;}__initcall(cpucache_init);/* * Interface to system's page allocator. No need to hold the cache-lock. * * If we requested dmaable memory, we will get it. Even if we * did not request dmaable memory, we might get it, but that * would be relatively rare and ignorable. */static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid){ struct page *page; int nr_pages; int i;#ifndef CONFIG_MMU /* * Nommu uses slab's for process anonymous memory allocations, and thus * requires __GFP_COMP to properly refcount higher order allocations */ flags |= __GFP_COMP;#endif flags |= cachep->gfpflags; if (cachep->flags & SLAB_RECLAIM_ACCOUNT) flags |= __GFP_RECLAIMABLE; page = alloc_pages_node(nodeid, flags, cachep->gfporder); if (!page) return NULL; nr_pages = (1 << cachep->gfporder); if (cachep->flags & SLAB_RECLAIM_ACCOUNT) add_zone_page_state(page_zone(page), NR_SLAB_RECLAIMABLE, nr_pages); else add_zone_page_state(page_zone(page), NR_SLAB_UNRECLAIMABLE, nr_pages); for (i = 0; i < nr_pages; i++) __SetPageSlab(page + i); return page_address(page);}/* * Interface to system's page release. */static void kmem_freepages(struct kmem_cache *cachep, void *addr){ unsigned long i = (1 << cachep->gfporder); struct page *page = virt_to_page(addr); const unsigned long nr_freed = i; if (cachep->flags & SLAB_RECLAIM_ACCOUNT) sub_zone_page_state(page_zone(page), NR_SLAB_RECLAIMABLE, nr_freed); else sub_zone_page_state(page_zone(page), NR_SLAB_UNRECLAIMABLE, nr_freed); while (i--) { BUG_ON(!PageSlab(page)); __ClearPageSlab(page); page++; } if (current->reclaim_state) current->reclaim_state->reclaimed_slab += nr_freed; free_pages((unsigned long)addr, cachep->gfporder);}static void kmem_rcu_free(struct rcu_head *head){ struct slab_rcu *slab_rcu = (struct slab_rcu *)head; struct kmem_cache *cachep = slab_rcu->cachep; kmem_freepages(cachep, slab_rcu->addr); if (OFF_SLAB(cachep)) kmem_cache_free(cachep->slabp_cache, slab_rcu);}#if DEBUG#ifdef CONFIG_DEBUG_PAGEALLOCstatic void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr, unsigned long caller){ int size = obj_size(cachep); addr = (unsigned long *)&((char *)addr)[obj_offset(cachep)]; if (size < 5 * sizeof(unsigned long)) return; *addr++ = 0x12345678; *addr++ = caller; *addr++ = smp_processor_id(); size -= 3 * sizeof(unsigned long); { unsigned long *sptr = &caller; unsigned long svalue; while (!kstack_end(sptr)) { svalue = *sptr++; if (kernel_text_address(svalue)) { *addr++ = svalue; size -= sizeof(unsigned long); if (size <= sizeof(unsigned long)) break; } } } *addr++ = 0x87654321;}#endifstatic void poison_obj(struct kmem_cache *cachep, void *addr, unsigned char val){ int size = obj_size(cachep); addr = &((char *)addr)[obj_offset(cachep)]; memset(addr, val, size); *(unsigned char *)(addr + size - 1) = POISON_END;}static void dump_line(char *data, int offset, int limit){ int i; unsigned char error = 0; int bad_count = 0; printk(KERN_ERR "%03x:", offset); for (i = 0; i < limit; i++) { if (data[offset + i] != POISON_FREE) { error = data[offset + i]; bad_count++; } printk(" %02x", (unsigned char)data[offset + i]); } printk("\n"); if (bad_count == 1) { error ^= POISON_FREE; if (!(error & (error - 1))) { printk(KERN_ERR "Single bit error detected. Probably " "bad RAM.\n");#ifdef CONFIG_X86 printk(KERN_ERR "Run memtest86+ or a similar memory " "test tool.\n");#else printk(KERN_ERR "Run a memory test tool.\n");#endif } }}#endif#if DEBUGstatic void print_objinfo(struct kmem_cache *cachep, void *objp, int lines){ int i, size; char *realobj; if (cachep->flags & SLAB_RED_ZONE) { printk(KERN_ERR "Redzone: 0x%llx/0x%llx.\n", *dbg_redzone1(cachep, objp), *dbg_redzone2(cachep, objp)); } if (cachep->flags & SLAB_STORE_USER) { printk(KERN_ERR "Last user: [<%p>]", *dbg_userword(cachep, objp)); print_symbol("(%s)", (unsigned long)*dbg_userword(cachep, objp)); printk("\n"); } realobj = (char *)objp + obj_offset(cachep); size = obj_size(cachep); for (i = 0; i < size && lines; i += 16, lines--) { int limit; limit = 16; if (i + limit > size) limit = size - i; dump_line(realobj, i, limit); }}static void check_poison_obj(struct kmem_cache *cachep, void *objp){ char *realobj; int size, i; int lines = 0; realobj = (char *)objp + obj_offset(cachep); size = obj_size(cachep); for (i = 0; i < size; i++) { char exp = POISON_FREE; if (i == size - 1) exp = POISON_END; if (realobj[i] != exp) { int limit; /* Mismatch ! */ /* Print header */ if (lines == 0) { printk(KERN_ERR "Slab corruption: %s start=%p, len=%d\n", cachep->name, realobj, size); print_objinfo(cachep, objp, 0); } /* Hexdump the affected line */ i = (i / 16) * 16; limit = 16; if (i + limit > size) limit = size - i; dump_line(realobj, i, limit); i += 16; lines++; /* Limit to 5 lines */ if (lines > 5) break; } } if (lines != 0) { /* Print some data about the neighboring objects, if they * exist: */ struct slab *slabp = virt_to_slab(objp); unsigned int objnr; objnr = obj_to_index(cachep, slabp, objp); if (objnr) { objp = index_to_obj(cachep, slabp, objnr - 1); realobj = (char *)objp + obj_offset(cachep); printk(KERN_ERR "Prev obj: start=%p, len=%d\n", realobj, size); print_objinfo(cachep, objp, 2); } if (objnr + 1 < cachep->num) { objp = index_to_obj(cachep, slabp, objnr + 1); realobj = (char *)objp + obj_offset(cachep); printk(KERN_ERR "Next obj: start=%p, len=%d\n", realobj, size); print_objinfo(cachep, objp, 2); } }}#endif#if DEBUGstatic void slab_destroy_debugcheck(struct kmem_cache *cachep, struct slab *slabp){ int i; for (i = 0; i < cachep->num; i++) { void *objp = index_to_obj(cachep, slabp, i); if (cachep->flags & SLAB_POISON) {#ifdef CONFIG_DEBUG_PAGEALLOC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -