aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Ercolani <214141+rincebrain@users.noreply.github.com>2024-04-29 18:32:49 +0000
committerGitHub <noreply@github.com>2024-04-29 18:32:49 +0000
commitdb499e68f9ef8d4b12ebdab699184e3acf35567c (patch)
treef4fb7e13aec55a7866a4785f1272f8fb86424584
parent4840f023afae7c4932c903cf3a436c02c6704e20 (diff)
downloadsrc-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.c15
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;
}