Chinaunix

标题: vfree为什么会引起睡眠? [打印本页]

作者: kinghawk1    时间: 2008-12-19 11:43
标题: vfree为什么会引起睡眠?
在vfree内核源码里找不到引起睡眠的地方啊,恳请高人告知。
作者: Godbach    时间: 2008-12-19 12:04
LDD2上说vmalloc可能睡眠
作者: windaoo    时间: 2008-12-19 14:44
LKD2 上也说 vmalloc 和 vfree 可能会睡眠,不能在中断上下文中调用,我也想知道是为什么

所以看了一下代码,发现 在 mm/vmalloc.c 中,vfree 是这样实现的:


void vfree(const void *addr)
{
        BUG_ON(in_interrupt());
        __vunmap(addr, 1);
}
EXPORT_SYMBOL(vfree);


再看 __vunmap , 它是这样的:
static void __vunmap(const void *addr, int deallocate_pages)
{
        struct vm_struct *area;

        if (!addr)
                return;

        if ((PAGE_SIZE-1) & (unsigned long)addr) {
                WARN(1, KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
                return;
        }

        area = remove_vm_area(addr);
        if (unlikely(!area)) {
                WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
                addr);
                return;
        }

        debug_check_no_locks_freed(addr, area->size);
        debug_check_no_obj_freed(addr, area->size);

        if (deallocate_pages) {
                int i;

                for (i = 0; i < area->nr_pages; i++) {
                        struct page *page = area->pages[i];

                        BUG_ON(!page);
                        __free_page(page);
                }

                if (area->flags & VM_VPAGES)
                        vfree(area->pages);
                else
                        kfree(area->pages);
        }

        kfree(area);
        return;
}


接着看 area = remove_vm_area(addr); 这一句, remove_vm_area():

struct vm_struct *remove_vm_area(const void *addr)
{
        struct vm_struct *v;
        write_lock(&vmlist_lock);
        v = __remove_vm_area(addr);
        write_unlock(&vmlist_lock);
        return v;
}


就是这个函数里,用了一个 write_lock,如果别人持有这把锁的话,在进锁的时候就会休眠了吧?


第一次在内核版发贴,呵呵
作者: windaoo    时间: 2008-12-19 15:22
标题: 回复 #3 windaoo 的帖子
sorry ,上面的 write_lock() 锁是自旋锁,应该不会睡眠
我也很想知道这个问题的真正原因
作者: scutan    时间: 2008-12-19 15:47
mail list中有一个这个,说vfree不会睡眠。

http://lkml.indiana.edu/hypermail/linux/kernel/0411.2/1955.html
作者: NewCore    时间: 2008-12-19 18:07
标题: 回复 #3 windaoo 的帖子
这位师兄贴出来的是2.6.26的内核代码吧。

2.6引入了很多更高效的数据结构,为什么vm空间的管理还是用链表,感觉还有待优化。

[ 本帖最后由 NewCore 于 2008-12-19 18:11 编辑 ]
作者: windaoo    时间: 2008-12-19 18:20
原帖由 scutan 于 2008-12-19 15:47 发表
mail list中有一个这个,说vfree不会睡眠。

http://lkml.indiana.edu/hypermail/linux/kernel/0411.2/1955.html


可是书上说 vfree 会睡眠,而且我这份代码的 vfree 前面的注释这样写:

/**
*        vfree  -  release memory allocated by vmalloc()
*        @addr:                memory base address
*
*        Free the virtually continuous memory area starting at @addr, as
*        obtained from vmalloc(), vmalloc_32() or __vmalloc(). If @addr is
*        NULL, no operation is performed.
*
*        Must not be called in interrupt context.
*/
void vfree(const void *addr)
{
        BUG_ON(in_interrupt());
        __vunmap(addr, 1);
}
EXPORT_SYMBOL(vfree);

代码注释里说 不能 在中断上下文中使用


原帖由 NewCore 于 2008-12-19 18:07 发表
这位师兄贴出来的是2.6.26的内核代码吧。

2.6引入了很多更高效的数据结构,为什么vm空间的管理还是用链表,感觉还有待优化。



我这个是 2.6.27 的代码
作者: windaoo    时间: 2008-12-20 12:53
标题: 回复 #7 windaoo 的帖子
突然想到,vfree 之所以不能在中断上下文中使用,应该就是因为那个 write_lock() 了
假如在中断上下文可以使用 vfree 的话,假设这样一个情况:
一个线程正好持有了这把锁,而这时候中断到来了,也要调 vfree ,想要得到这把锁——因为中断处理程序不能被重新调度,所以被中断的、执有这个锁的线程也得不到释放的机会——那么中断处理程序就会一直等待下去,从而造成死锁

不知道这样分析对否?
作者: vn42    时间: 2008-12-20 14:57
等vm多了之后会换成红黑树,6l不必担心啦
作者: vn42    时间: 2008-12-20 15:02
我想内核代码应该保证在中断上下文不会被抢占吧,lss解释似乎不合理
作者: NewCore    时间: 2008-12-27 17:56
原帖由 vn42 于 2008-12-20 14:57 发表
等vm多了之后会换成红黑树,6l不必担心啦


怎么不一开始就用红黑树,还要等多了才用?
作者: vn42    时间: 2008-12-27 20:22
少的时候不用红黑树反而快啊
作者: NewCore    时间: 2008-12-29 18:05
原帖由 vn42 于 2008-12-27 20:22 发表
少的时候不用红黑树反而快啊


这个就很难比较了,链表怎么说也是O(n)。

就像2.6以前,进程vm_area_struct还是用AVL树,2.6改成红黑树了,AVL和红黑树都是O(logN)的,但是红黑树的统计性能比AVL树高,“统计性能”如何定性比较?就像“少的时候不用红黑树反而快”一样。
作者: vn42    时间: 2008-12-29 19:55
经验




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2