diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 04a6531dcb..f5d2914be2 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -770,7 +770,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { * punch-hole/truncate this to release the disk space. */ bs = MAX(st.st_blksize, 512); - l = DIV_ROUND_UP(st.st_size, bs) * bs; /* Round up to next block size */ + l = ROUND_UP(st.st_size, bs); /* Round up to next block size */ if (fallocate(truncate_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 0, l) >= 0) return 0; /* Successfully punched a hole! 😊 */ diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index e901e8fb59..1d49765fce 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -108,7 +108,6 @@ #define assert_cc(expr) static_assert(expr, #expr) - #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ @@ -253,6 +252,16 @@ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ }) +/* Rounds up x to the next multiple of y. Resolves to typeof(x) -1 in case of overflow */ +#define __ROUND_UP(q, x, y) \ + ({ \ + const typeof(y) UNIQ_T(A, q) = (y); \ + const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \ + typeof(x) UNIQ_T(C, q); \ + __builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \ + }) +#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y)) + #define CASE_F_1(X) case X: #define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__) #define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__) diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index d1f8ca381e..f5d4823600 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -688,7 +688,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) } /* Increase by larger blocks at once */ - new_size = DIV_ROUND_UP(new_size, FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE; + new_size = ROUND_UP(new_size, FILE_SIZE_INCREASE); if (f->metrics.max_size > 0 && new_size > f->metrics.max_size) new_size = f->metrics.max_size; diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 628c6202e1..f17d97a2c1 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -1151,7 +1151,7 @@ static int find_matching_component( } else if (c->repeat > 0) { int k; - k = start + c->repeat * DIV_ROUND_UP(*val - start, c->repeat); + k = start + ROUND_UP(*val - start, c->repeat); if ((!d_set || k < d) && (stop < 0 || k <= stop)) { d = k; diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 637d6f1a49..810ebc580e 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -818,4 +818,70 @@ TEST(FOREACH_ARRAY) { assert_se(n == 0); } +#define TEST_ROUND_UP_BY_TYPE(type, max_value) \ + ({ \ + type x, y; \ + x = 0, y = 1; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 2; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 3; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 4; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 1, y = 1; \ + assert_se(ROUND_UP(x, y) == 1); \ + x = 1, y = 2; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 1, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 1, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 2, y = 1; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 2, y = 2; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 2, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 2, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 3, y = 1; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 3, y = 2; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 3, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 3, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 1; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 2; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 3; \ + assert_se(ROUND_UP(x, y) == 6); \ + x = 4, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = max_value, y = 1; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 2; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 3; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 4; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value-1, y = 1; \ + assert_se(ROUND_UP(x, y) == max_value-1); \ + x = max_value-1, y = 2; \ + assert_se(ROUND_UP(x, y) == max_value-1); \ + x = max_value-1, y = 4; \ + assert_se(ROUND_UP(x, y) == max_value); \ + }) + +TEST(round_up) { + TEST_ROUND_UP_BY_TYPE(uint8_t, UINT8_MAX); + TEST_ROUND_UP_BY_TYPE(uint16_t, UINT16_MAX); + TEST_ROUND_UP_BY_TYPE(uint32_t, UINT32_MAX); + TEST_ROUND_UP_BY_TYPE(uint64_t, UINT64_MAX); +} + DEFINE_TEST_MAIN(LOG_INFO);