Linux IO亂序

原創翻譯,轉載請註明出處。安全

 

在一些平臺,所謂的內存映射I/O在保序執行這方面是沒有保障的。在這些平臺,驅動寫入器負責保證I/O寫操做按照預期的順序寫到設備內存映射地址。翻譯

表明性的作法是經過讀取一個安全的設備或橋接寄存器,該寄存器能夠致使I/O芯片在任何讀操做發生前刷新全部帶處理的寫操做到設備上。rest

驅動一般在一退出由自旋鎖保護的臨界區代碼時就使用這種技術。這就能夠保證後發生的寫操做只能在以前已有的寫操做的後面執行,這個相似只對I/O操做使用一個內存屏障操做,mb()。

下面舉一個具體例子,假設一個設備驅動:code

        ...
CPU A:  spin_lock_irqsave(&dev_lock, flags)
CPU A:  val = readl(my_status);
CPU A:  ...
CPU A:  writel(newval, ring_ptr);
CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
        ...
CPU B:  spin_lock_irqsave(&dev_lock, flags)
CPU B:  val = readl(my_status);
CPU B:  ...
CPU B:  writel(newval2, ring_ptr);
CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
        ...


以上例子會發生設備可能接收到newval2在newval以前,這樣就會引發問題,須要以下修改才能正常:blog

        ...
CPU A:  spin_lock_irqsave(&dev_lock, flags)
CPU A:  val = readl(my_status);
CPU A:  ...
CPU A:  writel(newval, ring_ptr);
CPU A:  (void)readl(safe_register); /* maybe a config register? */
CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
        ...
CPU B:  spin_lock_irqsave(&dev_lock, flags)
CPU B:  val = readl(my_status);
CPU B:  ...
CPU B:  writel(newval2, ring_ptr);
CPU B:  (void)readl(safe_register); /* maybe a config register? */
CPU B:  spin_unlock_irqrestore(&dev_lock, flags)


這樣,想safe_register讀取就會讓I/O芯片在收到讀操做以前刷新以前的未處理的寫操做,從而防止數據污染。內存

相關文章
相關標籤/搜索