PATA delays - nomis/sr-test GitHub Wiki

With a per-device sr_mutex, when there are two PATA devices (master and slave) on the same host, one of them is somehow inevitably blocked for over a second by the other. This can happen anywhere in the open/ioctl/close sequence.

3 out of 4 of the PATA devices return SCSI ASC 0x04 (LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE) on close immediately after closing the tray without any media, causing sr_check_events to decide that media is present. They then return 0x3A (MEDIUM NOT PRESENT) on the next open.

This causes a DISK_EVENT_MEDIA_CHANGE event that requires extra calls to revalidate_disk() on every open and close. The call to revalidate_disk() takes longer if the other device on the same host is concurrently opening or closing the tray.

If the pair of devices both have these DISK_EVENT_MEDIA_CHANGE events, they usually experience the same timing and the open is not delayed. Instead, the ioctl of one and the close from of the other will be delayed.

The SCSI host layer won't send more than one request at a time and the START_STOP commands take at least a second to return.

systemd-udevd

This process likes to interfere by opening and closing the device. Make sure it's stopped before testing.

systemctl stop systemd-udevd-kernel.socket
systemctl stop systemd-udevd-control.socket
systemctl stop udev

sr_block_open()

__blkdev_get() {
  sr_block_open() {
    check_disk_change() {
      disk_clear_events() {
        sr_check_events() {
          last_present (1) != cd->media_present (0), set cd->device->changed = 1
          pending event DISK_EVENT_MEDIA_CHANGE
        }
      }
      if (DISK_EVENT_MEDIA_CHANGE is pending) {
        flush_disk() {
          bdev->bd_invalidated = 1
        }
        revalidate_disk() {
          // A: +72ms
        }
      }
    }
  }
  bdev_disk_changed() {
    if (bdev->bd_invalidated) {
      revalidate_disk() {
        // B: +1.2s
      }
    }
  }
}

scsi_cmd_ioctl()

sr_block_release()

  sr_block_release() {
    sr_check_events() {
      last_present (0) != cd->media_present (1), set cd->device->changed = 1
      pending event DISK_EVENT_MEDIA_CHANGE
    }
  }