Skip to content

Commit b7f919d

Browse files
authored
Relax zfs_vnops_read_chunk_size limitations
It makes no sense to limit read size below the block size, since DMU will any way consume resources for the whole block, while the current zfs_vnops_read_chunk_size is only 1MB, which is smaller that maximum block size of 16MB. Plus in case of misaligned Uncached I/O the buffer may get evicted between the chunks, requiring repeating I/Os. On 64-bit platforms increase zfs_vnops_read_chunk_size to 32MB. It allows to less depend on speculative prefetcher if application requests specific size, first not waiting for prefetcher to start and later not prefetching more than needed. Also while there, we don't need to align reads to the chunk size, but only to a block size, which is smaller and so more forgiving. My profiles show ~4% of CPU time saving when reading 16MB blocks. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed by: Igor Kozhukhov <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #17415
1 parent 68817d2 commit b7f919d

File tree

2 files changed

+11
-3
lines changed

2 files changed

+11
-3
lines changed

man/man4/zfs.4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,7 @@ Disable QAT hardware acceleration for AES-GCM encryption.
19801980
May be unset after the ZFS modules have been loaded to initialize the QAT
19811981
hardware as long as support is compiled in and the QAT driver is present.
19821982
.
1983-
.It Sy zfs_vnops_read_chunk_size Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64
1983+
.It Sy zfs_vnops_read_chunk_size Ns = Ns Sy 33554432 Ns B Po 32 MiB Pc Pq u64
19841984
Bytes to read per chunk.
19851985
.
19861986
.It Sy zfs_read_history Ns = Ns Sy 0 Pq uint

module/zfs/zfs_vnops.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ static int zfs_dio_strict = 0;
9999
/*
100100
* Maximum bytes to read per chunk in zfs_read().
101101
*/
102+
#ifdef _ILP32
102103
static uint64_t zfs_vnops_read_chunk_size = 1024 * 1024;
104+
#else
105+
static uint64_t zfs_vnops_read_chunk_size = DMU_MAX_ACCESS / 2;
106+
#endif
103107

104108
int
105109
zfs_fsync(znode_t *zp, int syncflag, cred_t *cr)
@@ -401,7 +405,8 @@ zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
401405
#if defined(__linux__)
402406
ssize_t start_offset = zfs_uio_offset(uio);
403407
#endif
404-
ssize_t chunk_size = zfs_vnops_read_chunk_size;
408+
uint_t blksz = zp->z_blksz;
409+
ssize_t chunk_size;
405410
ssize_t n = MIN(zfs_uio_resid(uio), zp->z_size - zfs_uio_offset(uio));
406411
ssize_t start_resid = n;
407412
ssize_t dio_remaining_resid = 0;
@@ -432,11 +437,14 @@ zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
432437
if (dio_remaining_resid != 0)
433438
n -= dio_remaining_resid;
434439
dflags |= DMU_DIRECTIO;
440+
} else {
441+
chunk_size = MIN(MAX(zfs_vnops_read_chunk_size, blksz),
442+
DMU_MAX_ACCESS / 2);
435443
}
436444

437445
while (n > 0) {
438446
ssize_t nbytes = MIN(n, chunk_size -
439-
P2PHASE(zfs_uio_offset(uio), chunk_size));
447+
P2PHASE(zfs_uio_offset(uio), blksz));
440448
#ifdef UIO_NOCOPY
441449
if (zfs_uio_segflg(uio) == UIO_NOCOPY)
442450
error = mappedread_sf(zp, nbytes, uio);

0 commit comments

Comments
 (0)