Skip to content

[pull] master from axboe:master - #314

Open
pull[bot] wants to merge 1499 commits into
kubestone:masterfrom
axboe:master
Open

pull[bot] wants to merge 1499 commits into
kubestone:masterfrom
axboe:master

Conversation

@pull

@pull pull Bot commented Dec 10, 2021

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot]

Can you help keep this open source service alive? 💖 Please sponsor : )

geertj and others added 27 commits November 23, 2025 21:02
This fixes the offset/size calculation when "offset" > 0. Previously this had:

        fmd->mmap_sz = f->io_size;
        fmd->mmap_off = 0;

This is correct only when "offset" (ie f->file_offset) = 0. We can fix this by
either keeping the offset at 0, and map the entire file, or by keeping the size
at f->io_size and setting mmap_off = f->file_offset. On 64-bit there isn't much
difference but on 32-bit the second option is better as it maps less memory.
This patch therefore takes the second approach.

Signed-off-by: Geert Jansen <geertj@google.com>
The engine supports a "full" mode where the entire range for a job is mapped,
and a "limited" mode that tries to map less memory. This fixes a bug and
implements the following simplified logic:

- If we are on a 64-bit architecture, or if io_size <= mmap_map_size, then we
  map the entire io_size region, and re-use for all IO.
- Otherwise, we map the range for each individual IOs.

Previously, we would fallback to limited mode in case of 32-bit overflow of the
job size. That isn't strict enough as we want to stay below mmap_map_size for a
single mapping. This fixes that.

Also, in limited mode, this code previously tried to map min(io_size,
mmap_map_size) bytes, starting at the offset. This could allow a future IO use
the same mapping if happens at a higher offset. I think it's better to keep it
simple and get the consistent performance of always having one mmap per IO in
limited mode.

Signed-off-by: Geert Jansen <geertj@google.com>
The patch adds support for sync operations to the fileoperations, ftruncate, and falloc ioengines.

Signed-off-by: Sergei Truschev <s.truschev@yadro.com>
* 'mmap-fixes' of https://github.com/geertj/fio:
  engines/mmap: fix full/limited prep logic
  engines/mmap: fix logic when "offset" > 0
  engines/mmap: support fadvise_hint
gnutls is required newwer version of libnfs, and so we need to check
for this. libnfs version 6.0.0 and later added TLS support. Earlier versions
like 5.0.x do not require gnutls.

Add a version check in the configure script to detect the libnfs version
and only add gnutls as a dependency when libnfs >= 6.0.0 is detected.

For systems with older libnfs versions, the build will work without
requiring gnutls. For systems with libnfs 6.0.0+, gnutls will be
properly detected and linked.

Generated-by: Claude AI
Reviewed-by: Vincent Fu <vincent.fu@samsung.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Extract the long if condition in str_steadystate_cb() into a separate
helper function is_valid_steadystate() for better readability and
maintainability.

Generated-by: Claude AI
Reviewed-by: Vincent Fu <vincent.fu@samsung.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Extract the common logic from steadystate_bw_mean() and steadystate_iops_mean()
into a helper function steadystate_data_mean() to reduce code duplication and
improve maintainability.

Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Add fio latency steady state support. The implementation calculates
weighted average latency across all I/O directions and supports both
maximum mean deviation and slope-based detection methods.

We bump FIO_SERVER_VER since struct thread_stat has changed.

Tested successfully against NVMe device with debug output confirming
proper latency calculation and steady state evaluation.

Quick demo with the null engine:

fio --name=test --ioengine=null --size=1G --rw=randread --bs=4k --iodepth=64 --steadystate=lat:100us --ss_dur=10s --runtime=120s --time_based=1
test: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=null, iodepth=64
fio-3.41-20-gf2b2e-dirty
Starting 1 process
Jobs: 1 (f=1): [f(1)][100.0%][r=15.6GiB/s][r=4078k IOPS][eta 00m:00s]
test: (groupid=0, jobs=1): err= 0: pid=1207074: Tue Oct  7 11:47:27 2025
  read: IOPS=4054k, BW=15.5GiB/s (16.6GB/s)(153GiB/9899msec)
    slat (nsec): min=18, max=33347, avg=22.20, stdev=64.49
    clat (nsec): min=135, max=42283, avg=152.74, stdev=173.53
     lat (nsec): min=156, max=42306, avg=174.94, stdev=185.32
    clat percentiles (nsec):
     |  1.00th=[  139],  5.00th=[  141], 10.00th=[  141], 20.00th=[  143],
     | 30.00th=[  143], 40.00th=[  145], 50.00th=[  147], 60.00th=[  153],
     | 70.00th=[  155], 80.00th=[  157], 90.00th=[  163], 95.00th=[  171],
     | 99.00th=[  217], 99.50th=[  221], 99.90th=[  239], 99.95th=[  270],
     | 99.99th=[ 2096]
   bw (  MiB/s): min=15344, max=15944, per=100.00%, avg=15835.92, stdev=132.94, samples=19
   iops        : min=3928298, max=4081694, avg=4053996.63, stdev=34033.65, samples=19
  lat (nsec)   : 250=99.93%, 500=0.06%, 750=0.01%, 1000=0.01%
  lat (usec)   : 2=0.01%, 4=0.01%, 10=0.01%, 20=0.01%, 50=0.01%
  cpu          : usr=99.93%, sys=0.03%, ctx=88, majf=0, minf=6
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=40129848,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64
  steadystate  : attained=yes, bw=15.2GiB/s (15.9GB/s), iops=3976k, lat=152nsec, lat mean dev=2.700

Run status group 0 (all jobs):
   READ: bw=15.5GiB/s (16.6GB/s), 15.5GiB/s-15.5GiB/s (16.6GB/s-16.6GB/s), io=153GiB (164GB), run=9899-9899msec

Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Introduce a mock test framework to validate specific algorithms and
calculations in isolation. This allows testing numerical precision,
edge cases, and algorithmic correctness without requiring the full
FIO infrastructure.

Features:
- TAP (Test Anything Protocol) output for CI integration
- Isolated testing of specific calculations
- Clear documentation of test purposes and goals
- Simple make target: 'make mock-tests'

The first test validates the numerical precision improvements in
steady state latency calculations, demonstrating how the framework
can catch subtle precision and overflow issues.

Structure:
- mock-tests/lib/tap.h: TAP output support
- mock-tests/tests/: Individual test programs
- mock-tests/Makefile: Build system
- mock-tests/README.md: Comprehensive documentation

This framework complements the existing integration tests by focusing
on unit-level validation of critical calculations.

Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
When fio has issued 884 billion IOs it is still aable to recover per
second latencies with less than 0.1% error using a latency value of
13ms. This is evidence that fio's strategy for estimating per second
latency for steady state detection works reasonably well.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
When rate limiting is enabled, do_io() calls usec_for_io() to calculate
delays.

If the current operation is a sync (DDIR_SYNC), using it as an index into
arrays sized DDIR_RWDIR_CNT (such as td->rate_bps) results in an
out-of-bounds access.

Guard the rate limiting check in do_io() with ddir_rw() to ensure it only
applies to READ, WRITE, and TRIM operations.

This fixes a UBSAN out-of-bounds error reported in usec_for_io().

Signed-off-by: Florian Mayer <fmayer@google.com>
* 'patch-1' of https://github.com/fmayer/fio:
  backend: fix OOB access in usec_for_io() with DDIR_SYNC
This commit fixes the build on musl which fails with the following
error:
```
oslib/linux-blkzoned.c: In function 'blkzoned_move_zone_wp':
oslib/linux-blkzoned.c:389:37: error: 'FALLOC_FL_ZERO_RANGE' undeclared (first use in this function)
  389 |                 ret = fallocate(fd, FALLOC_FL_ZERO_RANGE, z->wp, length);
      |                                     ^~~~~~~~~~~~~~~~~~~~
oslib/linux-blkzoned.c:389:37: note: each undeclared identifier is reported only once for each function it appears in
make: *** [Makefile:501: oslib/linux-blkzoned.o] Error 1
make: *** Waiting for unfinished jobs....
```

Signed-off-by: Arthur Gautier <arthur.gautier@arista.com>
If fio is run with md_per_io_size but no pi_chk argument,
fio_ioring_io_u_init() passes NULL to strstr(), which segfaults. Use the
struct ioring_options prchk flags instead, which have already been
parsed from pi_chk in parse_prchk_flags().

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
* 'fix/prchk-segfault' of https://github.com/calebsander/fio:
  io_uring: don't segfault if pi_chk isn't specified
…m/mcgrof/fio

* '20251023-steady-state-add-latency' of https://github.com/mcgrof/fio:
  mock-tests: assess per second latency recovery
  fio: add mock test framework for isolated unit testing
  fio: add latency steady state detection
  fio: refactor duplicate code in steadystate_*_mean functions
  fio: refactor steady state validation check
  configure: conditionally add gnutls for libnfs >= 6.0.0
For the JSON output latency measurements make the units explicit by
changing the name of the array to lat_ns.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
We have been running out of storage on GitHub-hosted runners in our
automated tests. Add a 'cleanup' option to delete artifacts of
successful tests as we are running.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
We have been running out of storage space on our GitHub-host runners for
our automated tests. Enable the option to delete artifacts for
successful tests as we are running.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Since `td->client_type` is always non-zero (CLI is 1, GUI is 2), the check
`if (td->client_type)` in `init.c` always triggers, causing --write_hist_log
to be unusable when ZLIB is not configured for standalone runs.
By checking if the fio instance `is_backend`, ZLIB availability will be
checked for fio running as server in server/client mode, and the check
will be passed for fio running in standalone mode.
* 'master' of https://github.com/alex310110/fio:
  write_hist_log: do not require ZLIB for non-server instances
Rename in_ramp_time() and ramp_time_over() to in_ramp_period() and
ramp_period_over() respectively. We will be adding other not time-based
methods for determining whether the load is ramping up so the old names
would be confusing.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20251219134247.14195-1-jack@suse.cz
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Instead of checking whether ramp_time is specified each time we need to
check whether we are in the ramp period, initialize ramp_period_over
based on the ramp_time option. This will simplify things more
significantly later when ramp up period can be defined in a different
way.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20251219134247.14195-2-jack@suse.cz
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20251219134247.14195-3-jack@suse.cz
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Instead of evaluating whether ramp up period has finished on each IO
submission and completion evaluate it once per second and set
appropriate state variable in thread_data. Later when ramp up period end
condition will be more complex and would involve stat data from all
threads, it would unnecessarily slow down IO.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20251219134247.14195-4-jack@suse.cz
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
In some cases the ramp up period is not easy to define by amount of
time. This is for example a case of buffered writes measurement where we
want to start measuring only once dirty throttling kicks in. The time
until dirty throttling kicks in depends on dirty limit (easy to figure
out) and speed of writes to the page cache (difficult to know in
advance). Add option ramp_size which determines the ramp up period by
the amount of IO written (either by each job or by each group when group
reporting is enabled).

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20251219134247.14195-5-jack@suse.cz
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
vincentkfu and others added 30 commits July 27, 2026 12:19
Fio had a bug where it would mistakenly account for trim sizes when
allocating memory for data buffers when issuing commands from an iolog.
Add this test case to catch possible regressions.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Add the copyright header to bsg.c and bsg.h, which provide BSG
(Block SCSI Generic) support for the io_uring_cmd engine. The
files were previously committed without a license header.

Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
When a forked job process dies from a fatal signal (SIGABRT from a
failed assert(), SIGSEGV, OOM kill), reap_threads() logs
"fio: pid=..., got signal=..." and records td->sig, but never sets
td->error. The reaped: label only counts td->error into exit_value, so
the main fio process exits 0 and the job summary prints err= 0 for the
crashed job. The WIFEXITED branch right below does propagate a
non-zero exit status, so a worker that exits(1) fails the run while a
worker that crashes reports success, defeating any automation that
checks fio's exit code.

Mark an unexpectedly signaled worker as failed by setting td->error
(EINTR) next to the existing log_err. SIGTERM and SIGUSR2 stay
excluded, matching the log message: fio uses them for orderly
termination. Setting td->error rather than bumping exit_value directly
keeps the accounting in one place and makes the job summary show a
non-zero err for the crashed job.

Tested by sending SIGABRT to one worker of a two-job process-based
run: the crashed job now reports err= 4 and fio exits 1 (both were 0
before); a crash-free run still reports err= 0 for all jobs and
exits 0.

Fixes: #2127

Signed-off-by: Vlad Tudose <tudosevt@amazon.com>
* 'add_copyright' of https://github.com/ljw8161/fio:
  engines/io_uring: add copyright header to bsg files
…tes130272/fio

* 'feat/hipfile-upstream-rebase' of https://github.com/sbates130272/fio:
  examples/doc: add libhipfile example job files and documentation
  engines/libhipfile: add ROCm hipFile engine
  engines/gpuaccel: add per-backend sync flags and backend-scoped state
  engines: refactor libcufile.c into a shared gpuaccel layer
An example job file was accidentally committed to the repository root
directory. Move it to the examples directory.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
fio_ioring_cmd_init() assigns ld->write_opcode = bsg_cmd_write_10 when
cmd_type=bsg, but that field is never read on the bsg submission path.
fio_bsg_uring_cmd_prep() fills bc->cdb[0] directly from io_u->ddir, and
ld->write_opcode is only consumed by fio_nvme_uring_cmd_prep() on the
nvme path. The assignment has therefore never had any effect.

Drop the dead assignment. The surrounding `if (write_mode == WRITE)`
branch existed only to hold it; once the assignment is gone the branch
is empty, so the check collapses to a plain rejection of unsupported
write modes.

Fixes: d77ed2b ("engines/io_uring: Add bsg support for io_uring_cmd engine")
Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
The bsg completion was being parsed in two places:
fio_ioring_cmd_event() decoded the packed SCSI status from
cqe->big_cqe[0] into io_u->error, and fio_ioring_cmd_errdetails()
re-derived the SCSI status and host status from io_u->error. The NVMe
path only does this breakdown once, in errdetails.

Drop the bsg-specific decoding from event and store the raw
cqe->big_cqe[0] in io_u->error, leaving errdetails as the single place
that splits the SCSI status (bits 0-7) and host status (bits 16-23).

Fixes: d77ed2b ("engines/io_uring: Add bsg support for io_uring_cmd engine")
Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
The bsg cmd_type of the io_uring_cmd engine has so far hardcoded
READ(10) and WRITE(10) for DDIR_READ and DDIR_WRITE. That caps the
supported LBA range at 32 bits and the transfer length at 65535
blocks, which prevents benchmarking devices whose capacity or per-I/O
transfer size exceeds those limits, and it also prevents comparing the
performance characteristics of different CDB lengths of the same
command.

Add a new engine option, cdb_len, that selects the SCSI CDB length
used for READ/WRITE commands. Supported values are 10, 16, and 32.
The 32-byte command is encoded as a variable-length CDB (opcode 0x7F)
with the READ(32) and WRITE(32) service actions.

The default is 0 (auto): the smallest CDB whose LBA and
transfer-length fields can hold the request is chosen, escalating from
READ(10)/WRITE(10) to READ(16)/WRITE(16) as the LBA or transfer
length grows, mirroring the sg engine. This lets fio drive devices
whose capacity or per-I/O size exceeds the 10-byte limits without
requiring the user to pick a CDB length up front. The 32-byte CDB
shares the same 64-bit LBA and 32-bit length field widths as the
16-byte CDB, so auto-escalation never reaches it and it remains
opt-in only (for exercising the variable-length CDB path itself).

When an explicit cdb_len is set, requests whose LBA or transfer
length would overflow the fields of the selected CDB length are
rejected with -EINVAL rather than being silently promoted to a larger
CDB. This preserves the user's explicit intent when a specific CDB
length is chosen for benchmarking.

SYNCHRONIZE CACHE follows cdb_len as well: the 10-byte command
(0x35) is issued when cdb_len=10, and the 16-byte command (0x91) is
issued otherwise. SBC does not define a 32-byte SYNCHRONIZE CACHE
service action, so cdb_len=32 falls back to the 16-byte command.
UNMAP has no CDB length selection and keeps its fixed 10-byte CDB
regardless of cdb_len.

Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
The existing write_mode=verify option is currently only handled for
the nvme cmd_type. Extend it to the bsg cmd_type so that SCSI VERIFY
commands can be used as the write-side operation of a workload. This
is useful for measuring the cost of medium verification against the
same address range that would otherwise be written.

The VERIFY CDB length follows the cdb_len option: VERIFY(10)=0x2F,
VERIFY(16)=0x8F, and VERIFY(32) via the variable-length CDB service
action.

The data comparison behavior is controlled by a new verify_bytchk
option that maps to the CDB BYTCHK field:

  0 - medium verification only, no host data transfer (SG_DXFER_NONE)
  1 - compare the full transfer against the medium byte by byte
  3 - compare a single block against every block in the range

For BYTCHK 1 and 3 the command sends data to the device
(SG_DXFER_TO_DEV); BYTCHK 3 transfers only a single block while the
CDB still carries the full block count. verify_bytchk defaults to 0
and is rejected unless write_mode=verify.

VERIFY is the first bsg command that issues SG_DXFER_NONE with a
non-zero io_u->xfer_buflen (the buflen encodes the block count that
the device verifies against the medium). The previous
fio_bsg_uring_cmd_init() lumped SG_DXFER_NONE into the else branch
that populates din_xferp/din_xfer_len, which happened to be harmless
only because DDIR_SYNC's xfer_buflen was zero. Tighten the else to
match SG_DXFER_FROM_DEV explicitly so SG_DXFER_NONE leaves the data
transfer fields cleared.

writefua is rejected when combined with write_mode=verify. The FUA
bit is not defined for the VERIFY command in any of the CDB variants
that we support, and silently dropping the flag would hide a user
misconfiguration.

Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
Introduce a new engine option, read_mode, that selects which command
variant is issued for DDIR_READ, symmetric to the existing write_mode
option. Two values are supported: 'read', which preserves the current
behavior, and 'prefetch', which issues SCSI PRE-FETCH commands.

PRE-FETCH pulls the requested LBAs from the medium into the device
read cache without transferring the data to the host. This is useful
for warming the device read cache prior to a subsequent measurement,
and for measuring the overhead of the prefetch path itself.

The PRE-FETCH CDB length follows the cdb_len option:
PRE-FETCH(10)=0x34 and PRE-FETCH(16)=0x90. SBC does not define a
32-byte PRE-FETCH service action, so cdb_len=32 is rejected with
read_mode=prefetch rather than silently falling back. readfua is
also rejected in this mode because the FUA bit is not defined for
PRE-FETCH.

read_mode is currently only meaningful for the bsg cmd_type. Passing
a non-default value with cmd_type=nvme is rejected at engine init
rather than silently ignored, so that users notice a
misconfiguration.

Signed-off-by: Jungwon Lee <jjung1.lee@samsung.com>
Modify configure to only require gnutls on Linux when libnfs
is >= 6.

Signed-off-by: Kurt Miller <kurt@openbsd.org>
* 'gnutls.configure' of https://github.com/bsdkurt/fio:
  libnfs only requires gnutls on Linux Modify configure to only require gnutls on Linux when libnfs is >= 6.
* 'bsg-update' of https://github.com/ljw8161/fio:
  engines/io_uring: add read_mode=prefetch for bsg cmd_type
  engines/io_uring: support write_mode=verify for bsg cmd_type
  engines/io_uring: add cdb_len option for bsg cmd_type
  engines/io_uring: drop bsg status parsing from event
  engines/io_uring: drop unused write_opcode assignment on bsg path
Add some test cases for newly added cmd_type=bsg features. These include
tests for the cdb_len, write_mode=verify, and read_mode=prefetch
options.

Example invocation:
 python3 t/io_uring_cmd.py --cmd_type=bsg "--dut=/dev/bsg/6\:0\:0\:0"

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
The flag is RWF_DONTCACHE and not RWF_UNCACHED.[1]

[1] https://man7.org/linux/man-pages/man2/pwritev2.2.html

Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
…ladyyy/fio

* 'reap-signaled-worker-exit-code' of https://github.com/Vladyyy/fio:
  backend: exit non-zero when a job process is killed by a signal
verify_zero() logs the file, offset and length of a mismatch, but unlike
the header and pattern verify paths it never writes out the data it read.
That makes trim_verify_zero and write zeroes verify failures harder to
analyze than a regular verify failure, where verify_dump=1 leaves the
offending block on disk for inspection.

Dump the received block from verify_zero() when verify_dump is set, so
that both callers benefit. There is no point in also dumping an expected
buffer, as the expected contents are all zeroes.

Signed-off-by: Sarthak Killedar <sarthak.killedar@gmail.com>
Calling io_ops->commit() will not update io_u_in_flight and io_u_queued
accordingly. If iio_u_queued is not reset properly the fio may need to
make unnecessary stop to drain the queue. Which may degrade the throughput.

Signed-off-by: Dennis Chang <cherhungc@google.com>
* 'verify-zero-dump' of https://github.com/sarthak-k/fio:
  verify: dump the received buffer when zero verify fails
…nischerchang/fio

* 'consolidate_commit_call_path' of https://github.com/dennischerchang/fio:
  Consolidate all caller of io_ops_commit() to call td_io_commit().
Recent QEMU tests have been failing with errors like this:

 dpkg: unrecoverable fatal error, aborting:
  unable to flush /var/lib/dpkg/updates/tmp.i after padding: No space
   left on device

Example: https://github.com/axboe/fio/actions/runs/33871509826/job/101018344984?pr=2133

Fix this by resizing the image.

Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
and definition.

In stat.c, show_ddir_status() and add_ddir_status_json() calls
convert_agg_kbytes_percent() with 'double' parameter however
convert_agg_kbytes_percent() defines the parameter as 'int'.

Fixes: #2142

Signed-off-by: Dennis Chang chernhungc@google.com
…nt' of https://github.com/dennischerchang/fio

* 'inconsistent_parameter_type_in_convert_agg_kbytes_percent' of https://github.com/dennischerchang/fio:
  Fix convert_agg_kbytes_percent() inconsistent type between caller and definition.
TD_RAMP increments both nr_running and nr_ramp, so nr_ramp is a subset
of nr_running and display_thread_status() can compare the two. The
TD_SETTING_UP side would increment only nr_setting_up, yet the
percentage calculation scales by nr_setting_up / nr_running, a ratio
that only means anything if setting up jobs are counted in nr_running as
well: the existing ratio can drive the multiplier negative.

A job that is setting up is started and doing work, it just has not
issued IO yet, so count it in nr_running and treat nr_setting_up as the
subset as intended. Today this only covers the brief windows where
setup_files() and pre_read_file() bump the state, but it means the
status line reports such a job instead of suppressing the whole line.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20260910161310.1478081-2-kbusch@meta.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
run_threads() moves a job from TD_INITIALIZED straight to TD_RUNNING and
only then releases it. The job still has all of its setup left to do:
exec_prerun, pre_read_files(), setup_files(), init_io_u(),
rate_submit_init() and finally set_epoch_time(). The job claims to be
running for that entire window when it has not issued any IO and has no
epoch to measure itself against.

Anything that reads the state during that window gets a wrong answer.
thread_eta() is the most readily observable  one: it derives elapsed
from td->epoch, which is still zeroed, so a job with a three second
exec_prerun reports

  Jobs: 1 (f=0): [R(1)][-.-%][eta 00m:00s]
  Jobs: 1 (f=0): [R(1)][50.0%][eta 00m:03s]

before doing any work at all. Running, half done and no time left, none
of which is true.

Promote to TD_SETTING_UP instead, which is what that state is for, and
let the job promote itself to TD_RAMP or TD_RUNNING once setup is over
and it has recorded its epoch. The same job now reports

  Jobs: 1 (f=1): [I(1)][0.0%][eta 00m:03s]

Widen the TERMINATE_STONEWALL check to match. It tests for runstate >=
TD_RUNNING to find jobs worth terminating, and a job in the setup window
used to satisfy that. Without this, exit_what=stonewall stops reaching a
job that is still setting up, and a test where the short job is reaped
while a longer one sits in exec_prerun goes from 5.5s to 20.5s. Note
TD_RAMP sorts below TD_SETTING_UP, so ramping jobs remain excluded from
that check exactly as before.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20260910161310.1478081-3-kbusch@meta.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
The ETA of a running job is capped at "timeout + done_secs - elapsed".
done_secs is a global accumulator of the runtime of every job reaped so
far, so the cap grows every time a job finishes. Whenever the cap is
what actually gets reported, the ETA jumps back up by the runtime of
everything that has already completed.

The cap is what gets reported when the progress based estimate exceeds
the remaining runtime, that is when perc is below elapsed/timeout. Any
job that is behind on bytes relative to its runtime is in that state,
so this covers the common "size the job to the whole device, bound it
with runtime" pattern. A job that would complete its size early stays
at or above elapsed/timeout and never reaches the cap.

time_based makes no difference either way. It only lowers perc to
min(perc, elapsed/timeout), so a time_based job that cannot finish its
size within the runtime is affected exactly like a size based one.

It is most visible with stonewalled jobs, where the ETA climbs back to
the full run time at every batch boundary instead of counting down:

  fio --name=global --filename=/dev/zero --runtime=5 --size=10T \
      --stonewall --name=a --name=b --name=c --name=d --name=e

  before: 22 21 20  24 23 22 21 20  24 23 22 21 20  24 ...
  after:  22 21 20 19 18 17 16 15 14 13 ... 02 01 00

Shrinking size until the jobs complete it within the runtime makes the
symptom disappear, which is a good way to confirm the cap is what is
being reported.

It is not specific to stonewall. Two concurrent jobs with runtime=5 and
runtime=20 show the same jump when the short one is reaped at t=5.

done_secs made sense when it was introduced: thread_eta() was handed
the global elapsed time back then, so "timeout + done_secs" was this
job's projected finish time relative to the start of the whole run.
b29ee5b switched elapsed to be per job, measured from td->epoch, but
left the done_secs term behind.

A job is terminated once utime_since(&td->epoch, now) reaches
td->o.timeout, so with a per job elapsed the cap is simply
"timeout - elapsed". Use that, and clamp at zero instead of relying on
the unsigned subtraction wrapping.

Fixes: b29ee5b ("Update ramp_time")
Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20260910161310.1478081-4-kbusch@meta.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Capping the ETA at the job's own remaining runtime removed the last
reader of done_secs. Drop the variable, along with the gettime call
that maintained it on every reap.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20260910161310.1478081-5-kbusch@meta.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Various error cases in fio_send_file() might send an uninitialized
buffer over the wire. The server should ignore this when errno is set,
but it's best practice to not ship heap data over the wire, so fix that
by:

- using calloc vs malloc in the initial allocation so that early error
  paths send initialized data.

- grow the buffer via realloc only after open() succeeds, so that an
  open() failure doesn't send a grown/uninit buffer back with the error.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Link: https://patch.msgid.link/20260917205554.2281093-1-sandeen@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.