zoukankan      html  css  js  c++  java
  • Linux IO乱序

    原创翻译,转载请注明出处。

    在一些平台,所谓的内存映射I/O在保序执行这方面是没有保障的。在这些平台,驱动写入器负责保证I/O写操作按照预期的顺序写到设备内存映射地址。

    代表性的做法是通过读取一个安全的设备或桥接寄存器,该寄存器可以导致I/O芯片在任何读操作发生前刷新所有带处理的写操作到设备上。

    驱动通常在一退出由自旋锁保护的临界区代码时就使用这种技术。这就可以保证后发生的写操作只能在之前已有的写操作的后面执行,这个类似只对I/O操作使用一个内存屏障操作,mb()。

    下面举一个具体例子,假设一个设备驱动:

            ...
    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之前,这样就会引起问题,需要如下修改才能正常:

            ...
    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芯片在收到读操作之前刷新之前的未处理的写操作,从而防止数据污染。

  • 相关阅读:
    设计模式之美学习-设计原则-面向对象基本概念(一)
    redis-分布式锁-设计与使用
    linux常用命令记录(一)
    redis-布隆过滤器使用
    jdk源码阅读-ConcurrentLinkedQueue(一)
    支付宝支付接口-app支付沙箱环境
    RocketMQ-安装
    支付宝支付接口-运行支付宝demo
    elasticsearch-文档-父子文档(十一)
    RTMPdump 源代码分析 1: main()函数
  • 原文地址:https://www.cnblogs.com/danxi/p/6647425.html
Copyright © 2011-2022 走看看