diff options
author | Rich Ercolani <214141+rincebrain@users.noreply.github.com> | 2024-04-29 18:32:49 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-29 18:32:49 +0000 |
commit | db499e68f9ef8d4b12ebdab699184e3acf35567c (patch) | |
tree | f4fb7e13aec55a7866a4785f1272f8fb86424584 | |
parent | 4840f023afae7c4932c903cf3a436c02c6704e20 (diff) | |
download | src-db499e68f9ef8d4b12ebdab699184e3acf35567c.tar.gz src-db499e68f9ef8d4b12ebdab699184e3acf35567c.zip |
Overflowing refreservation is bad
Someone came to me and pointed out that you could pretty
readily cause the refreservation calculation to exceed
2**64, given the 2**17 multiplier in it, and produce
refreservations wildly less than the actual volsize in cases where
it should have failed.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rich Ercolani <rincebrain@gmail.com>
Closes #15996
-rw-r--r-- | lib/libzfs/libzfs_dataset.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 6f8773aed425..231bbbd92dbf 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -5565,8 +5565,21 @@ volsize_from_vdevs(zpool_handle_t *zhp, uint64_t nblocks, uint64_t blksize) /* * Scale this size down as a ratio of 128k / tsize. * See theory statement above. + * + * Bitshift is to avoid the case of nblocks * asize < tsize + * producing a size of 0. + */ + volsize = (nblocks * asize) / (tsize >> SPA_MINBLOCKSHIFT); + /* + * If we would blow UINT64_MAX with this next multiplication, + * don't. */ - volsize = nblocks * asize * SPA_OLD_MAXBLOCKSIZE / tsize; + if (volsize > + (UINT64_MAX / (SPA_OLD_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT))) + volsize = UINT64_MAX; + else + volsize *= (SPA_OLD_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT); + if (volsize > ret) { ret = volsize; } |