内核版本: 2.6.11
1. slab描述符
每个slab都有自己的描述符。
定义如下:
207 struct slab {
208 struct list_head list;
209 unsigned long colouroff;
210 void *s_mem; /* including colour offset */
211 unsigned int inuse; /* num of objs active in slab */
212 kmem_bufctl_t free;
213 };
2. 对象描述符
每个object也有一个描述符,类型为kmem_bufctl_t,其实是个无符号短整型。作用在下面会介绍。
66 typedef unsigned short kmem_bufctl_t;
说明:
1)着色的实现
1780 static int cache_grow (kmem_cache_t * cachep, int flags, int nodeid)
1781 {
....
1809 /* Get colour for the slab, and cal the next value. */
1810 offset = cachep->colour_next;
1811 cachep->colour_next++;
1812 if (cachep->colour_next >= cachep->colour)
1813 cachep->colour_next = 0;
1814 offset *= cachep->colour_off;
1815
1816 spin_unlock(&cachep->spinlock);
1817
1818 if (local_flags & __GFP_WAIT)
1819 local_irq_enable();
1820
1821 /*
1822 * The test for missing atomic flag is performed here, rather than
1823 * the more obvious place, simply to reduce the critical path length
1824 * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
1825 * will eventually be caught here (where it matters).
1826 */
1827 kmem_flagcheck(cachep, flags);
1828
1829
1830 /* Get mem for the objs. */
1831 if (!(objp = kmem_getpages(cachep, flags, nodeid)))
1832 goto failed;
1833
1834 /* Get slab management. */
1835 if (!(slabp = alloc_slabmgmt(cachep, objp, offset, local_flags)))
1836 goto opps1;
...
}
在1810行,增加cache->colour_next,然后乘以对齐因子cache->colour_off,得到offset,然后通过alloc_slabmgmt加上着色值。
2)怎么实现object描述符和slab描述符靠在一起?
1678 static struct slab* alloc_slabmgmt (kmem_cache_t *cachep,
1679 void *objp, int colour_off, int local_flags)
1680 {
1681 struct slab *slabp;
1682
1683 if (OFF_SLAB(cachep)) {
1684 /* Slab management obj is off-slab. */
1685 slabp = kmem_cache_alloc(cachep->slabp_cache, local_flags);
1686 if (!slabp)
1687 return NULL;
1688 } else {
1689 slabp = objp+colour_off;
1690 colour_off += cachep->slab_size;
1691 }
1692 slabp->inuse = 0;
1693 slabp->colouroff = colour_off;
1694 slabp->s_mem = objp+colour_off;
1695
1696 return slabp;
1697 }
在1694行,可以看到slabp->s_mem赋值偏移color_offset,看看colour_off这个偏移量里面有没有object描述符,
在1690行,可以看到colour_off除了包含着色值,还包含cachep->slab_size。跟踪下cachep->slab的赋值。
1186 kmem_cache_t *
1187 kmem_cache_create (const char *name, size_t size, size_t align,
1188 unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
1189 void (*dtor)(void*, kmem_cache_t *, unsigned long))
1190 {
....
1391 if (flags & CFLGS_OFF_SLAB) {
1392 /* really off slab. No need for manual alignment */
1393 slab_size = cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab);
1394 }
.....
}
可以看到,slab_size是包含了cachep->num个对象描述符大小和slab描述符大小的和。
3)怎么操作对象描述符和对象描述符的作用?
首先分析下slab_bufctl函数
1699 static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp)
1700 {
1701 return (kmem_bufctl_t *)(slabp+1);
1702 }
输入:slab描述符指针
输出:slab紧挨着的对象描述符
分析:slabp+1,刚好是对象描述符开始的地址,然后转换成kmem_bufctl_t结构。
接着分析下,初始化object函数
1704 static void cache_init_objs (kmem_cache_t * cachep,
1705 struct slab * slabp, unsigned long ctor_flags)
1706 {
1707 int i;
1708
1709 for (i = 0; i < cachep->num; i++) {
1710 void* objp = slabp->s_mem+cachep->objsize*i;
1711 #if DEBUG
1712 /* need to poison the objs? */
1713 if (cachep->flags & SLAB_POISON)
1714 poison_obj(cachep, objp, POISON_FREE);
1715 if (cachep->flags & SLAB_STORE_USER)
1716 *dbg_userword(cachep, objp) = NULL;
1717
1718 if (cachep->flags & SLAB_RED_ZONE) {
1719 *dbg_redzone1(cachep, objp) = RED_INACTIVE;
1720 *dbg_redzone2(cachep, objp) = RED_INACTIVE;
1721 }
1722 /*
1723 * Constructors are not allowed to allocate memory from
1724 * the same cache which they are a constructor for.
1725 * Otherwise, deadlock. They must also be threaded.
1726 */
1727 if (cachep->ctor && !(cachep->flags & SLAB_POISON))
1728 cachep->ctor(objp+obj_dbghead(cachep), cachep, ctor_flags);
1729
1730 if (cachep->flags & SLAB_RED_ZONE) {
1731 if (*dbg_redzone2(cachep, objp) != RED_INACTIVE)
1732 slab_error(cachep, "constructor overwrote the"
1733 " end of an object");
1734 if (*dbg_redzone1(cachep, objp) != RED_INACTIVE)
1735 slab_error(cachep, "constructor overwrote the"
1736 " start of an object");
1737 }
1738 if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON)
1739 kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0);
1740 #else
1741 if (cachep->ctor)
1742 cachep->ctor(objp, cachep, ctor_flags);
1743 #endif
1744 slab_bufctl(slabp)[i] = i+1;
1745 }
1746 slab_bufctl(slabp)[i-1] = BUFCTL_END;
1747 slabp->free = 0;
1748 }
可以看到slab_bufctl(slabp)[i]是操作第i个对象描述符。可以看出第i个描述符存的是第i+1个object的索引。最后一个描述符对于BUFCTL_END。
用slabp->free=0,指向第0个object的索引,第0个object描述符的值是第1个object的索引,slab最后一个object的描述符的值是BUFCTL_END。
这样在这个slab获取object只需要,从slab中free变量中,取出空闲object的索引,然后把这个object的描述符的值,也就是下一个空闲object的索引赋值给free.
1983 static void* cache_alloc_refill(kmem_cache_t* cachep, int flags)
1984 {
......
2032 while (slabp->inuse < cachep->num && batchcount--) {
2033 kmem_bufctl_t next;
2034 STATS_INC_ALLOCED(cachep);
2035 STATS_INC_ACTIVE(cachep);
2036 STATS_SET_HIGH(cachep);
2037
2038 /* get obj pointer */
2039 ac_entry(ac)[ac->avail++] = slabp->s_mem + slabp->free*cachep->objsize;
2040
2041 slabp->inuse++;
2042 next = slab_bufctl(slabp)[slabp->free];
2043 #if DEBUG
2044 slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE;
2045 #endif
2046 slabp->free = next;
2047 }
.....
}
在2039行,就是根据slab中的free指向的object赋值给cache_array,然后slab中inuser增加1,把free指向object的描述符的值也就是下一个空闲object索引赋值给slab的free。
总结:
1)slab的free的值是当前可用的object的索引。
2)slab的free对应的object描述符的值是下一个可用object的索引值,这样object的描述符形成一个简单的链表。