• Bart Van Assche's avatar
    block, scsi: Make SCSI quiesce and resume work reliably · 3a0a5299
    Bart Van Assche authored
    The contexts from which a SCSI device can be quiesced or resumed are:
    * Writing into /sys/class/scsi_device/*/device/state.
    * SCSI parallel (SPI) domain validation.
    * The SCSI device power management methods. See also scsi_bus_pm_ops.
    
    It is essential during suspend and resume that neither the filesystem
    state nor the filesystem metadata in RAM changes. This is why while
    the hibernation image is being written or restored that SCSI devices
    are quiesced. The SCSI core quiesces devices through scsi_device_quiesce()
    and scsi_device_resume(). In the SDEV_QUIESCE state execution of
    non-preempt requests is deferred. This is realized by returning
    BLKPREP_DEFER from inside scsi_prep_state_check() for quiesced SCSI
    devices. Avoid that a full queue prevents power management requests
    to be submitted by deferring allocation of non-preempt requests for
    devices in the quiesced state. This patch has been tested by running
    the following commands and by verifying that after each resume the
    fio job was still running:
    
    for ((i=0; i<10; i++)); do
      (
        cd /sys/block/md0/md &&
        while true; do
          [ "$(<sync_action)" = "idle" ] && echo check > sync_action
          sleep 1
        done
      ) &
      pids=($!)
      for d in /sys/class/block/sd*[a-z]; do
        bdev=${d#/sys/class/block/}
        hcil=$(readlink "$d/device")
        hcil=${hcil#../../../}
        echo 4 > "$d/queue/nr_requests"
        echo 1 > "/sys/class/scsi_device/$hcil/device/queue_depth"
        fio --name="$bdev" --filename="/dev/$bdev" --buffered=0 --bs=512 \
          --rw=randread --ioengine=libaio --numjobs=4 --iodepth=16       \
          --iodepth_batch=1 --thread --loops=$((2**31)) &
        pids+=($!)
      done
      sleep 1
      echo "$(date) Hibernating ..." >>hibernate-test-log.txt
      systemctl hibernate
      sleep 10
      kill "${pids[@]}"
      echo idle > /sys/block/md0/md/sync_action
      wait
      echo "$(date) Done." >>hibernate-test-log.txt
    done
    Reported-by: default avatarOleksandr Natalenko <oleksandr@natalenko.name>
    References: "I/O hangs after resuming from suspend-to-ram" (https://marc.info/?l=linux-block&m=150340235201348).
    Signed-off-by: default avatarBart Van Assche <bart.vanassche@wdc.com>
    Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
    Tested-by: default avatarMartin Steigerwald <martin@lichtvoll.de>
    Tested-by: default avatarOleksandr Natalenko <oleksandr@natalenko.name>
    Cc: Martin K. Petersen <martin.petersen@oracle.com>
    Cc: Ming Lei <ming.lei@redhat.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Cc: Johannes Thumshirn <jthumshirn@suse.de>
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    3a0a5299
block_dev.c 53.1 KB