Create Slab mainly by the function Cache_grow () implementation, when the following two conditions are met, the slab allocator will create a new slab for the cache
1. Request allocation object, but local cache no free objects can be allocated, need to populate
2.kmem_list3 maintained lists are not slab or all slab are in the full list
Photo from: http://blog.csdn.net/vanbreaker/article/details/7673372
- /* Create an empty slab with one or more pages.
- OBJP: page virtual address, NULL indicates not yet requested memory page, not empty
- , which indicates that a memory page has been requested and can be directly used to create slab*/
/* * Grow (by 1) The number of slabs within a cache. This was called by * KMEM_CACHE_ALLOC () when there was no active OBJS left in a cache. */static int Cache_grow (struct kmem_cache *cachep,gfp_t flags, int nodeid, void *objp) {struct Slab *slabp;size_t OFFSET;GF p_t local_flags;struct kmem_list3 *l3;/* * be-lazy and only check for valid flags here, keeping it out of the * critical Path in Kmem_cache_alloc (). */BUG_ON (Flags & gfp_slab_bug_mask); local_flags = Flags & (gfp_constraint_mask| Gfp_reclaim_mask);/* Take the L3 list lock to change the Colour_next on this node */check_irq_off (); l3 = Cachep->nodeli sts[nodeid];/* obtains the slab three chains of this memory node */ spin_lock (&l3->list_lock);/* get colour for the slab, and cal the next value . */offset = l3->colour_next;/* Determines the color number of the slab to be created, that is, the shading offset */ l3->colour_next++; /* updates the shaded area offset so that different slab shading offsets are different */ if (l3->colour_next >= cachep->colour) /* Color number must be less than color number */ l3->colour_next = 0;spin_ Unlock (&l3->list_lockOffset *= cachep->colour_off;/* Converts the number of shading unit intervals to the shaded area size that determines the color of the slab to be created */ if (Local_flags & __gfp_wait) Local_irq_enable ();/* The test for missing atomic flag was performed here, rather than * the more obvious place, simply T o Reduce the critical path length * in Kmem_cache_alloc (). If a caller is seriously mis-behaving they * would eventually be caught here (where it matters). */kmem_flagcheck (Cachep, flags); */* Get mem for the OBJS. Attempt to allocate a physical page from * ' Nodeid '. */if (!OBJP) /* assign a page box from the partner system, which is the interface of the slab allocator with the partner system <span style= "White-space:pre" ></span> allocated from this memory node 1 <<cachep->gfporder page &NBSP;,OBJP is the virtual address of the Slab first page */&NBSP;OBJP = kmem_getpages (Cachep, Local_flags, Nodeid); if (!OBJP) goto failed;/* Get Slab Management. */* Assign Slab Management Objects */&NBSP;SLABP = ALLOC_SLABMGMT (Cachep, OBJP, Offset,local_flags & ~gfp_constraint_mask, Nodeid); SLABP) goto Opps1;<span style= "White-space:pre" ></span>slab_map_pages (Cachep, SLABP, OBJP); /* set the page-to-cache, slab mapping to facilitate quick positioning of the slab descriptor and the cache descriptor by obj */&NBSP;CACHE_INIT_OBJS (Cachep, SLABP);/* Initialize the Slab object */ if (Local_flags & __gfp_wait) local_irq_disable (); Check_irq_off (); Spin_lock (&l3->list_ lock);/* Make slab active. */list_add_tail (&slabp->list, & (L3->slabs_free)) /* Add the newly created slab to the free list */ stats_inc_ Grown (Cachep); L3->free_objects + = Cachep->num;spin_unlock (&l3->list_lock); return 1;opps1:kmem_ Freepages (Cachep, OBJP); Failed:if (Local_flags & __gfp_wait) local_irq_disable (); return 0;
Assigning a page box to a slab
/* * Interface to System ' s page allocator. No need to the cache-lock. * * IF We requested dmaable memory, we'll get it. Even if we do not have request dmaable memory, we might get it, but that * would is 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; #ifnde F config_mmu/* * Nommu uses slab ' s for process anonymous memory allocations, and thus * requires __gfp_comp to properly re Fcount Higher order allocations */flags |= __gfp_comp; #endifflags |= cachep->gfpflags;if (Cachep->flags & SLAB_ Reclaim_account) Flags |= __gfp_reclaimable;/* assigns 2^gfporder contiguous pages from a specific node */page = Alloc_pages_exact_node (Nodeid, Flags | __ Gfp_notrack, 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); elseadd_zone_ Page_state (Page_zone (page), nr_slab_unreclaimable, nr_pages); for (i = 0; i < nr_pages; i++) __setpageslab (page + i); if ( Kmemcheck_enabled &&! (Cachep->flags & Slab_notrack)) {Kmemcheck_alloc_shadow (page, Cachep->gfporder, flags, Nodeid); if (cachep->ctor) Kmemcheck_mark_uninitialized_pages (page, nr_pages); elsekmemcheck_mark_unallocated_pages (page, nr_pages);} /* Returns the virtual address of the home page */return page_address (page);}
For releasing a page box assigned to Slab
/* * Interface to System ' s page release. */static void kmem_freepages (struct kmem_cache *cachep, void *addr) {unsigned long i = (1 << cachep->gfporder); str UCT page *page = virt_to_page (addr); const unsigned long nr_freed = I;kmemcheck_free_shadow (page, cachep->gfporder); if (Cachep->flags & Slab_reclaim_account) sub_zone_page_state (Page_zone (page), nr_slab_reclaimable, nr_freed); Elsesub_zone_page_state (Page_zone (page), nr_slab_unreclaimable, Nr_freed), while (i--) {bug_on (! Pageslab (page)); __clearpageslabpfmemalloc (page); __clearpageslab (page);p age++;} if (current->reclaim_state)//Perform memory reclamation Current->reclaim_state->reclaimed_slab + = Nr_freed;free_pages ( unsigned long) addr, cachep->gfporder);}
Allocating space for the slab admin area
static struct slab *alloc_slabmgmt (struct kmem_cache *cachep, void *objp, int colour_off, gfp_t local_flags, int nodei d) {struct slab *slabp;/* if the slab management area is located outside of slab, allocate space Slabp_cache (*/if (Off_slab)) {/* Cachep slab obj in the specified management Off-slab. */SLABP = Kmem_cache_alloc_node (Cachep->slabp_cache, Local_flags, Nodeid);/* * If The first object in the slab is Leaked (it's allocated * But no one have a reference to it), we want to do sure * kmemleak does not treat the->s_mem Pointer as a reference * to the object. Otherwise We won't report the leak. */kmemleak_scan_area (SLABP, offsetof (struct slab, list), sizeof (struct list_head), local_flags), if (!SLABP) return NULL ;} else {/*slab Admin area is in slab *//* built-in slab. OBJP for slab The virtual address of the first page, plus coloring offset , get slab Management object's virtual address *//*slab admin area from slab first offset color value where */SLABP = OBJP + Colour_off; Colour_off + = cachep->slab_size;/* calculates the in-page offset of the first object in the slab, Slab_size saves the size of the slab management object  , including the struct slab object and the Kmem_bufctl_ T array */ }slabp->inuse = 0;/* ObjectAll for idle */slabp->colouroff = Colour_off; /* Refreshes the offset of the first object */ /* the page offset of the first object, visible for the built-in Slab,colouroff members include not only the shading area , but also the space   that the management object occupies, the external slab, Colouroff members include only shaded areas. */slabp->s_mem = OBJP + colour_off;/* Determines the position of the first object */slabp->nodeid = nodeid;/* The identity node is the memory Node ID */slabp->free = 0; /* The next Idle object is at the beginning of S_mem, which is the first element of the kmem_bufctl_t array */return slabp;}
1, obtains and calculates the shading offset from the cache structure;
2, obtain 1<<cachep->gfporder pages from the partner system for slab;
3, initialize The relevant variables in the slab, if it is external slab need to new application slab Management area, by the function ALLOC_SLABMGMT () implementation
The page describes the structure of the LRU domain to establish a map of the page box to the slab descriptor and the cache descriptor, which is actually to make Lru.next point to the cache descriptor, Lru.prev to the slab descriptor
static void Slab_map_pages (struct kmem_cache *cache, struct slab *slab, void *addr) {int nr_pages;struct page *page;pa GE = virt_to_page (addr); nr_pages = 1;if (Likely (! Pagecompound (page))) Nr_pages <<= cache->gfporder;/* The number of page frames assigned to slab */do {Page_set_cache (page, cache);/* Create a mapping to the cache */page_set_slab (page, slab); /* Establish mapping */page++ to slab;} while (--nr_pages);}
InitializeSlabinkmem_bufctl_t[]Array, wherekmem_bufctl_t[]array is a static linked list that specifies theSlabObject (obj)Order of Access. Thatkmem_bufctl_t[]The next access is stored in theobj. In the back of the analysisslab_get_obj ()function fromSlabto extract a free object from theindex_to_obj ()function to find the Idle object in thekmem_bufctl_t[]The subscript in the array, and then through theSlab_bufctl (SLABP) [Slabp->free]gets the index of the next free object and uses it to update the static list.
static void Cache_init_objs (struct kmem_cache *cachep, struct slab *slabp) {int i;for (i = 0; i < cachep->num; i++ { /* initializes the objects in the slab/ void *OBJP = Index_to_obj (Cachep, SLABP, i); #if debug/* need to poison the OBJS? */if ( Cachep->flags & Slab_poison) poison_obj (Cachep, OBJP, Poison_free); if (Cachep->flags & slab_store_user) * Dbg_userword (Cachep, OBJP) = Null;if (Cachep->flags & Slab_red_zone) {*dbg_redzone1 (Cachep, OBJP) = RED_INACTIVE; *dbg_redzone2 (Cachep, OBJP) = red_inactive;} /* * Constructors is allowed to allocate memory from the same * cache which they is a constructor for. Otherwise, deadlock. * They must also be threaded. */if (Cachep->ctor &&!) ( Cachep->flags & Slab_poison) cachep->ctor (OBJP + obj_offset (Cachep)); if (Cachep->flags & SLAB_RED_ ZONE) {if (*dbg_redzone2 (Cachep, OBJP)! = red_inactive) slab_error (Cachep, "constructor overwrote the" "End of an object "); if (*dbg_redzone1 (Cachep, OBJP)! = Red_INACTIVE) Slab_error (Cachep, "constructor overwrote the" "Start of an Object");} if ((cachep->size% page_size) = = 0 && off_slab (cachep) && cachep->flags & Slab_poison) kernel _map_pages (Virt_to_page (OBJP), cachep->size/page_size, 0); #elseif (Cachep->ctor) cachep->ctor (OBJP);/* Initializes the object according to the constructor */ slab_bufctl (SLABP) [i] = i + 1;/* determines the next idle object to be followed by adjacent objects */ }slab_bufctl (SLABP) [i-1] = bufctl_end;& nbsp;/* last point Bufctl_end */
Destruction of Slab;
/** * Slab_destroy-destroy and release all objects in a slab * @cachep: cache pointer being destroyed * @ Slabp:slab pointer being destroyed * * Destroy all the objs with a slab, and release the Mem back to the system.& nbsp;* before calling the slab must has been unlinked from the cache. the * Cache-lock is not held/needed. */static void Slab_destroy (struct kmem_cache *cachep, struct slab *s LABP) {/* Use the address of the first object minus the shading offset to get the slab start address */void *addr = Slabp->s_mem-slabp->colouroff;slab_destroy_debugcheck ( Cachep, SLABP);/* If the RCU method is chosen to destroy the SLAB, then the RCU is destroyed, and the expression is not quite clear */if (unlikely (Cachep->flags & Slab_destroy_by_rcu)) {struct SLAB_RCU *slab_rcu;slab_rcu = (struct Slab_rcu *) Slabp;slab_rcu->cachep = cachep;slab_rcu->addr = addr; Call_rcu (&slab_rcu->head, kmem_rcu_free);} else {/* SLAB the page frame occupied by the */kmem_freepages back to the partner system (Cachep, addr);/* If the SLAB administrative area is external, you need to release the Admin Area Object */if (Off_slab (Cachep)) from the corresponding cache Kmem_cache_free (Cachep->slabp_cache, SLABP);}}
Memory Management---Create destroy slab