The following changes since commit bcd46be2adaa4afc32b836ad6137798544a3d80a: Merge branch 'atomic-writes' (2024-09-16 20:23:06 -0600) are available in the Git repository at: git://git.kernel.dk/fio.git master for you to fetch changes up to e4e8520b374e7e021d289d400ade70c41681d635: engines/io_uring: Fix negative errno in io_u->error (2024-09-27 04:18:26 -0600) ---------------------------------------------------------------- HuangShumin (1): Fix configure with --build-static which enables static RDMA in #1801 Jens Axboe (1): engines/io_uring: don't use abs() on an unsigned value Minwoo Im (4): io_uring: Add IO_U_F_DEVICE_ERROR to identify error types io_uring: Support Compare command for verification HOWTO: update 'verify_mode' for io_uring_cmd engines/io_uring: Fix negative errno in io_u->error Vincent Fu (6): ci: remove unneeded packages ci: only remove libunwind-14-dev if installed ci: handle sudo in actions-install.sh ci: build and run a QEMU guest VM for testing ci/cifuzz: update to upload-artifacts@v4 Merge branch 'master' of https://github.com/HuangShumin/fio .github/actions/build-qemu/action.yml | 31 ++++++++ .github/actions/create-guest-image/action.yml | 45 +++++++++++ .github/actions/start-vm/action.yml | 54 +++++++++++++ .github/workflows/cifuzz.yml | 2 +- .github/workflows/qemu.yml | 104 ++++++++++++++++++++++++++ HOWTO.rst | 9 +++ ci/actions-install.sh | 39 +++++----- configure | 6 +- engines/io_uring.c | 63 ++++++++++++++-- engines/nvme.c | 5 +- engines/nvme.h | 4 +- fio.1 | 14 ++++ io_u.c | 9 ++- io_u.h | 2 + verify.c | 7 ++ 15 files changed, 359 insertions(+), 35 deletions(-) create mode 100644 .github/actions/build-qemu/action.yml create mode 100644 .github/actions/create-guest-image/action.yml create mode 100644 .github/actions/start-vm/action.yml create mode 100644 .github/workflows/qemu.yml --- Diff of recent changes: diff --git a/.github/actions/build-qemu/action.yml b/.github/actions/build-qemu/action.yml new file mode 100644 index 00000000..06804b8b --- /dev/null +++ b/.github/actions/build-qemu/action.yml @@ -0,0 +1,31 @@ +name: 'Build and Install QEMU on Ubuntu' +desription: 'Build QEMU and Install on Ubuntu' + +inputs: + version: # What QEMU version to build/install + description: 'QEMU version to build and install' + required: false + default: '9.1.0' + + +runs: + using: "composite" + steps: + - name: Install QEMU build dependencies + run: sudo apt-get -qq install libglib2.0-dev libfdt-dev libpixman-1-dev ninja-build flex bison libsdl2-dev libaio-dev python3-tomli libslirp-dev + shell: bash + + - name: Build and install QEMU + run: | + wget -nv https://download.qemu.org/qemu-$INPUT_VER.tar.xz + tar xJf qemu-$INPUT_VER.tar.xz + rm qemu-$INPUT_VER.tar.xz + cd qemu-$INPUT_VER + ./configure --enable-kvm --target-list=x86_64-softmmu + make -j $(nproc) + sudo make install + cd .. + rm -rf qemu-$INPUT_VER + shell: bash + env: + INPUT_VER: ${{ inputs.version }} diff --git a/.github/actions/create-guest-image/action.yml b/.github/actions/create-guest-image/action.yml new file mode 100644 index 00000000..ce413378 --- /dev/null +++ b/.github/actions/create-guest-image/action.yml @@ -0,0 +1,45 @@ +name: 'Create guest image' +description: 'Create VM guest image on Ubuntu runner' + +inputs: + distro: + description: 'Linux distribution to use for guest image' + required: false + default: 'debian-12' + extra_pkgs: + description: 'Extra packages to install for guest image' + required: false + default: + +runs: + using: "composite" + steps: + - name: Install libguestfs + run: sudo apt-get -qq install libguestfs-tools + shell: bash + - name: Setup steps for virt-builder + run: | + sudo chmod a+r /boot/vmlinuz* + sudo chmod 0666 /dev/kvm + ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa + shell: bash + - name: Create Debian image + run: | + virt-builder ${{ inputs.distro }} \ + --quiet \ + --hostname fio-tester \ + --ssh-inject root \ + --run-command "ssh-keygen -A" \ + --run-command "sed -i 's/ens2/enp0s2/g' /etc/network/interfaces" \ + --append-line '/etc/environment:PYTHONUNBUFFERED=1' \ + --append-line '/etc/environment:GITHUB_SERVER_URL=${{ github.server_url }}' \ + --append-line '/etc/environment:GITHUB_REPOSITORY=${{ github.repository }}' \ + --append-line '/etc/environment:GITHUB_REF=${{ github.ref }}' \ + --append-line '/etc/environment:GITHUB_SHA=${{ github.sha }}' \ + --append-line '/etc/environment:GITHUB_JOB=${{ github.job }}' \ + --append-line '/etc/environment:EXTRA_PKGS=${{ inputs.extra_pkgs }}' \ + --append-line '/etc/environment:CI_TARGET_BUILD=${{ env.CI_TARGET_BUILD }}' \ + --append-line '/etc/environment:CI_TARGET_OS=${{ env.CI_TARGET_OS }}' + + shell: bash + diff --git a/.github/actions/start-vm/action.yml b/.github/actions/start-vm/action.yml new file mode 100644 index 00000000..d47977c4 --- /dev/null +++ b/.github/actions/start-vm/action.yml @@ -0,0 +1,54 @@ +name: 'Start QEMU VM' +description: 'Start QEMU virtual machine' + +inputs: + qemu: # QEMU binary to use + required: false + default: "qemu-system-x86_64" + image: # VM image file + required: true + ssh_fwd_port: # forward this host port to the guest's SSH port + required: false + default: 2022 + options: # Custom QEMU invocation options no \n at the end! + required: false + ram: # how much RAM to allocate to VM + required: false + default: "12G" + host_key: # If true add guest host key to known_hosts + required: false + default: "false" + +runs: + using: "composite" + steps: + - name: install wait-for-it + shell: bash + run: sudo apt-get -qq install wait-for-it + - name: Start VM in background + shell: bash + run: | + ${{ inputs.qemu }} \ + -cpu host \ + -drive file=${{ inputs.image }},format=raw,if=virtio \ + -enable-kvm \ + -smp $(nproc) \ + -nographic \ + -m ${{ inputs.ram }} \ + -display none \ + -machine q35,accel=kvm \ + -nic user,model=virtio-net-pci,hostfwd=tcp::${{ inputs.ssh_fwd_port }}-:22 \ + ${{ inputs.options }} \ + & + - name: Wait for VM to boot + shell: bash + run: | + wait-for-it localhost:${{ inputs.ssh_fwd_port }} -t 15 + sleep 3 + - name: Add guest host key to known_hosts + shell: bash + run: | + if echo ${{ inputs.host_key }} | grep -c "true" + then + ssh root@localhost -p ${{ inputs.ssh_fwd_port }} -o StrictHostKeyChecking=no echo + fi diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index acc8d482..9227735e 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -17,7 +17,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml new file mode 100644 index 00000000..4ba8bfae --- /dev/null +++ b/.github/workflows/qemu.yml @@ -0,0 +1,104 @@ +name: CI + +on: + schedule: + - cron: "50 3 * * *" # daily at 4:50 UTC (00:50 EST) + +jobs: + qemu-guest: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + include: + - config: basic io_uring_cmd tests + device: >- + -device nvme,id=nvme0,serial=deadbeef + -drive id=nvm-0,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk + -device nvme-ns,id=nvm-0,drive=nvm-0,bus=nvme0,nsid=1 + test_cmd: "python3 t/run-fio-tests.py --nvmecdev /dev/ng0n1 --run-only 1014 1015" + extra_pkgs: "nvme-cli" + - config: 16-bit Guard PI tests (long) + device: >- + -device nvme,id=nvme0,serial=deadbeef + -drive id=nvm-0,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk + -device nvme-ns,id=nvm-0,drive=nvm-0,bus=nvme0,nsid=1 + test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1" + extra_pkgs: "nvme-cli" + - config: 4K+16 w/64-bit Guard PI + device: >- # 4K+16 w/64-bit Guard PI + -device nvme,id=nvme1,serial=deadbeee + -drive id=nvm-1,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk + -device nvme-ns,id=nvm-1,drive=nvm-1,bus=nvme1,nsid=1,pif=2,ms=16,mset=1,pi=1,pil=0,logical_block_size=4096,physical_block_size=4096 + test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1 --lbaf 6" + extra_pkgs: "nvme-cli" + - config: 4K+64 w/64-bit Guard PI + device: >- + -device nvme,id=nvme2,serial=deadeeef + -drive id=nvm-2,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk + -device nvme-ns,id=nvm-2,drive=nvm-2,bus=nvme2,nsid=1,pif=2,ms=64,mset=1,pi=1,pil=0,logical_block_size=4096,physical_block_size=4096 + test_cmd: "python3 t/nvmept_pi.py --fio ./fio --dut /dev/ng0n1 --lbaf 7" + extra_pkgs: "nvme-cli" + - config: FDP + device: >- + -device nvme-subsys,id=nvme-subsys0,fdp=on,fdp.runs=128K,fdp.nrg=8,fdp.nruh=64 + -device nvme,id=nvme0,serial=deadbeef,subsys=nvme-subsys0 + -drive id=nvm-1,file=nvme0.img,format=raw,if=none,discard=unmap,media=disk + -device nvme-ns,id=nvm-1,drive=nvm-1,bus=nvme0,nsid=1,logical_block_size=4096,physical_block_size=4096,fdp.ruhs=0-63 + test_cmd: "nvme fdp status /dev/ng0n1 && python3 t/nvmept_fdp.py --fio ./fio --dut /dev/ng0n1" + extra_pkgs: "nvme-cli" + - config: ZBD + device: + test_cmd: "./t/zbd/run-tests-against-nullb" + extra_pkgs: sg3-utils + + env: + DISTRO: debian-12 + SSHCMD: ssh root@localhost -p 2022 + CI_TARGET_BUILD: linux + CI_TARGET_OS: debian + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Create guest VM image + uses: ./.github/actions/create-guest-image + with: + distro: ${{ env.DISTRO }} + extra_pkgs: ${{ matrix.extra_pkgs }} + + - name: Build and install QEMU + uses: ./.github/actions/build-qemu + + - name: Create backing file for NVMe device + run: truncate -s 1G nvme0.img + + - name: Start VM + uses: ./.github/actions/start-vm + with: + image: ${{ env.DISTRO }}.img + host_key: true + options: ${{ matrix.device }} + + - name: Clone fio on guest + run: | + $SSHCMD "apt-get update && apt-get install -qq git" + $SSHCMD "git clone https://github.com/taiki-e/checkout-action --branch v1.3.0" + $SSHCMD "mkdir fio && cd fio && ../checkout-action/main.sh && git log -1" + + - name: Install dependencies on guest + run: $SSHCMD "cd fio && ./ci/actions-install.sh" + + - name: Build fio on guest + run: $SSHCMD "cd fio && ./ci/actions-build.sh" + + - name: Show nvme device configuration + if: ${{ contains( matrix.extra_pkgs, 'nvme-cli' ) }} + run: | + $SSHCMD "nvme id-ns /dev/ng0n1 -H" + $SSHCMD "nvme nvm-id-ns /dev/ng0n1 -v" + + - name: Run test + run: $SSHCMD "cd fio && ${{ matrix.test_cmd }}" diff --git a/HOWTO.rst b/HOWTO.rst index 4f071484..539bce19 100644 --- a/HOWTO.rst +++ b/HOWTO.rst @@ -2883,6 +2883,15 @@ with the caveat that when used on the command line, they must come after the **verify** Use Verify commands for write operations +.. option:: verify_mode=str : [io_uring_cmd] + + Specifies the type of command to be used in the verification phase. Defaults to 'read'. + + **read** + Use Read commands for data verification + **compare** + Use Compare commands for data verification + .. option:: sg_write_mode=str : [sg] Specify the type of write commands to issue. This option can take ten values: diff --git a/ci/actions-install.sh b/ci/actions-install.sh index 7a87fbe3..5a32ec91 100755 --- a/ci/actions-install.sh +++ b/ci/actions-install.sh @@ -6,16 +6,18 @@ SCRIPT_DIR=$(dirname "$0") # shellcheck disable=SC1091 . "${SCRIPT_DIR}/common.sh" +_sudo() { + if type -P sudo >/dev/null; then + sudo "$@" + else + "$@" + fi +} + install_ubuntu() { local pkgs - if [ "${GITHUB_JOB}" == "build-containers" ]; then - # containers run as root and do not have sudo - apt update - apt -y install sudo - fi - - cat <<DPKGCFG | sudo tee /etc/dpkg/dpkg.cfg.d/dpkg-speedup > /dev/null + cat <<DPKGCFG | _sudo tee /etc/dpkg/dpkg.cfg.d/dpkg-speedup > /dev/null # Skip fsync force-unsafe-io # Don't install documentation @@ -36,7 +38,7 @@ DPKGCFG ) case "${CI_TARGET_ARCH}" in "i686") - sudo dpkg --add-architecture i386 + _sudo dpkg --add-architecture i386 pkgs=("${pkgs[@]/%/:i386}") pkgs+=( gcc-multilib @@ -60,8 +62,10 @@ DPKGCFG librdmacm-dev pkg-config ) - echo "Removing libunwind-14-dev because of conflicts with libunwind-dev" - sudo apt remove -y libunwind-14-dev + if apt list --installed | grep -c "libunwind-14-dev"; then + echo "Removing libunwind-14-dev because of conflicts with libunwind-dev" + _sudo apt remove -y libunwind-14-dev + fi if [ "${CI_TARGET_OS}" == "linux" ] || [ "${CI_TARGET_OS}" == "ubuntu" ]; then # Only for Ubuntu pkgs+=( @@ -77,23 +81,22 @@ DPKGCFG python3-scipy python3-sphinx python3-statsmodels + sudo + ${EXTRA_PKGS:-} ) - if [ "${GITHUB_JOB}" == "build-containers" ]; then + if [ "${GITHUB_JOB}" == "build-containers" ] || [ "${GITHUB_JOB}" == "qemu-guest" ]; then pkgs+=( bison build-essential - cmake flex - unzip - wget zlib1g-dev ) fi echo "Updating APT..." - sudo apt-get -qq update + _sudo apt-get -qq update echo "Installing packages... ${pkgs[@]}" - sudo apt-get install -o APT::Immediate-Configure=false --no-install-recommends -qq -y "${pkgs[@]}" + _sudo apt-get install -o APT::Immediate-Configure=false --no-install-recommends -qq -y "${pkgs[@]}" } # Fedora and related distributions @@ -101,7 +104,6 @@ install_fedora() { pkgs=( bison-devel git - cmake flex-devel gperftools isa-l-devel @@ -119,9 +121,8 @@ install_fedora() { python3-scipy python3-sphinx sudo - unzip valgrind-devel - wget + ${EXTRA_PKGS:-} ) case "${CI_TARGET_OS}" in diff --git a/configure b/configure index eb92cde3..715f0602 100755 --- a/configure +++ b/configure @@ -1005,8 +1005,9 @@ int main(int argc, char **argv) return pd != NULL; } EOF -if test "$disable_rdma" != "yes" && compile_prog "" "-libverbs" "libverbs" ; then +if test "$disable_rdma" != "yes" && compile_prog "" "-libverbs -lnl-3 -lnl-route-3" "libverbs" ; then libverbs="yes" + LIBS="-libverbs -lnl-3 -lnl-route-3 $LIBS" fi print_config "libverbs" "$libverbs" @@ -1024,8 +1025,9 @@ int main(int argc, char **argv) return 0; } EOF -if test "$disable_rdma" != "yes" && compile_prog "" "-lrdmacm" "rdma"; then +if test "$disable_rdma" != "yes" && compile_prog "" "-lrdmacm -lnl-3 -lnl-route-3" "rdma"; then rdmacm="yes" + LIBS="-libverbs -lnl-3 -lnl-route-3 $LIBS" fi print_config "rdmacm" "$rdmacm" diff --git a/engines/io_uring.c b/engines/io_uring.c index 96a042a8..85cebf83 100644 --- a/engines/io_uring.c +++ b/engines/io_uring.c @@ -41,6 +41,11 @@ enum uring_cmd_write_mode { FIO_URING_CMD_WMODE_VERIFY, }; +enum uring_cmd_verify_mode { + FIO_URING_CMD_VMODE_READ = 1, + FIO_URING_CMD_VMODE_COMPARE, +}; + struct io_sq_ring { unsigned *head; unsigned *tail; @@ -99,6 +104,7 @@ struct ioring_options { unsigned int readfua; unsigned int writefua; unsigned int write_mode; + unsigned int verify_mode; struct cmdprio_options cmdprio_options; unsigned int fixedbufs; unsigned int registerfiles; @@ -194,6 +200,26 @@ static struct fio_option options[] = { .category = FIO_OPT_C_ENGINE, .group = FIO_OPT_G_IOURING, }, + { + .name = "verify_mode", + .lname = "Do verify based on the configured command (e.g., Read or Compare command)", + .type = FIO_OPT_STR, + .off1 = offsetof(struct ioring_options, verify_mode), + .help = "Issue Read or Compare command in the verification phase", + .def = "read", + .posval = { + { .ival = "read", + .oval = FIO_URING_CMD_VMODE_READ, + .help = "Issue Read commands in the verification phase" + }, + { .ival = "compare", + .oval = FIO_URING_CMD_VMODE_COMPARE, + .help = "Issue Compare commands in the verification phase" + }, + }, + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_IOURING, + }, { .name = "fixedbufs", .lname = "Fixed (pre-mapped) IO buffers", @@ -443,6 +469,7 @@ static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u) struct nvme_dsm *dsm; void *ptr = ld->dsm; unsigned int dsm_size; + uint8_t read_opcode = nvme_cmd_read; /* only supports nvme_uring_cmd */ if (o->cmd_type != FIO_URING_CMD_NVME) @@ -483,9 +510,21 @@ static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u) ptr += io_u->index * dsm_size; dsm = (struct nvme_dsm *)ptr; + /* + * If READ command belongs to the verification phase and the + * verify_mode=compare, convert READ to COMPARE command. + */ + if (io_u->flags & IO_U_F_VER_LIST && io_u->ddir == DDIR_READ && + o->verify_mode == FIO_URING_CMD_VMODE_COMPARE) { + populate_verify_io_u(td, io_u); + read_opcode = nvme_cmd_compare; + io_u_set(td, io_u, IO_U_F_VER_IN_DEV); + } + return fio_nvme_uring_cmd_prep(cmd, io_u, o->nonvectored ? NULL : &ld->iovecs[io_u->index], - dsm, ld->write_opcode, ld->cdw12_flags[io_u->ddir]); + dsm, read_opcode, ld->write_opcode, + ld->cdw12_flags[io_u->ddir]); } static struct io_u *fio_ioring_event(struct thread_data *td, int event) @@ -528,12 +567,9 @@ static struct io_u *fio_ioring_cmd_event(struct thread_data *td, int event) cqe = &ld->cq_ring.cqes[index]; io_u = (struct io_u *) (uintptr_t) cqe->user_data; - if (cqe->res != 0) { - io_u->error = abs(cqe->res); - return io_u; - } else { - io_u->error = 0; - } + io_u->error = cqe->res; + if (io_u->error != 0) + goto ret; if (o->cmd_type == FIO_URING_CMD_NVME) { data = FILE_ENG_DATA(io_u->file); @@ -544,6 +580,16 @@ static struct io_u *fio_ioring_cmd_event(struct thread_data *td, int event) } } +ret: + /* + * If IO_U_F_DEVICE_ERROR is not set, io_u->error will be parsed as an + * errno, otherwise device-specific error value (status value in CQE). + */ + if ((int)io_u->error > 0) + io_u_set(td, io_u, IO_U_F_DEVICE_ERROR); + else + io_u_clear(td, io_u, IO_U_F_DEVICE_ERROR); + io_u->error = abs((int)io_u->error); return io_u; } @@ -557,6 +603,9 @@ static char *fio_ioring_cmd_errdetails(struct thread_data *td, #define MAXMSGCHUNK 128 char *msg, msgchunk[MAXMSGCHUNK]; + if (!(io_u->flags & IO_U_F_DEVICE_ERROR)) + return NULL; + msg = calloc(1, MAXERRDETAIL); strcpy(msg, "io_uring_cmd: "); diff --git a/engines/nvme.c b/engines/nvme.c index 33d87477..18010c0b 100644 --- a/engines/nvme.c +++ b/engines/nvme.c @@ -363,7 +363,8 @@ void fio_nvme_uring_cmd_trim_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u, int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u, struct iovec *iov, struct nvme_dsm *dsm, - uint8_t write_opcode, unsigned int cdw12_flags) + uint8_t read_opcode, uint8_t write_opcode, + unsigned int cdw12_flags) { struct nvme_data *data = FILE_ENG_DATA(io_u->file); __u64 slba; @@ -373,7 +374,7 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u, switch (io_u->ddir) { case DDIR_READ: - cmd->opcode = nvme_cmd_read; + cmd->opcode = read_opcode; break; case DDIR_WRITE: cmd->opcode = write_opcode; diff --git a/engines/nvme.h b/engines/nvme.h index b5fef2fb..60b38d7f 100644 --- a/engines/nvme.h +++ b/engines/nvme.h @@ -77,6 +77,7 @@ enum nvme_io_opcode { nvme_cmd_write = 0x01, nvme_cmd_read = 0x02, nvme_cmd_write_uncor = 0x04, + nvme_cmd_compare = 0x05, nvme_cmd_write_zeroes = 0x08, nvme_cmd_dsm = 0x09, nvme_cmd_verify = 0x0c, @@ -431,7 +432,8 @@ int fio_nvme_get_info(struct fio_file *f, __u64 *nlba, __u32 pi_act, int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u, struct iovec *iov, struct nvme_dsm *dsm, - uint8_t write_opcode, unsigned int cdw12_flags); + uint8_t read_opcode, uint8_t write_opcode, + unsigned int cdw12_flags); void fio_nvme_pi_fill(struct nvme_uring_cmd *cmd, struct io_u *io_u, struct nvme_cmd_ext_io_opts *opts); diff --git a/fio.1 b/fio.1 index 0fd0fb25..356980b5 100644 --- a/fio.1 +++ b/fio.1 @@ -2675,6 +2675,20 @@ Use Verify commands for write operations .RE .RE .TP +.BI (io_uring_cmd)verify_mode \fR=\fPstr +Specifies the type of command to be used in the verification phase. Defaults to 'read'. +.RS +.RS +.TP +.B read +Use Read commands for data verification +.TP +.B compare +Use Compare commands for data verification +.TP +.RE +.RE +.TP .BI (sg)sg_write_mode \fR=\fPstr Specify the type of write commands to issue. This option can take multiple values: diff --git a/io_u.c b/io_u.c index c49cd4df..b699169d 100644 --- a/io_u.c +++ b/io_u.c @@ -1956,7 +1956,8 @@ static void __io_u_log_error(struct thread_data *td, struct io_u *io_u) log_err("fio: io_u error%s%s: %s: %s offset=%llu, buflen=%llu\n", io_u->file ? " on file " : "", io_u->file ? io_u->file->file_name : "", - strerror(io_u->error), + (io_u->flags & IO_U_F_DEVICE_ERROR) ? + "Device-specific error" : strerror(io_u->error), io_ddir_name(io_u->ddir), io_u->offset, io_u->xfer_buflen); @@ -1965,8 +1966,10 @@ static void __io_u_log_error(struct thread_data *td, struct io_u *io_u) if (td->io_ops->errdetails) { char *err = td->io_ops->errdetails(td, io_u); - log_err("fio: %s\n", err); - free(err); + if (err) { + log_err("fio: %s\n", err); + free(err); + } } if (!td->error) diff --git a/io_u.h b/io_u.h index ab93d50f..22ae6ed4 100644 --- a/io_u.h +++ b/io_u.h @@ -22,6 +22,8 @@ enum { IO_U_F_BARRIER = 1 << 6, IO_U_F_VER_LIST = 1 << 7, IO_U_F_PATTERN_DONE = 1 << 8, + IO_U_F_DEVICE_ERROR = 1 << 9, + IO_U_F_VER_IN_DEV = 1 << 10, /* Verify data in device */ }; /* diff --git a/verify.c b/verify.c index f3d228ba..2e113862 100644 --- a/verify.c +++ b/verify.c @@ -901,6 +901,13 @@ int verify_io_u(struct thread_data *td, struct io_u **io_u_ptr) if (td_ioengine_flagged(td, FIO_FAKEIO)) return 0; + /* + * If data has already been verified from the device, we can skip + * the actual verification phase here. + */ + if (io_u->flags & IO_U_F_VER_IN_DEV) + return 0; + if (io_u->flags & IO_U_F_TRIMMED) { ret = verify_trimmed_io_u(td, io_u); goto done;