全部博文(33)
分类: LINUX
2009-09-22 09:31:07
前一段时间在研发、调试一个virtual scsi host时,遇到了一个锁的问题,这个问题也就是在spinlock的环境中调用了可能睡眠的函数,导致系统崩溃。在此,对这个问题进行一下总结。
从理论上讲spinlock环境是不能睡眠的,这需要分两种情况进行讨论。
1、 在spinlock_irq(关中断)的环境下,如果上下文(context)睡眠,那么极有可能导致Linux系统无法正常调度,并且Linux的心跳中断服务例程都无法调度,所以,很容易导致系统进入崩溃状态。
2、 在spinlock(不关中断)的环境下,如果上下文睡眠,那么被调度的上下文极有可能再次访问被锁保护的临界资源,从而导致系统死锁而崩溃。
从上面的分析来看,在spinlock保护的范围内是不能睡眠的。如果睡眠,将会导致系统的崩溃。
在编写virtual scsi host代码时,没有注意scsi middle level的queuecommand函数接口是在spinlock环境下调用的,而在virtual scsi host的queuecommand函数实现时,引入了generic_make_request函数,该函数是块设备层的转发处理函数,极有可能导致睡眠。
在generic_make_request函数中,会调用被转发设备的私有make_request函数,如果私有make_request函数调用了kmalloc等内存分配的函数,那么在有些情况下,调用generic_make_request将会进入睡眠状态。所以在测试过程中,如果对virtual scsi host写的数据流较多,那么系统崩溃,如果写的数据流较少,那么系统工作正常,因此,十分不稳定。系统崩溃的信息参考如下:
发现问题之后,对queuecommand函数进行了修改。在scsi host driver的queuecommand函数中只能处理简单的事物,例如将scsi command挂入需要处理的队列,然后唤醒处理队列中的daemon,在daemon的上下文对scsi middle level传下来的scsi command进行处理,例如调用generic_make_request等函数。经过上述方法修改之后,virtual scsi host系统能够稳定运行了~~