Commit a3f6a89c authored by Marc Zyngier's avatar Marc Zyngier Committed by Andrew Morton
Browse files

scripts: fix gfp-translate after ___GFP_*_BITS conversion to an enum

Richard reports that since 772dd034 ("mm: enumerate all gfp flags"),
gfp-translate is broken, as the bit numbers are implicit, leaving the
shell script unable to extract them.  Even more, some bits are now at a
variable location, making it double extra hard to parse using a simple
shell script.

Use a brute-force approach to the problem by generating a small C stub
that will use the enum to dump the interesting bits.

As an added bonus, we are now able to identify invalid bits for a given
configuration.  As an added drawback, we cannot parse include files that
predate this change anymore.  Tough luck.

Link: https://lkml.kernel.org/r/20240823163850.3791201-1-maz@kernel.org


Fixes: 772dd034 ("mm: enumerate all gfp flags")
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Reported-by: default avatarRichard Weinberger <richard@nod.at>
Cc: Petr Tesařík <petr@tesarici.cz>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent bfe0857c
Loading
Loading
Loading
Loading
+49 −17
Original line number Diff line number Diff line
@@ -62,25 +62,57 @@ if [ "$GFPMASK" = "none" ]; then
fi

# Extract GFP flags from the kernel source
TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1
grep -q ___GFP $SOURCE/include/linux/gfp_types.h
if [ $? -eq 0 ]; then
	grep "^#define ___GFP" $SOURCE/include/linux/gfp_types.h | sed -e 's/u$//' | grep -v GFP_BITS > $TMPFILE
else
	grep "^#define __GFP" $SOURCE/include/linux/gfp_types.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
fi
TMPFILE=`mktemp -t gfptranslate-XXXXXX.c` || exit 1

# Parse the flags
IFS="
"
echo Source: $SOURCE
echo Parsing: $GFPMASK
for LINE in `cat $TMPFILE`; do
	MASK=`echo $LINE | awk '{print $3}'`
	if [ $(($GFPMASK&$MASK)) -ne 0 ]; then
		echo $LINE
	fi

(
    cat <<EOF
#include <stdint.h>
#include <stdio.h>

// Try to fool compiler.h into not including extra stuff
#define __ASSEMBLY__	1

#include <generated/autoconf.h>
#include <linux/gfp_types.h>

static const char *masks[] = {
EOF

    sed -nEe 's/^[[:space:]]+(___GFP_.*)_BIT,.*$/\1/p' $SOURCE/include/linux/gfp_types.h |
	while read b; do
	    cat <<EOF
#if defined($b) && ($b > 0)
	[${b}_BIT]	= "$b",
#endif
EOF
	done

rm -f $TMPFILE
    cat <<EOF
};

int main(int argc, char *argv[])
{
	unsigned long long mask = $GFPMASK;

	for (int i = 0; i < sizeof(mask) * 8; i++) {
		unsigned long long bit = 1ULL << i;
		if (mask & bit)
			printf("\t%-25s0x%llx\n",
			       (i < ___GFP_LAST_BIT && masks[i]) ?
					masks[i] : "*** INVALID ***",
			       bit);
	}

	return 0;
}
EOF
) > $TMPFILE

${CC:-gcc} -Wall -o ${TMPFILE}.bin -I $SOURCE/include $TMPFILE && ${TMPFILE}.bin

rm -f $TMPFILE ${TMPFILE}.bin

exit 0