From: Greg Kroah-Hartman Date: Mon, 22 Sep 2025 12:26:59 +0000 (+0200) Subject: 6.6-stable patches X-Git-Tag: v6.1.154~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3755f2520ee27b8576c64f4a949dbd1ad1dab7a2;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: minmax-add-a-few-more-min_t-max_t-users.patch minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch minmax-fix-up-min3-and-max3-too.patch minmax-improve-macro-expansion-and-type-checking.patch minmax-make-generic-min-and-max-macros-available-everywhere.patch minmax-simplify-and-clarify-min_t-max_t-implementation.patch minmax-simplify-min-max-clamp-implementation.patch --- diff --git a/queue-6.6/minmax-add-a-few-more-min_t-max_t-users.patch b/queue-6.6/minmax-add-a-few-more-min_t-max_t-users.patch new file mode 100644 index 0000000000..8dd9a4e69e --- /dev/null +++ b/queue-6.6/minmax-add-a-few-more-min_t-max_t-users.patch @@ -0,0 +1,160 @@ +From prvs=353d6d59a=farbere@amazon.com Mon Sep 22 12:34:49 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:29 +0000 +Subject: minmax: add a few more MIN_T/MAX_T users +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-4-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 4477b39c32fdc03363affef4b11d48391e6dc9ff ] + +Commit 3a7e02c040b1 ("minmax: avoid overly complicated constant +expressions in VM code") added the simpler MIN_T/MAX_T macros in order +to avoid some excessive expansion from the rather complicated regular +min/max macros. + +The complexity of those macros stems from two issues: + + (a) trying to use them in situations that require a C constant + expression (in static initializers and for array sizes) + + (b) the type sanity checking + +and MIN_T/MAX_T avoids both of these issues. + +Now, in the whole (long) discussion about all this, it was pointed out +that the whole type sanity checking is entirely unnecessary for +min_t/max_t which get a fixed type that the comparison is done in. + +But that still leaves min_t/max_t unnecessarily complicated due to +worries about the C constant expression case. + +However, it turns out that there really aren't very many cases that use +min_t/max_t for this, and we can just force-convert those. + +This does exactly that. + +Which in turn will then allow for much simpler implementations of +min_t()/max_t(). All the usual "macros in all upper case will evaluate +the arguments multiple times" rules apply. + +We should do all the same things for the regular min/max() vs MIN/MAX() +cases, but that has the added complexity of various drivers defining +their own local versions of MIN/MAX, so that needs another level of +fixes first. + +Link: https://lore.kernel.org/all/b47fad1d0cf8449886ad148f8c013dae@AcuMS.aculab.com/ +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/mm/pgtable.c | 2 +- + drivers/edac/sb_edac.c | 4 ++-- + drivers/gpu/drm/drm_color_mgmt.c | 2 +- + drivers/md/dm-integrity.c | 6 +++--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- + net/ipv4/proc.c | 2 +- + net/ipv6/proc.c | 2 +- + 7 files changed, 10 insertions(+), 10 deletions(-) + +--- a/arch/x86/mm/pgtable.c ++++ b/arch/x86/mm/pgtable.c +@@ -107,7 +107,7 @@ static inline void pgd_list_del(pgd_t *p + #define UNSHARED_PTRS_PER_PGD \ + (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD) + #define MAX_UNSHARED_PTRS_PER_PGD \ +- max_t(size_t, KERNEL_PGD_BOUNDARY, PTRS_PER_PGD) ++ MAX_T(size_t, KERNEL_PGD_BOUNDARY, PTRS_PER_PGD) + + + static void pgd_set_mm(pgd_t *pgd, struct mm_struct *mm) +--- a/drivers/edac/sb_edac.c ++++ b/drivers/edac/sb_edac.c +@@ -109,8 +109,8 @@ static const u32 knl_interleave_list[] = + 0x104, 0x10c, 0x114, 0x11c, /* 20-23 */ + }; + #define MAX_INTERLEAVE \ +- (max_t(unsigned int, ARRAY_SIZE(sbridge_interleave_list), \ +- max_t(unsigned int, ARRAY_SIZE(ibridge_interleave_list), \ ++ (MAX_T(unsigned int, ARRAY_SIZE(sbridge_interleave_list), \ ++ MAX_T(unsigned int, ARRAY_SIZE(ibridge_interleave_list), \ + ARRAY_SIZE(knl_interleave_list)))) + + struct interleave_pkg { +--- a/drivers/gpu/drm/drm_color_mgmt.c ++++ b/drivers/gpu/drm/drm_color_mgmt.c +@@ -532,7 +532,7 @@ int drm_plane_create_color_properties(st + { + struct drm_device *dev = plane->dev; + struct drm_property *prop; +- struct drm_prop_enum_list enum_list[max_t(int, DRM_COLOR_ENCODING_MAX, ++ struct drm_prop_enum_list enum_list[MAX_T(int, DRM_COLOR_ENCODING_MAX, + DRM_COLOR_RANGE_MAX)]; + int i, len; + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -1794,7 +1794,7 @@ static void integrity_metadata(struct wo + struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); + char *checksums; + unsigned int extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0; +- char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; ++ char checksums_onstack[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; + sector_t sector; + unsigned int sectors_to_process; + +@@ -2073,7 +2073,7 @@ retry_kmap: + } while (++s < ic->sectors_per_block); + #ifdef INTERNAL_VERIFY + if (ic->internal_hash) { +- char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; ++ char checksums_onstack[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; + + integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack); + if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) { +@@ -2638,7 +2638,7 @@ static void do_journal_write(struct dm_i + unlikely(from_replay) && + #endif + ic->internal_hash) { +- char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; ++ char test_tag[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; + + integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block), + (char *)access_journal_data(ic, i, l), test_tag); +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -2841,7 +2841,7 @@ static void stmmac_dma_interrupt(struct + u32 channels_to_check = tx_channel_count > rx_channel_count ? + tx_channel_count : rx_channel_count; + u32 chan; +- int status[max_t(u32, MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES)]; ++ int status[MAX_T(u32, MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES)]; + + /* Make sure we never check beyond our status buffer. */ + if (WARN_ON_ONCE(channels_to_check > ARRAY_SIZE(status))) +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -43,7 +43,7 @@ + #include + #include + +-#define TCPUDP_MIB_MAX max_t(u32, UDP_MIB_MAX, TCP_MIB_MAX) ++#define TCPUDP_MIB_MAX MAX_T(u32, UDP_MIB_MAX, TCP_MIB_MAX) + + /* + * Report socket allocation statistics [mea@utu.fi] +--- a/net/ipv6/proc.c ++++ b/net/ipv6/proc.c +@@ -27,7 +27,7 @@ + #include + + #define MAX4(a, b, c, d) \ +- max_t(u32, max_t(u32, a, b), max_t(u32, c, d)) ++ MAX_T(u32, MAX_T(u32, a, b), MAX_T(u32, c, d)) + #define SNMP_MIB_MAX MAX4(UDP_MIB_MAX, TCP_MIB_MAX, \ + IPSTATS_MIB_MAX, ICMP_MIB_MAX) + diff --git a/queue-6.6/minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch b/queue-6.6/minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch new file mode 100644 index 0000000000..0902b1b455 --- /dev/null +++ b/queue-6.6/minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch @@ -0,0 +1,78 @@ +From linux-staging+bounces-34536-greg=kroah.com@lists.linux.dev Mon Sep 22 12:34:42 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:27 +0000 +Subject: minmax: avoid overly complicated constant expressions in VM code +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , Lorenzo Stoakes , David Laight +Message-ID: <20250922103241.16213-2-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 3a7e02c040b130b5545e4b115aada7bacd80a2b6 ] + +The minmax infrastructure is overkill for simple constants, and can +cause huge expansions because those simple constants are then used by +other things. + +For example, 'pageblock_order' is a core VM constant, but because it was +implemented using 'min_t()' and all the type-checking that involves, it +actually expanded to something like 2.5kB of preprocessor noise. + +And when that simple constant was then used inside other expansions: + + #define pageblock_nr_pages (1UL << pageblock_order) + #define pageblock_start_pfn(pfn) ALIGN_DOWN((pfn), pageblock_nr_pages) + +and we then use that inside a 'max()' macro: + + case ISOLATE_SUCCESS: + update_cached = false; + last_migrated_pfn = max(cc->zone->zone_start_pfn, + pageblock_start_pfn(cc->migrate_pfn - 1)); + +the end result was that one statement expanding to 253kB in size. + +There are probably other cases of this, but this one case certainly +stood out. + +I've added 'MIN_T()' and 'MAX_T()' macros for this kind of "core simple +constant with specific type" use. These macros skip the type checking, +and as such need to be very sparingly used only for obvious cases that +have active issues like this. + +Reported-by: Lorenzo Stoakes +Link: https://lore.kernel.org/all/36aa2cad-1db1-4abf-8dd2-fb20484aabc3@lucifer.local/ +Cc: David Laight +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/minmax.h | 7 +++++++ + include/linux/pageblock-flags.h | 2 +- + 2 files changed, 8 insertions(+), 1 deletion(-) + +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -270,4 +270,11 @@ static inline bool in_range32(u32 val, u + #define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) + ++/* ++ * Use these carefully: no type checking, and uses the arguments ++ * multiple times. Use for obvious constants only. ++ */ ++#define MIN_T(type,a,b) __cmp(min,(type)(a),(type)(b)) ++#define MAX_T(type,a,b) __cmp(max,(type)(a),(type)(b)) ++ + #endif /* _LINUX_MINMAX_H */ +--- a/include/linux/pageblock-flags.h ++++ b/include/linux/pageblock-flags.h +@@ -41,7 +41,7 @@ extern unsigned int pageblock_order; + * Huge pages are a constant size, but don't exceed the maximum allocation + * granularity. + */ +-#define pageblock_order min_t(unsigned int, HUGETLB_PAGE_ORDER, MAX_ORDER) ++#define pageblock_order MIN_T(unsigned int, HUGETLB_PAGE_ORDER, MAX_ORDER) + + #endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */ + diff --git a/queue-6.6/minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch b/queue-6.6/minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch new file mode 100644 index 0000000000..7ee6538c90 --- /dev/null +++ b/queue-6.6/minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch @@ -0,0 +1,99 @@ +From linux-staging+bounces-34541-greg=kroah.com@lists.linux.dev Mon Sep 22 12:38:18 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:32 +0000 +Subject: minmax: don't use max() in situations that want a C constant expression +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-7-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit cb04e8b1d2f24c4c2c92f7b7529031fc35a16fed ] + +We only had a couple of array[] declarations, and changing them to just +use 'MAX()' instead of 'max()' fixes the issue. + +This will allow us to simplify our min/max macros enormously, since they +can now unconditionally use temporary variables to avoid using the +argument values multiple times. + +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- + drivers/input/touchscreen/cyttsp4_core.c | 2 +- + drivers/irqchip/irq-sun6i-r.c | 2 +- + drivers/net/can/usb/etas_es58x/es58x_devlink.c | 2 +- + fs/btrfs/tree-checker.c | 2 +- + lib/vsprintf.c | 2 +- + 6 files changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +@@ -708,7 +708,7 @@ static const char *smu_get_feature_name( + size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, + char *buf) + { +- int8_t sort_feature[max(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; ++ int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; + uint64_t feature_mask; + int i, feature_index; + uint32_t count = 0; +--- a/drivers/input/touchscreen/cyttsp4_core.c ++++ b/drivers/input/touchscreen/cyttsp4_core.c +@@ -871,7 +871,7 @@ static void cyttsp4_get_mt_touches(struc + struct cyttsp4_touch tch; + int sig; + int i, j, t = 0; +- int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)]; ++ int ids[MAX(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)]; + + memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int)); + for (i = 0; i < num_cur_tch; i++) { +--- a/drivers/irqchip/irq-sun6i-r.c ++++ b/drivers/irqchip/irq-sun6i-r.c +@@ -270,7 +270,7 @@ static const struct irq_domain_ops sun6i + + static int sun6i_r_intc_suspend(void) + { +- u32 buf[BITS_TO_U32(max(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))]; ++ u32 buf[BITS_TO_U32(MAX(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))]; + int i; + + /* Wake IRQs are enabled during system sleep and shutdown. */ +--- a/drivers/net/can/usb/etas_es58x/es58x_devlink.c ++++ b/drivers/net/can/usb/etas_es58x/es58x_devlink.c +@@ -215,7 +215,7 @@ static int es58x_devlink_info_get(struct + struct es58x_sw_version *fw_ver = &es58x_dev->firmware_version; + struct es58x_sw_version *bl_ver = &es58x_dev->bootloader_version; + struct es58x_hw_revision *hw_rev = &es58x_dev->hardware_revision; +- char buf[max(sizeof("xx.xx.xx"), sizeof("axxx/xxx"))]; ++ char buf[MAX(sizeof("xx.xx.xx"), sizeof("axxx/xxx"))]; + int ret = 0; + + if (es58x_sw_version_is_valid(fw_ver)) { +--- a/fs/btrfs/tree-checker.c ++++ b/fs/btrfs/tree-checker.c +@@ -614,7 +614,7 @@ static int check_dir_item(struct extent_ + */ + if (key->type == BTRFS_DIR_ITEM_KEY || + key->type == BTRFS_XATTR_ITEM_KEY) { +- char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; ++ char namebuf[MAX(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; + + read_extent_buffer(leaf, namebuf, + (unsigned long)(di + 1), name_len); +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -1079,7 +1079,7 @@ char *resource_string(char *buf, char *e + #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) + #define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") + #define RAW_BUF_SIZE sizeof("[mem - flags 0x]") +- char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, ++ char sym[MAX(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, + 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; + + char *p = sym, *pend = sym + sizeof(sym); diff --git a/queue-6.6/minmax-fix-up-min3-and-max3-too.patch b/queue-6.6/minmax-fix-up-min3-and-max3-too.patch new file mode 100644 index 0000000000..2b95d165b2 --- /dev/null +++ b/queue-6.6/minmax-fix-up-min3-and-max3-too.patch @@ -0,0 +1,79 @@ +From prvs=353d6d59a=farbere@amazon.com Mon Sep 22 12:37:42 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:34 +0000 +Subject: minmax: fix up min3() and max3() too +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight +Message-ID: <20250922103241.16213-9-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 21b136cc63d2a9ddd60d4699552b69c214b32964 ] + +David Laight pointed out that we should deal with the min3() and max3() +mess too, which still does excessive expansion. + +And our current macros are actually rather broken. + +In particular, the macros did this: + + #define min3(x, y, z) min((typeof(x))min(x, y), z) + #define max3(x, y, z) max((typeof(x))max(x, y), z) + +and that not only is a nested expansion of possibly very complex +arguments with all that involves, the typing with that "typeof()" cast +is completely wrong. + +For example, imagine what happens in max3() if 'x' happens to be a +'unsigned char', but 'y' and 'z' are 'unsigned long'. The types are +compatible, and there's no warning - but the result is just random +garbage. + +No, I don't think we've ever hit that issue in practice, but since we +now have sane infrastructure for doing this right, let's just use it. +It fixes any excessive expansion, and also avoids these kinds of broken +type issues. + +Requested-by: David Laight +Acked-by: Arnd Bergmann +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/minmax.h | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -152,13 +152,20 @@ + #define umax(x, y) \ + __careful_cmp(max, (x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull) + ++#define __careful_op3(op, x, y, z, ux, uy, uz) ({ \ ++ __auto_type ux = (x); __auto_type uy = (y);__auto_type uz = (z);\ ++ BUILD_BUG_ON_MSG(!__types_ok3(x,y,z,ux,uy,uz), \ ++ #op"3("#x", "#y", "#z") signedness error"); \ ++ __cmp(op, ux, __cmp(op, uy, uz)); }) ++ + /** + * min3 - return minimum of three values + * @x: first value + * @y: second value + * @z: third value + */ +-#define min3(x, y, z) min((typeof(x))min(x, y), z) ++#define min3(x, y, z) \ ++ __careful_op3(min, x, y, z, __UNIQUE_ID(x_), __UNIQUE_ID(y_), __UNIQUE_ID(z_)) + + /** + * max3 - return maximum of three values +@@ -166,7 +173,8 @@ + * @y: second value + * @z: third value + */ +-#define max3(x, y, z) max((typeof(x))max(x, y), z) ++#define max3(x, y, z) \ ++ __careful_op3(max, x, y, z, __UNIQUE_ID(x_), __UNIQUE_ID(y_), __UNIQUE_ID(z_)) + + /** + * min_not_zero - return the minimum that is _not_ zero, unless both are zero diff --git a/queue-6.6/minmax-improve-macro-expansion-and-type-checking.patch b/queue-6.6/minmax-improve-macro-expansion-and-type-checking.patch new file mode 100644 index 0000000000..b294a0cba6 --- /dev/null +++ b/queue-6.6/minmax-improve-macro-expansion-and-type-checking.patch @@ -0,0 +1,202 @@ +From prvs=353d6d59a=farbere@amazon.com Mon Sep 22 12:36:39 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:33 +0000 +Subject: minmax: improve macro expansion and type checking +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-8-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 22f5468731491e53356ba7c028f0fdea20b18e2c ] + +This clarifies the rules for min()/max()/clamp() type checking and makes +them a much more efficient macro expansion. + +In particular, we now look at the type and range of the inputs to see +whether they work together, generating a mask of acceptable comparisons, +and then just verifying that the inputs have a shared case: + + - an expression with a signed type can be used for + (1) signed comparisons + (2) unsigned comparisons if it is statically known to have a + non-negative value + + - an expression with an unsigned type can be used for + (3) unsigned comparison + (4) signed comparisons if the type is smaller than 'int' and thus + the C integer promotion rules will make it signed anyway + +Here rule (1) and (3) are obvious, and rule (2) is important in order to +allow obvious trivial constants to be used together with unsigned +values. + +Rule (4) is not necessarily a good idea, but matches what we used to do, +and we have extant cases of this situation in the kernel. Notably with +bcachefs having an expression like + + min(bch2_bucket_sectors_dirty(a), ca->mi.bucket_size) + +where bch2_bucket_sectors_dirty() returns an 's64', and +'ca->mi.bucket_size' is of type 'u16'. + +Technically that bcachefs comparison is clearly sensible on a C type +level, because the 'u16' will go through the normal C integer promotion, +and become 'int', and then we're comparing two signed values and +everything looks sane. + +However, it's not entirely clear that a 'min(s64,u16)' operation makes a +lot of conceptual sense, and it's possible that we will remove rule (4). +After all, the _reason_ we have these complicated type checks is exactly +that the C type promotion rules are not very intuitive. + +But at least for now the rule is in place for backwards compatibility. + +Also note that rule (2) existed before, but is hugely relaxed by this +commit. It used to be true only for the simplest compile-time +non-negative integer constants. The new macro model will allow cases +where the compiler can trivially see that an expression is non-negative +even if it isn't necessarily a constant. + +For example, the amdgpu driver does + + min_t(size_t, sizeof(fru_info->serial), pia[addr] & 0x3F)); + +because our old 'min()' macro would see that 'pia[addr] & 0x3F' is of +type 'int' and clearly not a C constant expression, so doing a 'min()' +with a 'size_t' is a signedness violation. + +Our new 'min()' macro still sees that 'pia[addr] & 0x3F' is of type +'int', but is smart enough to also see that it is clearly non-negative, +and thus would allow that case without any complaints. + +Cc: Arnd Bergmann +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/compiler.h | 9 +++++ + include/linux/minmax.h | 78 ++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 70 insertions(+), 17 deletions(-) + +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -245,6 +245,15 @@ static inline void *offset_to_ptr(const + #define is_unsigned_type(type) (!is_signed_type(type)) + + /* ++ * Useful shorthand for "is this condition known at compile-time?" ++ * ++ * Note that the condition may involve non-constant values, ++ * but the compiler may know enough about the details of the ++ * values to determine that the condition is statically true. ++ */ ++#define statically_true(x) (__builtin_constant_p(x) && (x)) ++ ++/* + * This is needed in functions which generate the stack canary, see + * arch/x86/kernel/smpboot.c::start_secondary() for an example. + */ +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -26,19 +26,63 @@ + #define __typecheck(x, y) \ + (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1))) + +-/* is_signed_type() isn't a constexpr for pointer types */ +-#define __is_signed(x) \ +- __builtin_choose_expr(__is_constexpr(is_signed_type(typeof(x))), \ +- is_signed_type(typeof(x)), 0) +- +-/* True for a non-negative signed int constant */ +-#define __is_noneg_int(x) \ +- (__builtin_choose_expr(__is_constexpr(x) && __is_signed(x), x, -1) >= 0) +- +-#define __types_ok(x, y, ux, uy) \ +- (__is_signed(ux) == __is_signed(uy) || \ +- __is_signed((ux) + 0) == __is_signed((uy) + 0) || \ +- __is_noneg_int(x) || __is_noneg_int(y)) ++/* ++ * __sign_use for integer expressions: ++ * bit #0 set if ok for unsigned comparisons ++ * bit #1 set if ok for signed comparisons ++ * ++ * In particular, statically non-negative signed integer ++ * expressions are ok for both. ++ * ++ * NOTE! Unsigned types smaller than 'int' are implicitly ++ * converted to 'int' in expressions, and are accepted for ++ * signed conversions for now. This is debatable. ++ * ++ * Note that 'x' is the original expression, and 'ux' is ++ * the unique variable that contains the value. ++ * ++ * We use 'ux' for pure type checking, and 'x' for when ++ * we need to look at the value (but without evaluating ++ * it for side effects! Careful to only ever evaluate it ++ * with sizeof() or __builtin_constant_p() etc). ++ * ++ * Pointers end up being checked by the normal C type ++ * rules at the actual comparison, and these expressions ++ * only need to be careful to not cause warnings for ++ * pointer use. ++ */ ++#define __signed_type_use(x,ux) (2+__is_nonneg(x,ux)) ++#define __unsigned_type_use(x,ux) (1+2*(sizeof(ux)<4)) ++#define __sign_use(x,ux) (is_signed_type(typeof(ux))? \ ++ __signed_type_use(x,ux):__unsigned_type_use(x,ux)) ++ ++/* ++ * To avoid warnings about casting pointers to integers ++ * of different sizes, we need that special sign type. ++ * ++ * On 64-bit we can just always use 'long', since any ++ * integer or pointer type can just be cast to that. ++ * ++ * This does not work for 128-bit signed integers since ++ * the cast would truncate them, but we do not use s128 ++ * types in the kernel (we do use 'u128', but they will ++ * be handled by the !is_signed_type() case). ++ * ++ * NOTE! The cast is there only to avoid any warnings ++ * from when values that aren't signed integer types. ++ */ ++#ifdef CONFIG_64BIT ++ #define __signed_type(ux) long ++#else ++ #define __signed_type(ux) typeof(__builtin_choose_expr(sizeof(ux)>4,1LL,1L)) ++#endif ++#define __is_nonneg(x,ux) statically_true((__signed_type(ux))(x)>=0) ++ ++#define __types_ok(x,y,ux,uy) \ ++ (__sign_use(x,ux) & __sign_use(y,uy)) ++ ++#define __types_ok3(x,y,z,ux,uy,uz) \ ++ (__sign_use(x,ux) & __sign_use(y,uy) & __sign_use(z,uz)) + + #define __cmp_op_min < + #define __cmp_op_max > +@@ -53,8 +97,8 @@ + + #define __careful_cmp_once(op, x, y, ux, uy) ({ \ + __auto_type ux = (x); __auto_type uy = (y); \ +- static_assert(__types_ok(x, y, ux, uy), \ +- #op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \ ++ BUILD_BUG_ON_MSG(!__types_ok(x,y,ux,uy), \ ++ #op"("#x", "#y") signedness error"); \ + __cmp(op, ux, uy); }) + + #define __careful_cmp(op, x, y) \ +@@ -70,8 +114,8 @@ + static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \ + (lo) <= (hi), true), \ + "clamp() low limit " #lo " greater than high limit " #hi); \ +- static_assert(__types_ok(uval, lo, uval, ulo), "clamp() 'lo' signedness error"); \ +- static_assert(__types_ok(uval, hi, uval, uhi), "clamp() 'hi' signedness error"); \ ++ BUILD_BUG_ON_MSG(!__types_ok3(val,lo,hi,uval,ulo,uhi), \ ++ "clamp("#val", "#lo", "#hi") signedness error"); \ + __clamp(uval, ulo, uhi); }) + + #define __careful_clamp(val, lo, hi) \ diff --git a/queue-6.6/minmax-make-generic-min-and-max-macros-available-everywhere.patch b/queue-6.6/minmax-make-generic-min-and-max-macros-available-everywhere.patch new file mode 100644 index 0000000000..a7a1412b9e --- /dev/null +++ b/queue-6.6/minmax-make-generic-min-and-max-macros-available-everywhere.patch @@ -0,0 +1,357 @@ +From prvs=353d6d59a=farbere@amazon.com Mon Sep 22 12:35:15 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:30 +0000 +Subject: minmax: make generic MIN() and MAX() macros available everywhere +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-5-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 1a251f52cfdc417c84411a056bc142cbd77baef4 ] + +This just standardizes the use of MIN() and MAX() macros, with the very +traditional semantics. The goal is to use these for C constant +expressions and for top-level / static initializers, and so be able to +simplify the min()/max() macros. + +These macro names were used by various kernel code - they are very +traditional, after all - and all such users have been fixed up, with a +few different approaches: + + - trivial duplicated macro definitions have been removed + + Note that 'trivial' here means that it's obviously kernel code that + already included all the major kernel headers, and thus gets the new + generic MIN/MAX macros automatically. + + - non-trivial duplicated macro definitions are guarded with #ifndef + + This is the "yes, they define their own versions, but no, the include + situation is not entirely obvious, and maybe they don't get the + generic version automatically" case. + + - strange use case #1 + + A couple of drivers decided that the way they want to describe their + versioning is with + + #define MAJ 1 + #define MIN 2 + #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) + + which adds zero value and I just did my Alexander the Great + impersonation, and rewrote that pointless Gordian knot as + + #define DRV_VERSION "1.2" + + instead. + + - strange use case #2 + + A couple of drivers thought that it's a good idea to have a random + 'MIN' or 'MAX' define for a value or index into a table, rather than + the traditional macro that takes arguments. + + These values were re-written as C enum's instead. The new + function-line macros only expand when followed by an open + parenthesis, and thus don't clash with enum use. + +Happily, there weren't really all that many of these cases, and a lot of +users already had the pattern of using '#ifndef' guarding (or in one +case just using '#undef MIN') before defining their own private version +that does the same thing. I left such cases alone. + +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + arch/um/drivers/mconsole_user.c | 2 + drivers/edac/skx_common.h | 1 + drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c | 2 + drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h | 14 ++++- + drivers/gpu/drm/radeon/evergreen_cs.c | 2 + drivers/hwmon/adt7475.c | 24 +++++----- + drivers/media/dvb-frontends/stv0367_priv.h | 3 + + drivers/net/fjes/fjes_main.c | 4 - + drivers/nfc/pn544/i2c.c | 2 + drivers/platform/x86/sony-laptop.c | 1 + drivers/scsi/isci/init.c | 6 -- + drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h | 5 -- + include/linux/minmax.h | 2 + kernel/trace/preemptirq_delay_test.c | 2 + lib/btree.c | 1 + lib/decompress_unlzma.c | 2 + mm/zsmalloc.c | 2 + tools/testing/selftests/mm/mremap_test.c | 2 + tools/testing/selftests/seccomp/seccomp_bpf.c | 2 + 19 files changed, 41 insertions(+), 38 deletions(-) + +--- a/arch/um/drivers/mconsole_user.c ++++ b/arch/um/drivers/mconsole_user.c +@@ -71,7 +71,9 @@ static struct mconsole_command *mconsole + return NULL; + } + ++#ifndef MIN + #define MIN(a,b) ((a)<(b) ? (a):(b)) ++#endif + + #define STRINGX(x) #x + #define STRING(x) STRINGX(x) +--- a/drivers/edac/skx_common.h ++++ b/drivers/edac/skx_common.h +@@ -45,7 +45,6 @@ + #define I10NM_NUM_CHANNELS MAX(I10NM_NUM_DDR_CHANNELS, I10NM_NUM_HBM_CHANNELS) + #define I10NM_NUM_DIMMS MAX(I10NM_NUM_DDR_DIMMS, I10NM_NUM_HBM_DIMMS) + +-#define MAX(a, b) ((a) > (b) ? (a) : (b)) + #define NUM_IMC MAX(SKX_NUM_IMC, I10NM_NUM_IMC) + #define NUM_CHANNELS MAX(SKX_NUM_CHANNELS, I10NM_NUM_CHANNELS) + #define NUM_DIMMS MAX(SKX_NUM_DIMMS, I10NM_NUM_DIMMS) +--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c ++++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c +@@ -25,7 +25,9 @@ + + #include "hdcp.h" + ++#ifndef MIN + #define MIN(a, b) ((a) < (b) ? (a) : (b)) ++#endif + #define HDCP_I2C_ADDR 0x3a /* 0x74 >> 1*/ + #define KSV_READ_SIZE 0xf /* 0x6803b - 0x6802c */ + #define HDCP_MAX_AUX_TRANSACTION_SIZE 16 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h +@@ -22,12 +22,18 @@ + */ + #include + +-#define SHIFT_AMOUNT 16 /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */ ++enum ppevvmath_constants { ++ /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */ ++ SHIFT_AMOUNT = 16, + +-#define PRECISION 5 /* Change this value to change the number of decimal places in the final output - 5 is a good default */ ++ /* Change this value to change the number of decimal places in the final output - 5 is a good default */ ++ PRECISION = 5, + +-#define SHIFTED_2 (2 << SHIFT_AMOUNT) +-#define MAX (1 << (SHIFT_AMOUNT - 1)) - 1 /* 32767 - Might change in the future */ ++ SHIFTED_2 = (2 << SHIFT_AMOUNT), ++ ++ /* 32767 - Might change in the future */ ++ MAX = (1 << (SHIFT_AMOUNT - 1)) - 1, ++}; + + /* ------------------------------------------------------------------------------- + * NEW TYPE - fINT +--- a/drivers/gpu/drm/radeon/evergreen_cs.c ++++ b/drivers/gpu/drm/radeon/evergreen_cs.c +@@ -33,8 +33,10 @@ + #include "evergreen_reg_safe.h" + #include "cayman_reg_safe.h" + ++#ifndef MIN + #define MAX(a,b) (((a)>(b))?(a):(b)) + #define MIN(a,b) (((a)<(b))?(a):(b)) ++#endif + + #define REG_SAFE_BM_SIZE ARRAY_SIZE(evergreen_reg_safe_bm) + +--- a/drivers/hwmon/adt7475.c ++++ b/drivers/hwmon/adt7475.c +@@ -22,23 +22,23 @@ + #include + + /* Indexes for the sysfs hooks */ +- +-#define INPUT 0 +-#define MIN 1 +-#define MAX 2 +-#define CONTROL 3 +-#define OFFSET 3 +-#define AUTOMIN 4 +-#define THERM 5 +-#define HYSTERSIS 6 +- ++enum adt_sysfs_id { ++ INPUT = 0, ++ MIN = 1, ++ MAX = 2, ++ CONTROL = 3, ++ OFFSET = 3, // Dup ++ AUTOMIN = 4, ++ THERM = 5, ++ HYSTERSIS = 6, + /* + * These are unique identifiers for the sysfs functions - unlike the + * numbers above, these are not also indexes into an array + */ ++ ALARM = 9, ++ FAULT = 10, ++}; + +-#define ALARM 9 +-#define FAULT 10 + + /* 7475 Common Registers */ + +--- a/drivers/media/dvb-frontends/stv0367_priv.h ++++ b/drivers/media/dvb-frontends/stv0367_priv.h +@@ -25,8 +25,11 @@ + #endif + + /* MACRO definitions */ ++#ifndef MIN + #define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) + #define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) ++#endif ++ + #define INRANGE(X, Y, Z) \ + ((((X) <= (Y)) && ((Y) <= (Z))) || \ + (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) +--- a/drivers/net/fjes/fjes_main.c ++++ b/drivers/net/fjes/fjes_main.c +@@ -14,9 +14,7 @@ + #include "fjes.h" + #include "fjes_trace.h" + +-#define MAJ 1 +-#define MIN 2 +-#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) ++#define DRV_VERSION "1.2" + #define DRV_NAME "fjes" + char fjes_driver_name[] = DRV_NAME; + char fjes_driver_version[] = DRV_VERSION; +--- a/drivers/nfc/pn544/i2c.c ++++ b/drivers/nfc/pn544/i2c.c +@@ -126,8 +126,6 @@ struct pn544_i2c_fw_secure_blob { + #define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0 + #define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6 + +-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +- + #define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7 + #define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE + #define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8 +--- a/drivers/platform/x86/sony-laptop.c ++++ b/drivers/platform/x86/sony-laptop.c +@@ -757,7 +757,6 @@ static union acpi_object *__call_snc_met + return result; + } + +-#define MIN(a, b) (a > b ? b : a) + static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, + void *buffer, size_t buflen) + { +--- a/drivers/scsi/isci/init.c ++++ b/drivers/scsi/isci/init.c +@@ -65,11 +65,7 @@ + #include "task.h" + #include "probe_roms.h" + +-#define MAJ 1 +-#define MIN 2 +-#define BUILD 0 +-#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ +- __stringify(BUILD) ++#define DRV_VERSION "1.2.0" + + MODULE_VERSION(DRV_VERSION); + +--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h ++++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h +@@ -31,11 +31,6 @@ + /* A => B */ + #define IMPLIES(a, b) (!(a) || (b)) + +-/* for preprocessor and array sizing use MIN and MAX +- otherwise use min and max */ +-#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +-#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +- + #define ROUND_DIV(a, b) (((b) != 0) ? ((a) + ((b) >> 1)) / (b) : 0) + #define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0) + #define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -277,6 +277,8 @@ static inline bool in_range32(u32 val, u + * Use these carefully: no type checking, and uses the arguments + * multiple times. Use for obvious constants only. + */ ++#define MIN(a,b) __cmp(min,a,b) ++#define MAX(a,b) __cmp(max,a,b) + #define MIN_T(type,a,b) __cmp(min,(type)(a),(type)(b)) + #define MAX_T(type,a,b) __cmp(max,(type)(a),(type)(b)) + +--- a/kernel/trace/preemptirq_delay_test.c ++++ b/kernel/trace/preemptirq_delay_test.c +@@ -34,8 +34,6 @@ MODULE_PARM_DESC(cpu_affinity, "Cpu num + + static struct completion done; + +-#define MIN(x, y) ((x) < (y) ? (x) : (y)) +- + static void busy_wait(ulong time) + { + u64 start, end; +--- a/lib/btree.c ++++ b/lib/btree.c +@@ -43,7 +43,6 @@ + #include + #include + +-#define MAX(a, b) ((a) > (b) ? (a) : (b)) + #define NODESIZE MAX(L1_CACHE_BYTES, 128) + + struct btree_geo { +--- a/lib/decompress_unlzma.c ++++ b/lib/decompress_unlzma.c +@@ -37,7 +37,9 @@ + + #include + ++#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++#endif + + static long long INIT read_int(unsigned char *ptr, int size) + { +--- a/mm/zsmalloc.c ++++ b/mm/zsmalloc.c +@@ -119,8 +119,6 @@ + #define ISOLATED_BITS 5 + #define MAGIC_VAL_BITS 8 + +-#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +- + #define ZS_MAX_PAGES_PER_ZSPAGE (_AC(CONFIG_ZSMALLOC_CHAIN_SIZE, UL)) + + /* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */ +--- a/tools/testing/selftests/mm/mremap_test.c ++++ b/tools/testing/selftests/mm/mremap_test.c +@@ -22,7 +22,9 @@ + #define VALIDATION_DEFAULT_THRESHOLD 4 /* 4MB */ + #define VALIDATION_NO_THRESHOLD 0 /* Verify the entire region */ + ++#ifndef MIN + #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) ++#endif + + struct config { + unsigned long long src_alignment; +--- a/tools/testing/selftests/seccomp/seccomp_bpf.c ++++ b/tools/testing/selftests/seccomp/seccomp_bpf.c +@@ -60,7 +60,9 @@ + #define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__) + #endif + ++#ifndef MIN + #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) ++#endif + + #ifndef PR_SET_PTRACER + # define PR_SET_PTRACER 0x59616d61 diff --git a/queue-6.6/minmax-simplify-and-clarify-min_t-max_t-implementation.patch b/queue-6.6/minmax-simplify-and-clarify-min_t-max_t-implementation.patch new file mode 100644 index 0000000000..99f97a2f3f --- /dev/null +++ b/queue-6.6/minmax-simplify-and-clarify-min_t-max_t-implementation.patch @@ -0,0 +1,76 @@ +From prvs=353d6d59a=farbere@amazon.com Mon Sep 22 12:34:24 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:28 +0000 +Subject: minmax: simplify and clarify min_t()/max_t() implementation +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-3-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit 017fa3e89187848fd056af757769c9e66ac3e93d ] + +This simplifies the min_t() and max_t() macros by no longer making them +work in the context of a C constant expression. + +That means that you can no longer use them for static initializers or +for array sizes in type definitions, but there were only a couple of +such uses, and all of them were converted (famous last words) to use +MIN_T/MAX_T instead. + +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/minmax.h | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -45,17 +45,20 @@ + + #define __cmp(op, x, y) ((x) __cmp_op_##op (y) ? (x) : (y)) + +-#define __cmp_once(op, x, y, unique_x, unique_y) ({ \ +- typeof(x) unique_x = (x); \ +- typeof(y) unique_y = (y); \ ++#define __cmp_once_unique(op, type, x, y, ux, uy) \ ++ ({ type ux = (x); type uy = (y); __cmp(op, ux, uy); }) ++ ++#define __cmp_once(op, type, x, y) \ ++ __cmp_once_unique(op, type, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_)) ++ ++#define __careful_cmp_once(op, x, y) ({ \ + static_assert(__types_ok(x, y), \ + #op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \ +- __cmp(op, unique_x, unique_y); }) ++ __cmp_once(op, __auto_type, x, y); }) + + #define __careful_cmp(op, x, y) \ + __builtin_choose_expr(__is_constexpr((x) - (y)), \ +- __cmp(op, x, y), \ +- __cmp_once(op, x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y))) ++ __cmp(op, x, y), __careful_cmp_once(op, x, y)) + + #define __clamp(val, lo, hi) \ + ((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val))) +@@ -158,7 +161,7 @@ + * @x: first value + * @y: second value + */ +-#define min_t(type, x, y) __careful_cmp(min, (type)(x), (type)(y)) ++#define min_t(type, x, y) __cmp_once(min, type, x, y) + + /** + * max_t - return maximum of two values, using the specified type +@@ -166,7 +169,7 @@ + * @x: first value + * @y: second value + */ +-#define max_t(type, x, y) __careful_cmp(max, (type)(x), (type)(y)) ++#define max_t(type, x, y) __cmp_once(max, type, x, y) + + /* + * Do not check the array parameter using __must_be_array(). diff --git a/queue-6.6/minmax-simplify-min-max-clamp-implementation.patch b/queue-6.6/minmax-simplify-min-max-clamp-implementation.patch new file mode 100644 index 0000000000..26733f8031 --- /dev/null +++ b/queue-6.6/minmax-simplify-min-max-clamp-implementation.patch @@ -0,0 +1,140 @@ +From stable+bounces-180928-greg=kroah.com@vger.kernel.org Mon Sep 22 12:37:49 2025 +From: Eliav Farber +Date: Mon, 22 Sep 2025 10:32:31 +0000 +Subject: minmax: simplify min()/max()/clamp() implementation +To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , +Cc: Linus Torvalds , David Laight , Lorenzo Stoakes +Message-ID: <20250922103241.16213-6-farbere@amazon.com> + +From: Linus Torvalds + +[ Upstream commit dc1c8034e31b14a2e5e212104ec508aec44ce1b9 ] + +Now that we no longer have any C constant expression contexts (ie array +size declarations or static initializers) that use min() or max(), we +can simpify the implementation by not having to worry about the result +staying as a C constant expression. + +So now we can unconditionally just use temporary variables of the right +type, and get rid of the excessive expansion that used to come from the +use of + + __builtin_choose_expr(__is_constexpr(...), .. + +to pick the specialized code for constant expressions. + +Another expansion simplification is to pass the temporary variables (in +addition to the original expression) to our __types_ok() macro. That +may superficially look like it complicates the macro, but when we only +want the type of the expression, expanding the temporary variable names +is much simpler and smaller than expanding the potentially complicated +original expression. + +As a result, on my machine, doing a + + $ time make drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.i + +goes from + + real 0m16.621s + user 0m15.360s + sys 0m1.221s + +to + + real 0m2.532s + user 0m2.091s + sys 0m0.452s + +because the token expansion goes down dramatically. + +In particular, the longest line expansion (which was line 71 of that +'ia_css_ynr.host.c' file) shrinks from 23,338kB (yes, 23MB for one +single line) to "just" 1,444kB (now "only" 1.4MB). + +And yes, that line is still the line from hell, because it's doing +multiple levels of "min()/max()" expansion thanks to some of them being +hidden inside the uDIGIT_FITTING() macro. + +Lorenzo has a nice cleanup patch that makes that driver use inline +functions instead of macros for sDIGIT_FITTING() and uDIGIT_FITTING(), +which will fix that line once and for all, but the 16-fold reduction in +this case does show why we need to simplify these helpers. + +Cc: David Laight +Cc: Lorenzo Stoakes +Signed-off-by: Linus Torvalds +Signed-off-by: Eliav Farber +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/minmax.h | 43 ++++++++++++++++++++----------------------- + 1 file changed, 20 insertions(+), 23 deletions(-) + +--- a/include/linux/minmax.h ++++ b/include/linux/minmax.h +@@ -35,10 +35,10 @@ + #define __is_noneg_int(x) \ + (__builtin_choose_expr(__is_constexpr(x) && __is_signed(x), x, -1) >= 0) + +-#define __types_ok(x, y) \ +- (__is_signed(x) == __is_signed(y) || \ +- __is_signed((x) + 0) == __is_signed((y) + 0) || \ +- __is_noneg_int(x) || __is_noneg_int(y)) ++#define __types_ok(x, y, ux, uy) \ ++ (__is_signed(ux) == __is_signed(uy) || \ ++ __is_signed((ux) + 0) == __is_signed((uy) + 0) || \ ++ __is_noneg_int(x) || __is_noneg_int(y)) + + #define __cmp_op_min < + #define __cmp_op_max > +@@ -51,34 +51,31 @@ + #define __cmp_once(op, type, x, y) \ + __cmp_once_unique(op, type, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_)) + +-#define __careful_cmp_once(op, x, y) ({ \ +- static_assert(__types_ok(x, y), \ ++#define __careful_cmp_once(op, x, y, ux, uy) ({ \ ++ __auto_type ux = (x); __auto_type uy = (y); \ ++ static_assert(__types_ok(x, y, ux, uy), \ + #op "(" #x ", " #y ") signedness error, fix types or consider u" #op "() before " #op "_t()"); \ +- __cmp_once(op, __auto_type, x, y); }) ++ __cmp(op, ux, uy); }) + +-#define __careful_cmp(op, x, y) \ +- __builtin_choose_expr(__is_constexpr((x) - (y)), \ +- __cmp(op, x, y), __careful_cmp_once(op, x, y)) ++#define __careful_cmp(op, x, y) \ ++ __careful_cmp_once(op, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_)) + + #define __clamp(val, lo, hi) \ + ((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val))) + +-#define __clamp_once(val, lo, hi, unique_val, unique_lo, unique_hi) ({ \ +- typeof(val) unique_val = (val); \ +- typeof(lo) unique_lo = (lo); \ +- typeof(hi) unique_hi = (hi); \ ++#define __clamp_once(val, lo, hi, uval, ulo, uhi) ({ \ ++ __auto_type uval = (val); \ ++ __auto_type ulo = (lo); \ ++ __auto_type uhi = (hi); \ + static_assert(__builtin_choose_expr(__is_constexpr((lo) > (hi)), \ + (lo) <= (hi), true), \ + "clamp() low limit " #lo " greater than high limit " #hi); \ +- static_assert(__types_ok(val, lo), "clamp() 'lo' signedness error"); \ +- static_assert(__types_ok(val, hi), "clamp() 'hi' signedness error"); \ +- __clamp(unique_val, unique_lo, unique_hi); }) +- +-#define __careful_clamp(val, lo, hi) ({ \ +- __builtin_choose_expr(__is_constexpr((val) - (lo) + (hi)), \ +- __clamp(val, lo, hi), \ +- __clamp_once(val, lo, hi, __UNIQUE_ID(__val), \ +- __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); }) ++ static_assert(__types_ok(uval, lo, uval, ulo), "clamp() 'lo' signedness error"); \ ++ static_assert(__types_ok(uval, hi, uval, uhi), "clamp() 'hi' signedness error"); \ ++ __clamp(uval, ulo, uhi); }) ++ ++#define __careful_clamp(val, lo, hi) \ ++ __clamp_once(val, lo, hi, __UNIQUE_ID(v_), __UNIQUE_ID(l_), __UNIQUE_ID(h_)) + + /** + * min - return minimum of two values of the same or compatible types diff --git a/queue-6.6/series b/queue-6.6/series index b577e648ac..40cf82ab9f 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -64,3 +64,11 @@ xhci-dbc-fix-full-dbc-transfer-ring-after-several-reconnects.patch iommu-amd-pgtbl-fix-possible-race-while-increase-page-table-level.patch rtc-pcf2127-fix-spi-command-byte-for-pcf2131-backport.patch mptcp-propagate-shutdown-to-subflows-when-possible.patch +minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch +minmax-simplify-and-clarify-min_t-max_t-implementation.patch +minmax-add-a-few-more-min_t-max_t-users.patch +minmax-make-generic-min-and-max-macros-available-everywhere.patch +minmax-simplify-min-max-clamp-implementation.patch +minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch +minmax-improve-macro-expansion-and-type-checking.patch +minmax-fix-up-min3-and-max3-too.patch