当与卡通信超时时,阻止MMC队列获取新请求

时间:2017-01-30 18:02:53

标签: linux-kernel arm sd-card omap

我们正在使用运行3.2版内核的自定义主板,但在测试MM​​C层的稳健性时,我们遇到了一些问题。

首先,我们的MMC插槽没有卡检测引脚。有问题包括以下内容:

  1. 加载模块(omap_hsmmc)。上电时检测到卡, 适当安装。
  2. 从SD卡中读取内容(即cat foo.txt
  3. 在阅读文件时,请取出卡片。
  4. 尝试失败后,系统挂起。
  5. 现在,我已将问题跟踪到drivers/mmc/card/queue.c中的以下代码部分:

    static int mmc_queue_thread(void *d)                                                                                    
    {                                                                                                                       
       struct mmc_queue *mq = d;                                                                                            
       struct request_queue *q = mq->queue;                                                                                 
    
       current->flags |= PF_MEMALLOC;                                                                                       
    
       down(&mq->thread_sem);                                                                                               
       do {                                                                                                                 
          struct request *req = NULL;                                                                                       
          struct mmc_queue_req *tmp;                                                                                        
    
          spin_lock_irq(q->queue_lock);                                                                                     
          set_current_state(TASK_INTERRUPTIBLE);                                                                            
          req = blk_fetch_request(q);                                                                                       
          mq->mqrq_cur->req = req;                                                                                          
          spin_unlock_irq(q->queue_lock);                                                                                   
    
          if (req || mq->mqrq_prev->req) {                                                                                  
             set_current_state(TASK_RUNNING);                                                                               
             mq->issue_fn(mq, req);                                                                                         
          } else {                                                                                                          
             if (kthread_should_stop()) {                                                                                   
                set_current_state(TASK_RUNNING);                                                                            
                break;                                                                                                      
             }                                                                                                              
             up(&mq->thread_sem);                                                                                           
             schedule();                                                                                                    
             down(&mq->thread_sem);                                                                                         
          }                                                                                                                 
    
          /* Current request becomes previous request and vice versa. */                                                    
          mq->mqrq_prev->brq.mrq.data = NULL;                                                                               
          mq->mqrq_prev->req = NULL;                                                                                        
          tmp = mq->mqrq_prev;                                                                                              
          mq->mqrq_prev = mq->mqrq_cur;                                                                                     
          mq->mqrq_cur = tmp;                                                                                               
       } while (1);                                                                                                         
       up(&mq->thread_sem);                                                                                                 
    
       return 0;                                                                                                            
    }
    

    调查此代码,我发现它在mq->issue_fn(mq, req)电话中挂起。此函数准备并发出适当的命令以填充传递给它的请求,并且它知道在它无法与卡通信时发生的任何错误。错误是以一种尴尬(在我看来)的方式处理的,并且没有“冒出来”。到mmc_queue_thread。但是,我已经检查了我的版本代码与最新内核版本(4.9)的代码,除了更好地分离每个错误案例之外,我没有看到对这些错误的处理有任何不同(治疗非常相似)。

    我怀疑这个问题是由于上层无法停止向MMC卡发出新的请求而引起的。

    我尝试过的事情:

    • 重新编写代码以便错误传递,以便我可以ret = mq->issue_fn(mq, req)
    • 由于能够识别特定错误,我尝试以不同方式取消该帖子:致电kthread_stop,致电mmc_queue_suspend__blk_end_request等。有了这些,我能够完成的最多的事情就是让线程保持在无害的状态。国家,它仍然存在,但没有消耗任何资源。但是,触发呼叫的用户空间程序不会返回,锁定在不间断状态。

    我的问题:

    1. 通过阻止上层提出新请求来解决这个问题的最佳方法是什么?或者该线程本身是否会被杀掉?
    2. 在像我这样的情况下,是否应该假设因为没有卡检测针,卡不应该被移除?
    3. 更新:我发现您可以告诉司机使用轮询来检测卡插入/移除。可以通过在驱动程序初始化时将MMC_CAP_NEEDS_POLL标志添加到mmc .caps来完成(在较新的内核上,您可以使用DT上的broken-cd属性)。但是,在此修改后问题仍然存在。

1 个答案:

答案 0 :(得分:1)

找出解决方案!

正如我所怀疑的那样,问题是即使在卡被移除后仍然会发出阻止请求。该错误已在a8ad82cc1b22d04916d9cdb1dc75052e80ac803c的提交Texas' kernel repository中修复:

commit a8ad82cc1b22d04916d9cdb1dc75052e80ac803c
Author: Sujit Reddy Thumma <sthumma@codeaurora.org>
Date:   Thu Dec 8 14:05:50 2011 +0530

    mmc: card: Kill block requests if card is removed

    Kill block requests when the host realizes that the card is
    removed from the slot and is sure that subsequent requests
    are bound to fail. Do this silently so that the block
    layer doesn't output unnecessary error messages.

    Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
    Acked-by: Adrian Hunter <adrian.hunter@intel.com>
    Signed-off-by: Chris Ball <cjb@laptop.org>

提交中的关键是return BLKPREP_KILL被添加到mmc_prep_request(),除了一些小的调整,为错误处理增加了一些“粒度”,为这些情况添加了一个特定的代码卡已被删除。