linux_kernel_cleanup

This is an old revision of the document!


Several years ago, I wrote a number of Linux kernel “cleanup” scripts that scanned the kernel source tree to identify obvious candidates for cleanup or simplification. The scripts are below, and they are admittedly imperfect as there is no way to consider every possible variation of what they look for, so they will almost certainly display some false positives.

The point here is that Linux kernel “newbies” are welcome to examine these scripts, tweak them, run them, and submit organized and well-documented patches if they want to become contributors to the kernel.

Over the next several days, I'll be adding the cleanup scripts one at a time after I check them over and perhaps tidy them up a bit, but be warned that many of them are just brute force searching, so you're expected to check the output. If you have any comments or want to improve the scripts, drop me a note at rpjday@crashcourse.ca.

So far, the cleanup scripts below are for:

  • calculating the length of an array
  • checking for testing for a power of 2
  • identifying “bad” select directives in Kconfig files

NOTE: Don't try to submit a mega-patch with as many similar patches as you possibly can; rather, submit patches on a subsystem by subsystem basis, to make the patches manageable so that they can be reviewed and approved by just the maintainers of that subsystem.

IMPORTANT: Do not accept the output from any of these or upcoming scripts verbatim. There is no question that these scripts cannot possibly take into account every conceivable variation being searched for, so treat the results with skepticism and do extra sanity checking to make sure your submitted improvements make sense. If you're unsure, check the Git log to see if there are previous commits that back up your interpretation of what you're seeing.

1. Calculating the length of an array

A lot of kernel code needs to calculate the length of an array, frequently to iterate through all of its elements. There are two standard ways to do this in C language:

sizeof(array) / (sizeof(array[0]))
sizeof(array) / sizeof(*(array))

This shortcut is already defined in the kernel header file include/linux/array_size.h:

/**
 * ARRAY_SIZE - get the number of elements in array @arr
 * @arr: array to be sized
 */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))

Here is a script that looks for expressions that appear to match that pattern (note how the script accepts an optional argument as to which directory is the target of the search):

#!/bin/sh

DIR=${1-.}

grep -Er "sizeof ?\(?([^\)]+)\)? ?/ ?sizeof ?\(?.*\1.*" ${DIR}

As a sample run, here's running the script on the kernel “arch/” directory:

$ arraysize.sh arch
arch/powerpc/boot/types.h:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
arch/powerpc/xmon/ppc-opc.c:  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
arch/powerpc/xmon/ppc-opc.c:  sizeof (vle_opcodes) / sizeof (vle_opcodes[0]);
arch/powerpc/xmon/ppc-opc.c:  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
arch/um/include/shared/user.h:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
arch/um/kernel/config.c.in:	for (i = 0; i < sizeof(config)/sizeof(config[0]); i++)
arch/um/kernel/skas/stub_exe.c:			.len = sizeof(filter) / sizeof(filter[0]),
arch/s390/tools/gen_opcode_table.c:	for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
arch/s390/tools/gen_facilities.c:	for (i = 0; i < sizeof(facility_defs) / sizeof(facility_defs[0]); i++)
arch/s390/include/asm/fpu.h:	__save_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
arch/s390/include/asm/fpu.h:	__load_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
arch/mips/boot/tools/relocs.h:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
arch/mips/sgi-ip22/ip28-berr.c:	for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) {
arch/mips/sgi-ip22/ip28-berr.c:	if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) {
arch/x86/um/shared/sysdep/stub_32.h:	for (int i = 0; i < sizeof(arch->tls) / sizeof(arch->tls[0]); i++) {
arch/x86/boot/boot.h:#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
arch/x86/tools/relocs.h:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

Note that there some obvious examples of what the script is looking for, as well as some false positives. Note also how various files insist on re-inventing the test in defining a macro that does what is already in that Linux header file.

2. Check if something is a power of two

Quite a lot of kernel code needs to check if an integer value is an exact power of two – the general test for that is already defined in the header file include/linux/log2.h as follows:

/**
 * is_power_of_2() - check if a value is a power of two
 * @n: the value to check
 *
 * Determine whether some value is a power of two, where zero is
 * *not* considered a power of two.
 * Return: true if @n is a power of 2, otherwise false.
 */
static __always_inline __attribute__((const))
bool is_power_of_2(unsigned long n)
{
        return (n != 0 && ((n & (n - 1)) == 0));
}

Because of the number of variations of that test involving parenthesization, the cleanup script just brute forces its way through a number of slight changes:

#!/bin/sh

DIR=${1-*}

echo "PATTERN:     x & (x - 1):\n"
grep -Ern "([^\(\)]+) ?\& ?\(\1 ?- ?1\)" ${DIR}
echo "PATTERN:     x & ((x) - 1):\n"
grep -Ern "([^\(\)]+) ?\& ?\(\(\1\) ?- ?1\)" ${DIR}
echo "PATTERN:     (x) & (x - 1):\n"
grep -Ern "\(([^\(\)]+)\) ?\& ?\(\1 ?- ?1\)" ${DIR}
echo "PATTERN:     (x) & ((x) - 1):\n"
grep -Ern "\(([^\(\)]+)\) ?\& ?\(\(\1\) ?- ?1\)" ${DIR}

As a simple example, check the lib/ directory – here's the snipped output:

$ test_for_power_of_2.sh lib
PATTERN:     x & (x - 1):

lib/zstd/compress/zstd_lazy.c:810:    assert((align & (align - 1)) == 0);
lib/zstd/compress/huf_compress.c:116:    assert((align & (align - 1)) == 0); /* pow 2 */
lib/zstd/compress/zstd_compress_internal.h:1189:    assert((maxDist & (maxDist - 1)) == 0);
lib/zstd/common/compiler.h:181:    return (u & (u-1)) == 0;

Note well that if you search for that expression, many tests are actually checking if the number in question is not a power of two, so make sure you notice the difference. Here's the output running that script against the arch/powerpc directory:

arch/powerpc/sysdev/fsl_rio.c:317:	if ((size & (size - 1)) != 0 || size > 0x400000000ULL)
arch/powerpc/mm/book3s32/mmu.c:370:	if (n_hpteg & (n_hpteg - 1)) {
arch/powerpc/boot/cuboot-pq2.c:173:	if (mem->size[1] & (mem->size[1] - 1))
arch/powerpc/boot/cuboot-pq2.c:175:	if (io->size[1] & (io->size[1] - 1))
arch/powerpc/include/asm/bitops.h:93:	return !(x & (x - 1));
arch/powerpc/platforms/44x/pci.c:166:	if ((size & (size - 1)) != 0  ||
arch/powerpc/lib/rheap.c:258:	if ((alignment & (alignment - 1)) != 0)
arch/powerpc/lib/rheap.c:307:	if ((alignment & (alignment - 1)) != 0)
arch/powerpc/lib/rheap.c:450:	if (size <= 0 || (alignment & (alignment - 1)) != 0)

so you need to be careful as to what you think any of that simplifies to.

3. Finding "bad" select directives in Kconfig files

Many kernel Kconfig files contain “select” directives, some of which are no longer relevant since the config entry they refer to was deleted previously, but the associated “select” directives were never removed. This is clearly not fatal, but it's still something that can be cleaned up.

Here is the current script that scans the tree (or a specified subdirectory) searching for select directives that don't seem to have any current value:

#!/bin/sh

DIR=${1-*}

DIRKS=$(find ${DIR} -name "Kconfig*")
ALLKS=$(find . -name "Kconfig*")

SELS=$(grep -h "^       select " ${DIRKS} |     \
        sed -e 's|.*select[     ]*\([^  ]*\).*|\1|' |   \
        sort -u)

for sel in ${SELS} ; do
        grep -q "config[        ]*${sel}$" ${ALLKS} || {
                echo "===== ${sel}"
                grep -rwn ${sel} *
        }
done

Running that script on the arch/ subdirectory produces the following potentially removable lines:

$ find_bad_selects.sh arch
===== ARCH_HAS_HOLES_MEMORYMODEL
arch/arm/mach-omap1/Kconfig:7:	select ARCH_HAS_HOLES_MEMORYMODEL
===== ARM_ERRATA_794072
arch/arm/mach-npcm/Kconfig:33:	select ARM_ERRATA_794072
===== ARM_SMC_MBOX
arch/arm64/Kconfig.platforms:315:	select ARM_SMC_MBOX
===== HAVE_LEGACY_CLK
arch/sh/boards/Kconfig:13:	select HAVE_LEGACY_CLK
arch/mips/Kconfig:334:	select HAVE_LEGACY_CLK
arch/mips/Kconfig:475:	select HAVE_LEGACY_CLK
arch/m68k/Kconfig.cpu:33:	select HAVE_LEGACY_CLK
drivers/clk/Kconfig:12:config HAVE_LEGACY_CLK # TODO: Remove once all legacy users are migrated
drivers/clk/Kconfig:23:	depends on !HAVE_LEGACY_CLK
===== PINCTRL_MILBEAUT
arch/arm/mach-milbeaut/Kconfig:16:	select PINCTRL_MILBEAUT
===== USB_OHCI_SH
arch/sh/Kconfig:335:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:345:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:430:	select USB_OHCI_SH if USB_OHCI_HCD
arch/sh/Kconfig:456:	select USB_OHCI_SH if USB_OHCI_HCD
  • linux_kernel_cleanup.1751306837.txt.gz
  • Last modified: 2025/06/30 18:07
  • by rpjday