fix abd_nr_pages_off for gang abd
authorMatthew Ahrens <matthew.ahrens@delphix.com>
Thu, 28 Jan 2021 17:28:20 +0000 (09:28 -0800)
committerGitHub <noreply@github.com>
Thu, 28 Jan 2021 17:28:20 +0000 (09:28 -0800)
commitf8c0d7e1f6a2c7efebea004afbab436d8d20b1e7
tree01a602c89e807fdbb4e816b5dfe60b7fcbe40352
parent0ae184a6baaf71e155e9b19af81b75474622ff58
fix abd_nr_pages_off for gang abd

`__vdev_disk_physio()` uses `abd_nr_pages_off()` to allocate a bio with
a sufficient number of iovec's to process this zio (i.e.
`nr_iovecs`/`bi_max_vecs`).  If there are not enough iovec's in the bio,
then additional bio's will be allocated.  However, this is a sub-optimal
code path.  In particular, it requires several abd calls (to
`abd_nr_pages_off()` and `abd_bio_map_off()`) which will have to walk
the constituents of the ABD (the pages or the gang children) because
they are looking for offsets > 0.

For gang ABD's, `abd_nr_pages_off()` returns the number of iovec's
needed for the first constituent, rather than the sum of all
constituents (within the requested range).  This always under-estimates
the required number of iovec's, which causes us to always need several
bio's.  The end result is that `__vdev_disk_physio()` is usually O(n^2)
for gang ABD's (and occasionally O(n^3), when more than 16 bio's are
needed).

This commit fixes `abd_nr_pages_off()`'s handling of gang ABD's, to
correctly determine how many iovec's are needed, by adding up the number
of iovec's for each of the gang children in the requested range.

Reviewed-by: Mark Maybee <mark.maybee@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Brian Atkinson <batkinson@lanl.gov>
Signed-off-by: Matthew Ahrens <mahrens@delphix.com>
Closes #11536
module/os/linux/zfs/abd_os.c
module/os/linux/zfs/vdev_disk.c