免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 13215 | 回复: 8

投石问路:kmem_cache_alloc函数使用问题 [复制链接]

论坛徽章:
0
发表于 2007-11-09 16:31 |显示全部楼层
为了更好的得到问题解决,也对问题的提出进点义务,在抛出我的问题前先简单介绍一下Linux下slab高速缓存的使用方法。

在内核编程中,可能经常会有一些数据结构需要反复使用和释放,按照通常的思路,可能是使用kmalloc和kfree来实现。
但是这种方式效率不高,Linux为我们提供了更加高效的方法——Slab高速缓存管理器
通过先使用kmem_cache_create函数创建一个高速缓存的头指针——在内核中是struct kmem_cache结构,具体用法可以这样:
struct kmem_cache *cachep = NULL;

cachep = kmem_cache_create("cache_name", sizeof(struct yourstruct), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);

这样我们就获得了一个可用的cachep头指针。

当需要分配一个struct yourstruct的结构体空间时,我们只需要调用kmem_cache_alloc函数,就可以获得一个足够我们使用的空间的指针(为什么我要说足够呢?因为刚才的声明中我使用了一个标志——SLAB_HWCACHE_ALIGN,这个标志会让分配的空间对于硬件来说是对齐的,而不一定恰好等于sizeof(struct yourstruct)的结果)。范例代码如下:
struct yourstruct *bodyp = NULL;


bodyp = (struct yourstruct *) kmem_cache_alloc(cachep, GFP_ATOMIC & ~__GFP_DMA);


这样就可以使用bodyp指针所对应的空间存贮你需要的结构体信息了。
当用完结束后,我们需要释放空间,如何操作呢?代码很简单:
kmem_cache_free(cachep, bodyp);


OK,简单的介绍结束了,下面谈谈我的问题。

当在软中断中使用kmem_cache_alloc时,什么原因能够造成该函数返回失败呢?
我碰到的问题是当系统硬中断较频繁时,kmem_cache_alloc返回了失败,但是与此同时,skbuff_head的高速缓存却依然能够正常地依赖kmem_cache_alloc_node分配成功,这是为什么呢?

希望各位了解2.6内核这部分机制的仁兄不吝赐教!

小弟投石问路,还望各位花点时间帮帮忙,在此先谢过了!

论坛徽章:
0
发表于 2007-11-09 17:16 |显示全部楼层
刚刚研究代码,调用关系大致如下:
kmem_cache_alloc==〉__cache_alloc;
__cache_alloc==〉local_irq_save; __do_cache_alloc; local_irq_restore;
其中__do_cache_alloc==〉____cache_alloc;
static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
    void *objp;
    struct array_cache *ac;

    check_irq_off();

    if (should_failslab(cachep, flags))
        return NULL;

    ac = cpu_cache_get(cachep);
    if (likely(ac->avail)) {
        STATS_INC_ALLOCHIT(cachep);
        ac->touched = 1;
        objp = ac->entry[--ac->avail];
    } else {
        STATS_INC_ALLOCMISS(cachep);
        objp = cache_alloc_refill(cachep, flags);
    }
    return objp;
}

如果should_failslab为true,那么kmem_cache_alloc应当返回失败;
那么分析should_failslab函数:
static int should_failslab(struct kmem_cache *cachep, gfp_t flags)
{
    if (cachep == &cache_cache)
        return 0;
    if (flags & __GFP_NOFAIL)
        return 0;
    if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT))
        return 0;

    return should_fail(&failslab.attr, obj_size(cachep));
}

从以上分析,前三个if肯定都不会为true的,因此,分析最后一个should_fail函数(代码较长,就不列出了),我判断这里也不会返回失败的,因此应该返回____cache_alloc函数继续分析。
分析分配失败应该是刚好出现在已分配的cache用完了,需要slab再分配一组cache时失败的,因此感觉有可能是cache_alloc_refill函数返回的NULL。继续分析ing。。。

希望有了解的兄弟能来指点一二!

论坛徽章:
0
发表于 2007-11-09 17:48 |显示全部楼层
再来更新一下:

首先我是在软中断中调用kmem_cache_alloc函数的,因此属于中断模式,所以标志为必须使用GPF_ATOMIC来避免睡眠;
另外,我分配的结构大小也不是很大,纯结构体大小为108字节,因为使用了SLAB_HWCACHE_ALIGN标志,因此分配出来时128字节。
通常认为kmem_cache_alloc失败是内存不够用了,但是我这里的情况是系统仍然有512M左右的内存可以使用,因此排除此原因。

还能有什么原因呢?希望有经验的兄弟来说两句!

论坛徽章:
0
发表于 2007-11-10 01:58 |显示全部楼层
有人看,没人回。。。

期待有人能来聊聊slab使用经验!

论坛徽章:
0
发表于 2007-11-10 11:48 |显示全部楼层

回复 #4 Jobs.AE@ 的帖子

没用过,但是觉得不应该有问题的
我建议楼主先绕过slab,使用Atomic的kmalloc实现确定是slab问题

如果真是slab问题,建议楼主看看别人代码怎么使用slab的,最好的例子就是kernel自带的那些了,我估计是楼主自己不小心,slab使用方法上有问题

论坛徽章:
0
发表于 2007-11-10 12:25 |显示全部楼层
原帖由 bluesky_jxc 于 2007-11-10 11:48 发表
没用过,但是觉得不应该有问题的
我建议楼主先绕过slab,使用Atomic的kmalloc实现确定是slab问题

如果真是slab问题,建议楼主看看别人代码怎么使用slab的,最好的例子就是kernel自带的那些了,我估计是楼主 ...


谢谢回复。

我的用法与skbuff_head的slab分配方式几乎完全一样,一点小差别是skbuff分配时指定了node,但是不指定的话,系统也会选择默认的cpu node进行分配的
可以参见相关内核代码,比较多,我就不贴出来了。
以e1000驱动中clean_irq中分配skbuff为例,使用的是netdev_alloc_skb接口,对应调用__alloc_skb函数,可参见skbuff.c
另外,我到没有尝试将该slab调用替换成kmalloc,但是这个slab分配的cache中有一个指针使用的空间恰好是使用kmalloc分配的
测试中,通常会先出现kmalloc失败,然后才是slab分配失败

对比了2.4的slab.h,其中有一个强制SLAB_NO_REAPET的标志位,可是该标志到了2.6内核被取消了

论坛徽章:
0
发表于 2007-11-10 12:49 |显示全部楼层
原帖由 Jobs.AE@ 于 2007-11-10 12:25 发表


谢谢回复。

我的用法与skbuff_head的slab分配方式几乎完全一样,一点小差别是skbuff分配时指定了node,但是不指定的话,系统也会选择默认的cpu node进行分配的
可以参见相关内核代码,比较多,我就不贴 ...

这个是肯定的,当cache里面没有对象的时候,最后还是调用kmalloc分配空间,如果cache失败,kmalloc必然先失败

但是,你是否能肯定一定是kmalloc失败呢?所以建议你先直接kmalloc试试

论坛徽章:
0
发表于 2008-09-23 14:16 |显示全部楼层
有结果吗? 我想知道最后是怎么解决的

论坛徽章:
0
发表于 2008-12-04 17:24 |显示全部楼层
以下是我的一点见解
在函数 cache_alloc_refill中 有一个 check_irq_off();
这个check函数有一个判断中断是否打开的动作,在中断打开的状态下使用allocate slab 会触发这个错误

软中断调用的时机有两种情况

      1) 在所有中断处理TOP HALF 完成之后, 退出中断VECTOR 之前 .这种情况下中断处于打开状态(这时调用出错)
      2) 在KSOFTIRQD中调用中断处于非使能状态.(如果这时调用ALLOC SLAB 没有问题)

static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
{
        int batchcount;
        struct kmem_list3 *l3;
        struct array_cache *ac;
        int node;

        node = numa_node_id();

        check_irq_off();

static void check_irq_off(void)
{
        BUG_ON(!irqs_disabled());
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,7折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时七折期:2019年8月31日前


----------------------------------------

大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP