nswcfd 发表于 2015-12-21 16:43

还是由等待的事件源来wakeup要安全一些。

这种情况下,倒不如想办法终止或减少磁盘IO的频率?

bfdhczw 发表于 2015-12-21 17:20

回复 11# nswcfd


    我也想等到事件来源,但是现在系统已经不调度了,几乎是卡死状态,没法等到事件来源。
减少磁盘操作是不可能的,原因有两个
其一,这个进程的源码不在我们手上,
其二,这个进程本身是个下载器,不操作磁盘不可能。

所以,我现在期望能达到的最好效果就是,OOM的时候kill这个进程,保证系统不被卡死。

nswcfd 发表于 2015-12-22 16:10

11楼表达的不准确,意思是接管内核的disk io入口(hack/hack/hack),替换成空操作,避免新的io操作产生。
这样,旧的请求才能及时被旧的io模块满足,产生wakeup调用,进程才能结束D状态。

当然,也可以去模拟disk io的complete事件,终极目标是触发wakeup。
不太建议绕过io系统去直接wakeup处于D状态的进程,除非先cancel掉原来的wait。

不建议的原因是出于稳定性考虑。
waitq通常位于等待进程的stack上(类似DEFINE_WAIT),如果自行把进程wakeup,则进程会继续执行。
像楼主的例子,就响应OOM的kill signal结束进程了。
但是io子系统不知道这些事情,当事件完成后,依然会调用wakeup,去修改waitq的状态。
这时候就不知道会touch到谁的内存了。

bfdhczw 发表于 2015-12-24 15:04

回复 13# nswcfd


    我是这样做的,直接active,但还是杀不掉int kill_etm(void)
{
        int ret = 0;
        struct task_struct *p;

        read_lock(&tasklist_lock);
        for_each_process(p){
                if(!strcmp("my_process_name", p->comm)){
                        oom_kill_task(p, NULL);
                        ret = 1;
                        break;
                }
        }
        read_unlock(&tasklist_lock);

        if(likely(ret) && likely(p!=current)){
                printk("%s active %s and schedule()\n", __func__, p->comm);
                activate_task_priv(p);               
                schedule_timeout_uninterruptible(HZ>>2);
        }
       
        return ret;
}

nswcfd 发表于 2015-12-25 10:37

不好意思,忽略了一件事情,D状态是不考虑signal的。#define __wait_event(wq, condition)                                         \
do {                                                                        \
        DEFINE_WAIT(__wait);                                                \
                                                                        \
        for (;;) {                                                        \
                prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);        \
                if (condition)                                                \
                        break;                                                \
                schedule();                                                \
        }                                                                \
        finish_wait(&wq, &__wait);                                        \
} while (0)其中的schedule会被楼主显式的wake_up恢复,但是如果继续检查条件(IO未完成等),还是不满足,继续schedule。
关键还是得破坏(或者说满足)condition条件。

bfdhczw 发表于 2015-12-28 18:18

回复 15# nswcfd


    D状态不响应signal我是知道的,我理解的不响应只是暂时不响应,信号被挂起而已,等到进程退出D状态的时候,就会响应了。难道我理解错了?

bfdhczw 发表于 2015-12-29 10:35

本帖最后由 bfdhczw 于 2015-12-29 10:36 编辑

回复 15# nswcfd #define __wait_event(wq, condition)                                         \
do {                                                                        \
        DEFINE_WAIT(__wait);                                                \
                                                                        \
        for (;;) {                                                        \
                prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);        \
                if (condition)                                                \
                        break;                                                \
                if(current->force_quit)\
                        break;\
                schedule();                                                \
        }                                                                \
        finish_wait(&wq, &__wait);                                        \
        if(current->force_quit){\
                printk("=========> force_quit at %s\n", __func__);\
                force_sig(SIGKILL, current);\
        }\
} while (0)我把代码改成了这样,在task_struct里面加了force_quit成员,看起来wait queue上不会出什么问题,不知道会不会引起其他问题。
目前还没有测试结果,等后面有测试结果了,再继续更新状况。

nswcfd 发表于 2015-12-29 11:08

回复 16# bfdhczw
“退出D状态去响应信号”不会平白无故的发生,一定对应某个kernel code path,比如
1)等待的条件满足,结束wait_event循环,在核心态返回用户态的路径上检查信号处理;
2)像wait_event_interruptible那样,在wait循环里面,每次醒来之后显式的检查是否有信号发生,如果有退出循环,在返回用户态的路径上处理signal。


   
页: 1 [2]
查看完整版本: 【求助】OOM的时候kill进程失败