Files
monok8s/docs/ask-deepresearch-4.md
2026-04-30 22:05:23 +08:00

261 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `filter-kconfig-fragment.sh` for Reproducible Kernel-Config Filtering
## Executive summary
I did **not** find a file named `filter-kconfig-fragment.sh` in the uploaded project files or in the supplied ASK/kernel tarballs. What **is** present is the standard kernel-side machinery you would use around such a filter: the Linux kernels own `scripts/kconfig/merge_config.sh` for fragment merging, `scripts/config` for imperative `.config` edits, and documented Kconfig controls such as `KCONFIG_WARN_UNKNOWN_SYMBOLS`, `KCONFIG_WERROR`, and `KCONFIG_ALLCONFIG`. The kernel tree itself also uses `merge_config.sh` followed by `olddefconfig` when it builds from config fragments. citeturn3view1turn0search2turn3view2
A small pre-filter is still useful, because neither `merge_config.sh` nor `scripts/config` is meant to silently rewrite a fragment for a **different kernel generation**. `merge_config.sh` merges and warns; `scripts/config` edits `.config`; Kconfig enforces symbol existence and dependency rules. When a fragment contains a symbol that simply does not exist in the target tree, such as `CONFIG_NETFILTER_XTABLES_LEGACY` in your reported 6.12-based tree, a pre-filter avoids an avoidable mismatch by dropping only the absent symbol while preserving ordering, comments, and all valid settings. That is the narrow job of the replacement script below. citeturn3view1turn3view2turn3view6
The replacement script in this report is POSIX `sh`, offline-safe, requires only standard Unix tools (`find`, `grep`, `sed`, `mktemp`, `cat`), validates inputs, checks for `scripts/kconfig/merge_config.sh`, preserves comments and ordering, emits only symbols that exist in the target Kconfig tree, and exits non-zero if nothing usable remains after filtering. It is designed specifically for Docker builder stages and reproducible kernel-config flows. citeturn3view1turn3view2turn3view4
## What I found and what to use instead
The Linux kernel already ships the two main utilities you should treat as authoritative.
`merge_config.sh` is the standard fragment-merging tool in the kernel tree. Its own header says it “takes a list of config fragment values, and merges them one by one,” and that it warns about overridden values and symbols that did not make it into the final `.config` because of dependencies or symbol removal. The kernel build system also invokes `scripts/kconfig/merge_config.sh -m $(KCONFIG_CONFIG) ...` and then runs `olddefconfig` for fragment-based config targets. citeturn3view1turn0search2
`scripts/config` is the standard imperative editor for `.config`. Its built-in usage text documents `--enable`, `--disable`, `--module`, `--set-str`, `--set-val`, `--undefine`, `--state`, and `--file`, and also states that it does **not** validate `.config` immediately; that validation happens at the next `make` step. The kernel docs also contain concrete examples of `./scripts/config -e ...` and `-m ...` being used to enable required options. citeturn3view0turn3view5
Kconfig itself exposes the exact controls you want for drift detection: `KCONFIG_WARN_UNKNOWN_SYMBOLS` warns on unrecognized config symbols, `KCONFIG_WERROR` turns those warnings into errors, and `KCONFIG_ALLCONFIG` provides a documented “mini-config” mechanism for all*config targets. The same docs also recommend `make listnewconfig` to surface newly introduced symbols. citeturn3view2turn5view0
For external module builds, the kernel docs also matter here: `modules_prepare` can prepare a tree for external modules, but it does **not** produce `Module.symvers` if `CONFIG_MODVERSIONS` matters, so a full kernel build is still required in that case. That is the main reason a strict builder pipeline should validate kernel config and preparation before invoking out-of-tree module builds. citeturn3view4
## Minimal portable replacement script
Assumptions for this script:
- `KERNEL_DIR` is a Linux kernel source tree root.
- The tree contains `scripts/kconfig/merge_config.sh`.
- Config symbols are defined in `Kconfig*` files somewhere under `KERNEL_DIR`.
- The fragment format is standard Kconfig fragment syntax: `CONFIG_FOO=...` and `# CONFIG_FOO is not set`.
- The builder environment has POSIX `sh`, `find`, `grep`, `sed`, `mktemp`, `cat`, and `rm`.
**`scripts/filter-kconfig-fragment.sh`**
```sh
#!/bin/sh
# filter-kconfig-fragment.sh
#
# Purpose:
# Emit an "effective" Kconfig fragment that preserves comments and ordering
# but drops CONFIG symbols that do not exist in the target kernel tree.
#
# Usage:
# filter-kconfig-fragment.sh KERNEL_DIR FRAGMENT_FILE > effective.config
#
# Exit codes:
# 2 invalid usage / missing required files
# 3 no Kconfig files were found in KERNEL_DIR
# 4 fragment had no surviving CONFIG lines after filtering
set -eu
usage() {
echo "usage: $0 KERNEL_DIR FRAGMENT_FILE" >&2
exit 2
}
[ "$#" -eq 2 ] || usage
KERNEL_DIR=$1
FRAGMENT_FILE=$2
MERGE_SCRIPT=$KERNEL_DIR/scripts/kconfig/merge_config.sh
[ -d "$KERNEL_DIR" ] || {
echo "error: KERNEL_DIR is not a directory: $KERNEL_DIR" >&2
exit 2
}
[ -r "$FRAGMENT_FILE" ] || {
echo "error: FRAGMENT_FILE is not readable: $FRAGMENT_FILE" >&2
exit 2
}
[ -s "$FRAGMENT_FILE" ] || {
echo "error: FRAGMENT_FILE is empty: $FRAGMENT_FILE" >&2
exit 2
}
[ -r "$MERGE_SCRIPT" ] || {
echo "error: required kernel utility missing: $MERGE_SCRIPT" >&2
exit 2
}
TMP_KCONFIGS=$(mktemp)
TMP_OUT=$(mktemp)
trap 'rm -f "$TMP_KCONFIGS" "$TMP_OUT"' EXIT HUP INT TERM
# Index all Kconfig files once. Searching the whole tree is simpler and more
# robust than hardcoding a small directory subset.
find "$KERNEL_DIR" -type f \( -name 'Kconfig' -o -name 'Kconfig*' \) | sort > "$TMP_KCONFIGS"
[ -s "$TMP_KCONFIGS" ] || {
echo "error: no Kconfig files found under $KERNEL_DIR" >&2
exit 3
}
symbol_exists() {
# Accept either CONFIG_FOO or FOO.
sym=$1
case "$sym" in
CONFIG_*) sym=${sym#CONFIG_} ;;
esac
# We treat both "config FOO" and "menuconfig FOO" as symbol definitions.
# GNU grep and busybox grep both support -E.
while IFS= read -r kf; do
if grep -Eq "^[[:space:]]*(menu)?config[[:space:]]+$sym([[:space:]]|\$)" "$kf"; then
return 0
fi
done < "$TMP_KCONFIGS"
return 1
}
kept_symbols=0
while IFS= read -r line || [ -n "$line" ]; do
# Preserve blank lines exactly.
if [ -z "$line" ]; then
printf '\n' >> "$TMP_OUT"
continue
fi
case "$line" in
'# 'CONFIG_*' is not set')
# Example: "# CONFIG_FOO is not set"
sym=$(printf '%s\n' "$line" | sed -n 's/^# \(CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*\) is not set$/\1/p')
if [ -n "$sym" ] && symbol_exists "$sym"; then
printf '%s\n' "$line" >> "$TMP_OUT"
kept_symbols=$((kept_symbols + 1))
fi
;;
CONFIG_*=*)
# Example: "CONFIG_FOO=y" or "CONFIG_BAR=\"abc\""
sym=${line%%=*}
if symbol_exists "$sym"; then
printf '%s\n' "$line" >> "$TMP_OUT"
kept_symbols=$((kept_symbols + 1))
fi
;;
'#'*)
# Preserve comments and headings.
printf '%s\n' "$line" >> "$TMP_OUT"
;;
*)
# Preserve any other non-empty line verbatim; fragments normally
# shouldn't contain these, but preserving them is safer than rewriting.
printf '%s\n' "$line" >> "$TMP_OUT"
;;
esac
done < "$FRAGMENT_FILE"
if [ "$kept_symbols" -eq 0 ]; then
echo "error: no CONFIG entries remain after filtering $FRAGMENT_FILE" >&2
exit 4
fi
cat "$TMP_OUT"
```
This script is intentionally narrow. It does **not** try to solve dependency resolution, force values, or replace `merge_config.sh`. It only answers one question: “Does this symbol exist anywhere in the target kernels Kconfig tree?” That is the right preflight step when a fragment spans multiple kernel generations and you need a portable Docker-safe filter before Kconfig proper enforces dependencies. citeturn3view1turn3view2turn3view6
## Integration examples
### Dockerfile usage
```dockerfile
COPY scripts/filter-kconfig-fragment.sh /usr/local/bin/filter-kconfig-fragment.sh
COPY docker/kernel-extra.config /tmp/kernel-extra.config
RUN chmod +x /usr/local/bin/filter-kconfig-fragment.sh && \
test -d /opt/kernel && \
/usr/local/bin/filter-kconfig-fragment.sh /opt/kernel /tmp/kernel-extra.config \
> /tmp/kernel-extra.effective.config && \
/opt/kernel/scripts/kconfig/merge_config.sh -m /opt/kernel/.config /tmp/kernel-extra.effective.config && \
KCONFIG_WARN_UNKNOWN_SYMBOLS=1 KCONFIG_WERROR=1 \
make -C /opt/kernel olddefconfig && \
make -C /opt/kernel modules_prepare
```
If `CONFIG_MODVERSIONS=y` or your external modules depend on `Module.symvers`, replace the final `modules_prepare` with a full kernel build step for the relevant targets. The kernel docs explicitly warn that `modules_prepare` does not produce `Module.symvers`. citeturn3view4
### Makefile usage
```make
KERNEL_DIR ?= /opt/kernel
KERNEL_FRAGMENT ?= docker/kernel-extra.config
KERNEL_EFFECTIVE?= build/kernel-extra.effective.config
KCONFIG_FILTER ?= scripts/filter-kconfig-fragment.sh
$(KERNEL_EFFECTIVE): $(KERNEL_FRAGMENT) $(KCONFIG_FILTER)
mkdir -p $(dir $@)
$(KCONFIG_FILTER) $(KERNEL_DIR) $(KERNEL_FRAGMENT) > $@
kernel-merge: $(KERNEL_EFFECTIVE)
$(KERNEL_DIR)/scripts/kconfig/merge_config.sh -m $(KERNEL_DIR)/.config $(KERNEL_EFFECTIVE)
KCONFIG_WARN_UNKNOWN_SYMBOLS=1 KCONFIG_WERROR=1 $(MAKE) -C $(KERNEL_DIR) olddefconfig
kernel-prepare: kernel-merge
$(MAKE) -C $(KERNEL_DIR) modules_prepare
```
### Why the filter is needed
This filter exists to handle **kernel-version mismatches in fragments**, not to bypass Kconfig. A fragment can be perfectly valid for kernel line A and partially invalid for kernel line B because symbols were renamed, split, removed, or introduced later. Your concrete example, `CONFIG_NETFILTER_XTABLES_LEGACY`, is exactly that class of problem: the symbol may be meaningful in one kernel generation and absent in another. Filtering it out before `merge_config.sh` and `olddefconfig` prevents a false failure from one stale line while still allowing Kconfig to validate all remaining, real symbols and dependencies. Kconfigs own docs explain that symbols live in a dependency-aware tree and that visibility and legality depend on those relationships, which is why the filter should check **existence only** and leave dependency resolution to Kconfig itself. citeturn3view6turn3view2
```mermaid
flowchart LR
A[kernel-extra.config] --> B[filter-kconfig-fragment.sh]
B --> C[kernel-extra.effective.config]
C --> D[merge_config.sh -m .config effective.fragment]
D --> E[make olddefconfig]
E --> F[make modules_prepare or full kernel build]
```
## Quick checks and validation commands
Use these checks before or after wiring the script into Docker:
### Check whether a symbol exists in the target tree
```sh
grep -Rnw --include='Kconfig*' \
-E '^[[:space:]]*(menu)?config[[:space:]]+NETFILTER_XTABLES_LEGACY([[:space:]]|$)' \
"$KERNEL_DIR" || echo "missing"
```
### Show which lines survive filtering
```sh
scripts/filter-kconfig-fragment.sh "$KERNEL_DIR" docker/kernel-extra.config \
| grep -E '^(CONFIG_|# CONFIG_)'
```
### Confirm the filtered fragment is non-empty
```sh
scripts/filter-kconfig-fragment.sh "$KERNEL_DIR" docker/kernel-extra.config \
> /tmp/kernel-extra.effective.config && \
test -s /tmp/kernel-extra.effective.config
```
### Validate after merge and `olddefconfig`
```sh
"$KERNEL_DIR"/scripts/kconfig/merge_config.sh -m "$KERNEL_DIR"/.config /tmp/kernel-extra.effective.config
KCONFIG_WARN_UNKNOWN_SYMBOLS=1 KCONFIG_WERROR=1 \
make -C "$KERNEL_DIR" olddefconfig
```
### Inspect config drift
```sh
make -C "$KERNEL_DIR" listnewconfig
```
The kernel docs explicitly recommend `listnewconfig` when older configs are reused against newer kernels, and they document `KCONFIG_WARN_UNKNOWN_SYMBOLS` / `KCONFIG_WERROR` for exactly the “unknown symbol in config input” problem this workflow is guarding against. citeturn5view0turn3view2
## Sources and notes
I did not find `filter-kconfig-fragment.sh` in the provided project files, so the replacement above is intentionally conservative and built around **official kernel interfaces** instead of inventing a parallel config system. The authoritative equivalents are: the kernels own `scripts/kconfig/merge_config.sh`, whose header states that it merges config fragments and warns about overridden or unresolved values; `scripts/config`, whose built-in usage documents `--enable`, `--disable`, `--module`, `--file`, and related options; the Kconfig documentation for `KCONFIG_WARN_UNKNOWN_SYMBOLS`, `KCONFIG_WERROR`, `KCONFIG_ALLCONFIG`, and `listnewconfig`; the Kconfig language docs for symbol definitions and dependency semantics; and the external-modules docs for `modules_prepare` and the `Module.symvers` caveat. The reproducible-builds kernel docs are also relevant when the surrounding Docker pipeline sets `SOURCE_DATE_EPOCH`, `KBUILD_BUILD_TIMESTAMP`, `KBUILD_BUILD_USER`, and `KBUILD_BUILD_HOST`. citeturn3view1turn3view0turn3view2turn5view0turn3view6turn3view4turn3view3