From b5cb119593dff84345ca22aa3791befcd7485dbc Mon Sep 17 00:00:00 2001 From: Rich Ercolani Date: Thu, 14 Mar 2024 05:08:34 -0400 Subject: [PATCH] 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. Signed-off-by: Rich Ercolani --- lib/libzfs/libzfs_dataset.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 6f8773aed4..231bbbd92d 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 * SPA_OLD_MAXBLOCKSIZE / tsize; + volsize = (nblocks * asize) / (tsize >> SPA_MINBLOCKSHIFT); + /* + * If we would blow UINT64_MAX with this next multiplication, + * don't. + */ + if (volsize > + (UINT64_MAX / (SPA_OLD_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT))) + volsize = UINT64_MAX; + else + volsize *= (SPA_OLD_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT); + if (volsize > ret) { ret = volsize; }