https://github.com/torvalds/linux
Revision 3a7e02c040b130b5545e4b115aada7bacd80a2b6 authored by Linus Torvalds on 26 July 2024, 22:32:27 UTC, committed by Linus Torvalds on 26 July 2024, 22:32:27 UTC
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 <lorenzo.stoakes@oracle.com>
Link: https://lore.kernel.org/all/36aa2cad-1db1-4abf-8dd2-fb20484aabc3@lucifer.local/
Cc: David Laight <David.Laight@aculab.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent e8432ac
Raw File
Tip revision: 3a7e02c040b130b5545e4b115aada7bacd80a2b6 authored by Linus Torvalds on 26 July 2024, 22:32:27 UTC
minmax: avoid overly complicated constant expressions in VM code
Tip revision: 3a7e02c
des_generic.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Cryptographic API.
 *
 * DES & Triple DES EDE Cipher Algorithms.
 *
 * Copyright (c) 2005 Dag Arne Osvik <da@osvik.no>
 */

#include <asm/byteorder.h>
#include <crypto/algapi.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>

#include <crypto/internal/des.h>

static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
		      unsigned int keylen)
{
	struct des_ctx *dctx = crypto_tfm_ctx(tfm);
	int err;

	err = des_expand_key(dctx, key, keylen);
	if (err == -ENOKEY) {
		if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)
			err = -EINVAL;
		else
			err = 0;
	}
	if (err)
		memset(dctx, 0, sizeof(*dctx));
	return err;
}

static void crypto_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	const struct des_ctx *dctx = crypto_tfm_ctx(tfm);

	des_encrypt(dctx, dst, src);
}

static void crypto_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
	const struct des_ctx *dctx = crypto_tfm_ctx(tfm);

	des_decrypt(dctx, dst, src);
}

static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
			   unsigned int keylen)
{
	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
	int err;

	err = des3_ede_expand_key(dctx, key, keylen);
	if (err == -ENOKEY) {
		if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)
			err = -EINVAL;
		else
			err = 0;
	}
	if (err)
		memset(dctx, 0, sizeof(*dctx));
	return err;
}

static void crypto_des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst,
				    const u8 *src)
{
	const struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);

	des3_ede_encrypt(dctx, dst, src);
}

static void crypto_des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst,
				    const u8 *src)
{
	const struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);

	des3_ede_decrypt(dctx, dst, src);
}

static struct crypto_alg des_algs[2] = { {
	.cra_name		=	"des",
	.cra_driver_name	=	"des-generic",
	.cra_priority		=	100,
	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
	.cra_blocksize		=	DES_BLOCK_SIZE,
	.cra_ctxsize		=	sizeof(struct des_ctx),
	.cra_module		=	THIS_MODULE,
	.cra_u			=	{ .cipher = {
	.cia_min_keysize	=	DES_KEY_SIZE,
	.cia_max_keysize	=	DES_KEY_SIZE,
	.cia_setkey		=	des_setkey,
	.cia_encrypt		=	crypto_des_encrypt,
	.cia_decrypt		=	crypto_des_decrypt } }
}, {
	.cra_name		=	"des3_ede",
	.cra_driver_name	=	"des3_ede-generic",
	.cra_priority		=	100,
	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
	.cra_blocksize		=	DES3_EDE_BLOCK_SIZE,
	.cra_ctxsize		=	sizeof(struct des3_ede_ctx),
	.cra_module		=	THIS_MODULE,
	.cra_u			=	{ .cipher = {
	.cia_min_keysize	=	DES3_EDE_KEY_SIZE,
	.cia_max_keysize	=	DES3_EDE_KEY_SIZE,
	.cia_setkey		=	des3_ede_setkey,
	.cia_encrypt		=	crypto_des3_ede_encrypt,
	.cia_decrypt		=	crypto_des3_ede_decrypt } }
} };

static int __init des_generic_mod_init(void)
{
	return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs));
}

static void __exit des_generic_mod_fini(void)
{
	crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs));
}

subsys_initcall(des_generic_mod_init);
module_exit(des_generic_mod_fini);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
MODULE_AUTHOR("Dag Arne Osvik <da@osvik.no>");
MODULE_ALIAS_CRYPTO("des");
MODULE_ALIAS_CRYPTO("des-generic");
MODULE_ALIAS_CRYPTO("des3_ede");
MODULE_ALIAS_CRYPTO("des3_ede-generic");
back to top