上篇讲了Slab中的数据结构,这篇该讲Slab中的操作了。
既然是内存管理,那操作无非就两点:allocate 和 free。
1. 申请一个object
在Slab中,申请一个object是通过函数 kmem_cache_alloc() 来完成的。
3618 void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) 3619 { 3620 return __cache_alloc(cachep, flags, __builtin_return_address(0)); 3621 }
该函数有两个参数:
cachep指定了要从哪个cache中申请object.
flags: 如果该cache中所有的slab都已经满了,那就不得不向buddy system求救。flags指定了此时从buddy system中申请page frame时要使用的标志。
其实函数 kmem_cache_alloc() 只是一个wapper,经过层层调用,除去必要的锁操作,最终真正干活的是函数 ____cache_alloc()。
3190 static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) 3191 { 3192 void *objp; 3193 struct array_cache *ac; 3194 3195 check_irq_off(); 3196 3197 ac = cpu_cache_get(cachep); 3198 if (likely(ac->avail)) { 3199 STATS_INC_ALLOCHIT(cachep); 3200 ac->touched = 1; 3201 objp = ac->entry[--ac->avail]; 3202 } else { 3203 STATS_INC_ALLOCMISS(cachep); 3204 objp = cache_alloc_refill(cachep, flags); 3205 } 3206 return objp; 3207 }
该函数看起来唬人,其实其武功招式总结起来就三招,人称“分配三板斧”。
第一板斧:per-cpu object cache.
3197 ~ 3201: 首先找到当前CPU的object cache,然后检查cache中有没有可用的object,有的话就拿出一个来。然后完活收工。
定位object cache是通过以下函数完成的:
760 static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep) 761 { 762 return cachep->array[smp_processor_id()]; 763 }
上篇讲过,object cache实际上是一个LIFO的栈结构,其中成员变量 avail 即代表了可用object的个数,又作为索引值指出了栈顶位置。
所以从object cache中拿出一个object的操作,可以通过 3201 行的语句来完成。
3201 objp = ac->entry[--ac->avail];
第二板斧:Slab中的空闲object
如果object cache中没有可用的object,那就要先填充object cache。如果不考虑 shared object cache,填充cache的object来自于Slab页面。
该操作由函数 cache_alloc_refill() 完成。
2957 static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags) 2958 { 2959 int batchcount; 2960 struct kmem_list3 *l3; 2961 struct array_cache *ac; 2962 int node; 2963 2964 node = numa_node_id(); 2965 2966 check_irq_off(); 2967 ac = cpu_cache_get(cachep); 2968 retry: 2969 batchcount = ac->batchcount; 2978 l3 = cachep->nodelists[node]; 2979 2980 BUG_ON(ac->avail > 0 || !l3); 2981 spin_lock(&l3->list_lock); 2982 2983 /* See if we can refill from the shared array */ 2984 if (l3->shared && transfer_objects(ac, l3->shared, batchcount)) 2985 goto alloc_done; 2986 2987 while (batchcount > 0) { 2988 struct list_head *entry; 2989 struct slab *slabp; 2990 /* Get slab alloc is to come from. */ 2991 entry = l3->slabs_partial.next; 2992 if (entry == &l3->slabs_partial) { 2993 l3->free_touched = 1; 2994 entry = l3->slabs_free.next; 2995 if (entry == &l3->slabs_free) 2996 goto must_grow; 2997 } 2998 2999 slabp = list_entry(entry, struct slab, list); 3000 check_slabp(cachep, slabp); 3001 check_spinlock_acquired(cachep); 3002 3003 /* 3004 * The slab was either on partial or free list so 3005 * there must be at least one object available for 3006 * allocation. 3007 */ 3008 BUG_ON(slabp->inuse < 0 || slabp->inuse >= cachep->num); 3009 3010 while (slabp->inuse < cachep->num && batchcount--) { 3011 STATS_INC_ALLOCED(cachep); 3012 STATS_INC_ACTIVE(cachep); 3013 STATS_SET_HIGH(cachep); 3014 3015 ac->entry[ac->avail++] = slab_get_obj(cachep, slabp, 3016 node); 3017 } 3018 check_slabp(cachep, slabp); 3019 3020 /* move slabp to correct slabp list: */ 3021 list_del(&slabp->list); 3022 if (slabp->free == BUFCTL_END) 3023 list_add(&slabp->list, &l3->slabs_full); 3024 else 3025 list_add(&slabp->list, &l3->slabs_partial); 3026 } 3027 3028 must_grow: 3029 l3->free_objects -= ac->avail; 3030 alloc_done: 3031 spin_unlock(&l3->list_lock); 3032 3033 if (unlikely(!ac->avail)) { 3034 int x; 3035 x = cache_grow(cachep, flags | GFP_THISNODE, node, NULL); 3036 3037 /* cache_grow can reenable interrupts, then ac could change. */ 3038 ac = cpu_cache_get(cachep); 3039 if (!x && ac->avail == 0) /* no objects in sight? abort */ 3040 return NULL; 3041 3042 if (!ac->avail) /* objects refilled by interrupt? */ 3043 goto retry; 3044 } 3045 ac->touched = 1; 3046 return ac->entry[--ac->avail]; 3047 }
2984行先检查一下能否从shared object cache中拿一些object填充到我们的object cache中。该操作其实就是一个memory copy的过程。
2987 ~ 3026 是从Slab页面中填充object cache的操作。
该操作首先遍历所有partial的slab,然后再遍历所有free的slab。对每个slab,拿出其中的free objects,填充到object cache中。
从slab中拿出一个free object的操作由函数 slab_get_obj() 完成。
2695 static void *slab_get_obj(struct kmem_cache *cachep, struct slab *slabp, 2696 int nodeid) 2697 { 2698 void *objp = index_to_obj(cachep, slabp, slabp->free); 2699 kmem_bufctl_t next; 2700 2701 slabp->inuse++; 2702 next = slab_bufctl(slabp)[slabp->free]; 2707 slabp->free = next; 2708 2709 return objp; 2710 }
我们上篇讲过,slab中所有空闲的object 的描述符组成了一个简单的链表。该函数从这个链表中取下头部的一个空闲object。
把拿出的空闲object填充到object cache的操作是由3015行完成的。
3015 ac->entry[ac->avail++] = slab_get_obj(cachep, slabp, 3016 node);
第三板斧:buddy system
如果所有的slab都满了,即每个slab都没有空闲object了,那怎么办?这个时候就得求助于buddy system了。
从buddy system中申请新的page frame,创建新的slab,从而创建出一批新的object。该操作由函数 cache_grow() 完成。
2760 static int cache_grow(struct kmem_cache *cachep, 2761 gfp_t flags, int nodeid, void *objp) 2762 { 2763 struct slab *slabp; 2764 size_t offset; 2765 gfp_t local_flags; 2766 struct kmem_list3 *l3; 2767 2768 /* 2769 * Be lazy and only check for valid flags here, keeping it out of the 2770 * critical path in kmem_cache_alloc(). 2771 */ 2772 BUG_ON(flags & GFP_SLAB_BUG_MASK); 2773 local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK); 2774 2775 /* Take the l3 list lock to change the colour_next on this node */ 2776 check_irq_off(); 2777 l3 = cachep->nodelists[nodeid]; 2778 spin_lock(&l3->list_lock); 2779 2780 /* Get colour for the slab, and cal the next value. */ 2781 offset = l3->colour_next; 2782 l3->colour_next++; 2783 if (l3->colour_next >= cachep->colour) 2784 l3->colour_next = 0; 2785 spin_unlock(&l3->list_lock); 2786 2787 offset *= cachep->colour_off;
2780 ~ 2787,该函数首先确定新建slab的color值。
上篇讲过,结构体kmem_list3的成员变量colour_next,保存了下一个要使用的color值。cache描述符中的colour,保存了可用的color 数。cache描述符中的colour_off, 保存了对齐字节数。
2781 ~ 2784行把colour_next的值赋值给变量offset,然后更新colour_next的值。如果colour_next的值达到了最大值,则重置为0。
2787行用color值乘以字节对齐数,算出来的就是slab开始位置的偏移量。
确定了color值后,下一步就是要向buddy system申请page frame了。
2804 if (!objp) 2805 objp = kmem_getpages(cachep, local_flags, nodeid); 2806 if (!objp) 2807 goto failed;
为新slab申请page frame的操作由函数 kmem_getpages() 完成。
1653 static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid) 1654 { 1655 struct page *page; 1656 int nr_pages; 1657 int i; 1667 flags |= cachep->gfpflags; 1668 if (cachep->flags & SLAB_RECLAIM_ACCOUNT) 1669 flags |= __GFP_RECLAIMABLE; 1670 1671 page = alloc_pages_node(nodeid, flags, cachep->gfporder); 1672 if (!page) 1673 return NULL; 1674 1675 nr_pages = (1 << cachep->gfporder); 1682 for (i = 0; i < nr_pages; i++) 1683 __SetPageSlab(page + i); 1684 return page_address(page); 1685 }
函数 kmem_getpages() 首先确定分配flags。至此,调用 kmem_cache_alloc() 时传递的参数 flags 终于被用到了。但是这个flags还要再加上cache本身的flag,才会被用来申请page frame。
然后1671行调用了我们前面讲的alloc_pages函数,从buddy system中申请page frame。申请的page frame order为cachep->gfporder。
1682 ~ 1683行,为每个申请到的page frame的描述符设置 PG_slab 标志。
最后返回第一个page frame的线性地址。
好,申请到page frame了,那下一步做什么?让我们回到函数 cache_grow() 继续跟踪。
2810 slabp = alloc_slabmgmt(cachep, objp, offset, 2811 local_flags & ~GFP_CONSTRAINT_MASK, nodeid); 2812 if (!slabp) 2813 goto opps1;
2810 ~ 2813为新建的slab 分配并初始化slab描述符,由函数 alloc_slabmgmt() 完成。
2609 static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp, 2610 int colour_off, gfp_t local_flags, 2611 int nodeid) 2612 { 2613 struct slab *slabp; 2614 2615 if (OFF_SLAB(cachep)) { 2616 /* Slab management obj is off-slab. */ 2617 slabp = kmem_cache_alloc_node(cachep->slabp_cache, 2618 local_flags & ~GFP_THISNODE, nodeid); 2619 if (!slabp) 2620 return NULL; 2621 } else { 2622 slabp = objp + colour_off; 2623 colour_off += cachep->slab_size; 2624 } 2625 slabp->inuse = 0; 2626 slabp->colouroff = colour_off; 2627 slabp->s_mem = objp + colour_off; 2628 slabp->nodeid = nodeid; 2629 return slabp; 2630 }
2615 ~ 2620:针对external slab,从cachep->slabp_cache中分配slab描述符(以及object描述符)。
2622 ~ 2623:针对internal slab,在slab页面内指定slab描述符的地址。考虑进去slab coloring, slab描述符放在 (color*aln) 位置处。
2625 ~ 2628:初始化新建的slab描述符。正如上篇讲到的,第一个object的偏移量定义为(color * aln) + dsize。
有了slab描述符后,让我们回到函数 cache_grow() 继续跟踪。
2816 slab_map_pages(cachep, slabp, objp); 2817 2818 cache_init_objs(cachep, slabp); 2819
2816行建立page frame与cache和slab描述符之间的关联。
2737 static void slab_map_pages(struct kmem_cache *cache, struct slab *slab, 2738 void *addr) 2739 { 2740 int nr_pages; 2741 struct page *page; 2742 2743 page = virt_to_page(addr); 2744 2745 nr_pages = 1; 2746 if (likely(!PageCompound(page))) 2747 nr_pages <<= cache->gfporder; 2748 2749 do { 2750 page_set_cache(page, cache); 2751 page_set_slab(page, slab); 2752 page++; 2753 } while (--nr_pages); 2754 }
建立关联的方式就是重用了page描述符中的成员变量lru。
583 static inline void page_set_cache(struct page *page, struct kmem_cache *cache) 584 { 585 page->lru.next = (struct list_head *)cache; 586 }
595 static inline void page_set_slab(struct page *page, struct slab *slab) 596 { 597 page->lru.prev = (struct list_head *)slab; 598 }
2818行初始化新建slab中的objects.
2637 static void cache_init_objs(struct kmem_cache *cachep, 2638 struct slab *slabp) 2639 { 2640 int i; 2641 2642 for (i = 0; i < cachep->num; i++) { 2643 void *objp = index_to_obj(cachep, slabp, i); 2676 if (cachep->ctor) 2677 cachep->ctor(cachep, objp); 2679 slab_bufctl(slabp)[i] = i + 1; 2680 } 2681 slab_bufctl(slabp)[i - 1] = BUFCTL_END; 2682 slabp->free = 0; 2683 }
这个初始化做了两件事:
如果该cache定义了构造函数,则对每个新建的object执行构造函数。
初始化object描述符,构造出空闲object链表。
建立了关联,初始化了object,继续跟踪 cache_grow()。
2823 spin_lock(&l3->list_lock); 2824 2825 /* Make slab active. */ 2826 list_add_tail(&slabp->list, &(l3->slabs_free)); 2827 STATS_INC_GROWN(cachep); 2828 l3->free_objects += cachep->num; 2829 spin_unlock(&l3->list_lock); 2830 return 1; 2831 opps1: 2832 kmem_freepages(cachep, objp); 2833 failed: 2834 if (local_flags & __GFP_WAIT) 2835 local_irq_disable(); 2836 return 0; 2837 }
把新建的slab添加到cache的free slab链表中,更新kmem_list3中free_objects的值,然后完活收工。
第三板斧使出来之后,该cache新增了一slab的free object。于是重新使用第二板斧。
2. 释放一个object
释放一个object的API是函数 kmem_cache_free().
3760 void kmem_cache_free(struct kmem_cache *cachep, void *objp) 3761 { 3762 unsigned long flags; 3763 3764 local_irq_save(flags); 3765 debug_check_no_locks_freed(objp, obj_size(cachep)); 3766 __cache_free(cachep, objp); 3767 local_irq_restore(flags); 3768 }
该函数也是一个wrapper,最终干活的是函数 __cache_free()。
3582 static inline void __cache_free(struct kmem_cache *cachep, void *objp) 3583 { 3584 struct array_cache *ac = cpu_cache_get(cachep); 3598 3599 if (likely(ac->avail < ac->limit)) { 3600 STATS_INC_FREEHIT(cachep); 3601 ac->entry[ac->avail++] = objp; 3602 return; 3603 } else { 3604 STATS_INC_FREEMISS(cachep); 3605 cache_flusharray(cachep, ac); 3606 ac->entry[ac->avail++] = objp; 3607 } 3608 }
相对应的,该函数也是三板斧,人称“释放三板斧”,而且这三板斧与“申请三板斧”一一对应,真是一对生死冤家。
第一板斧:per-cpu object cache
3599 ~ 3602,如果当前CPU的object cache没有满,则直接把要释放的object放到object cache中,然后完活收工。
第二板斧:Slab页面
如果object cache满了,则要刷一批object到slab页面中。该操作由函数 cache_flusharray() 完成。
3527 static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) 3528 { 3529 int batchcount; 3530 struct kmem_list3 *l3; 3531 int node = numa_node_id(); 3532 3533 batchcount = ac->batchcount; 3537 check_irq_off(); 3538 l3 = cachep->nodelists[node]; 3539 spin_lock(&l3->list_lock); 3540 if (l3->shared) { 3541 struct array_cache *shared_array = l3->shared; 3542 int max = shared_array->limit - shared_array->avail; 3543 if (max) { 3544 if (batchcount > max) 3545 batchcount = max; 3546 memcpy(&(shared_array->entry[shared_array->avail]), 3547 ac->entry, sizeof(void *) * batchcount); 3548 shared_array->avail += batchcount; 3549 goto free_done; 3550 } 3551 } 3552 3553 free_block(cachep, ac->entry, batchcount, node); 3554 free_done: 3573 spin_unlock(&l3->list_lock); 3574 ac->avail -= batchcount; 3575 memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail); 3576 }
3540 ~ 3551:如果shared object cache没有满额,则转移一批object到shared cache中。
3553行:利用函数 free_block() 刷一批object到slab页面中。
3575行:把object cache中剩下的object上移。为了保证object cache是LIFO的结构,会把最早放入object cache的那些object刷掉,因此需要把剩下的object向上移动。
3483 static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects, 3484 int node) 3485 { 3486 int i; 3487 struct kmem_list3 *l3; 3488 3489 for (i = 0; i < nr_objects; i++) { 3490 void *objp = objpp[i]; 3491 struct slab *slabp; 3492 3493 slabp = virt_to_slab(objp); 3494 l3 = cachep->nodelists[node]; 3495 list_del(&slabp->list); 3496 check_spinlock_acquired_node(cachep, node); 3497 check_slabp(cachep, slabp); 3498 slab_put_obj(cachep, slabp, objp, node); 3499 STATS_DEC_ACTIVE(cachep); 3500 l3->free_objects++; 3501 check_slabp(cachep, slabp); 3502 3503 /* fixup slab chains */ 3504 if (slabp->inuse == 0) { 3505 if (l3->free_objects > l3->free_limit) { 3506 l3->free_objects -= cachep->num; 3507 /* No need to drop any previously held 3508 * lock here, even if we have a off-slab slab 3509 * descriptor it is guaranteed to come from 3510 * a different cache, refer to comments before 3511 * alloc_slabmgmt. 3512 */ 3513 slab_destroy(cachep, slabp); 3514 } else { 3515 list_add(&slabp->list, &l3->slabs_free); 3516 } 3517 } else { 3518 /* Unconditionally move a slab to the end of the 3519 * partial list on free - maximum time for the 3520 * other objects to be freed, too. 3521 */ 3522 list_add_tail(&slabp->list, &l3->slabs_partial); 3523 } 3524 } 3525 }
3493行根据object的地址,确定出slab描述符的地址。这里就用到我们在创建slab时建立的关联了。
612 static inline struct slab *virt_to_slab(const void *obj) 613 { 614 struct page *page = virt_to_head_page(obj); 615 return page_get_slab(page); 616 }
600 static inline struct slab *page_get_slab(struct page *page) 601 { 602 BUG_ON(!PageSlab(page)); 603 return (struct slab *)page->lru.prev; 604 }
3498行把一个object放回到slab中。
2712 static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp, 2713 void *objp, int nodeid) 2714 { 2715 unsigned int objnr = obj_to_index(cachep, slabp, objp); 2727 slab_bufctl(slabp)[objnr] = slabp->free; 2728 slabp->free = objnr; 2729 slabp->inuse--; 2730 }
3504 ~ 3523:放回一个object后,就要检查该slab的状态:
partial:把slab挂到slabs_partial链表上。
free:检查cache中free object的数量有没有超过限制。
没有超过:把slab挂到slabs_free链表中。
超过了:删掉该slab,把其page frame还给buddy system。
第三板斧:buddy system
删除一个slab的操作是由函数 slab_destroy() 完成的。
1944 static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) 1945 { 1946 void *addr = slabp->s_mem - slabp->colouroff; 1947 1957 kmem_freepages(cachep, addr); 1958 if (OFF_SLAB(cachep)) 1959 kmem_cache_free(cachep->slabp_cache, slabp); 1961 }
该函数首先释放slab所用的page frame,然后对于external slab,把slab描述符占用的空间释放掉。
释放slab所用page frame的操作是由函数 kmem_freepages() 完成的。
1690 static void kmem_freepages(struct kmem_cache *cachep, void *addr) 1691 { 1692 unsigned long i = (1 << cachep->gfporder); 1693 struct page *page = virt_to_page(addr); 1702 while (i--) { 1703 BUG_ON(!PageSlab(page)); 1704 __ClearPageSlab(page); 1705 page++; 1706 } 1709 free_pages((unsigned long)addr, cachep->gfporder); 1710 }
1702 ~ 1706:对slab所用的每个page frame,清除其描述符中的 PG_slab 标志。
1709:调用函数 free_pages() 把slab所用的page frame还给buddy system。