From: Johannes Berg <johannes.berg@xxxxxxxxx> Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> --- backport/backport-include/linux/math64.h | 11 ++++++ backport/compat/Makefile | 1 + backport/compat/backport-5.9.c | 45 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 backport/backport-include/linux/math64.h create mode 100644 backport/compat/backport-5.9.c diff --git a/backport/backport-include/linux/math64.h b/backport/backport-include/linux/math64.h new file mode 100644 index 00000000..6aea9c9e --- /dev/null +++ b/backport/backport-include/linux/math64.h @@ -0,0 +1,11 @@ +#ifndef __BACKPORT_LINUX_MATH64_H +#define __BACKPORT_LINUX_MATH64_H +#include_next <linux/math64.h> +#include <linux/version.h> + +#if LINUX_VERSION_IS_LESS(5,9,0) +#define mul_u64_u64_div_u64 LINUX_BACKPORT(mul_u64_u64_div_u64) +extern u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c); +#endif /* < 5.9 */ + +#endif /* __BACKPORT_LINUX_MATH64_H */ diff --git a/backport/compat/Makefile b/backport/compat/Makefile index c2b89176..698f14f5 100644 --- a/backport/compat/Makefile +++ b/backport/compat/Makefile @@ -11,6 +11,7 @@ compat-$(CPTCFG_KERNEL_4_18) += backport-4.18.o compat-$(CPTCFG_KERNEL_5_2) += backport-5.2.o backport-genetlink.o compat-$(CPTCFG_KERNEL_5_3) += backport-5.3.o compat-$(CPTCFG_KERNEL_5_5) += backport-5.5.o +compat-$(CPTCFG_KERNEL_5_9) += backport-5.9.o compat-$(CPTCFG_KERNEL_5_10) += backport-5.10.o compat-$(CPTCFG_KERNEL_5_11) += backport-5.11.o compat-$(CPTCFG_KERNEL_5_13) += backport-5.13.o diff --git a/backport/compat/backport-5.9.c b/backport/compat/backport-5.9.c new file mode 100644 index 00000000..54d1802e --- /dev/null +++ b/backport/compat/backport-5.9.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/math64.h> + +u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c) +{ + u64 res = 0, div, rem; + int shift; + + /* can a * b overflow ? */ + if (ilog2(a) + ilog2(b) > 62) { + /* + * (b * a) / c is equal to + * + * (b / c) * a + + * (b % c) * a / c + * + * if nothing overflows. Can the 1st multiplication + * overflow? Yes, but we do not care: this can only + * happen if the end result can't fit in u64 anyway. + * + * So the code below does + * + * res = (b / c) * a; + * b = b % c; + */ + div = div64_u64_rem(b, c, &rem); + res = div * a; + b = rem; + + shift = ilog2(a) + ilog2(b) - 62; + if (shift > 0) { + /* drop precision */ + b >>= shift; + c >>= shift; + if (!c) + return res; + } + } + + return res + div64_u64(a * b, c); +} +EXPORT_SYMBOL_GPL(mul_u64_u64_div_u64); -- 2.45.2