⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slab.c

📁 最新最稳定的Linux内存管理模块源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -