Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ LINUX_VERSION=7.0

BINUTILS_URL=https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VERSION}.tar.xz
GCC_URL=https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz
UCLIBC_NG_URL=https://downloads.uclibc-ng.org/releases/${UCLIBC_NG_VERSION}/uClibc-ng-${UCLIBC_NG_VERSION}.tar.xz
# GitHub auto-archive. The canonical mirror at downloads.uclibc-ng.org
# has been observed returning HTTP 522 (Cloudflare-to-origin failure)
# for extended windows; GitHub's tag-based source archive is permanent
# and byte-equivalent to the upstream tarball content (same 5,527-file
# tree, only the top-level directory uses lowercase 'u' which we rename
# back below to keep configs/uClibc-ng-*.config and the rest of this
# script unchanged).
UCLIBC_NG_URL=https://github.com/wbx-github/uclibc-ng/archive/refs/tags/v${UCLIBC_NG_VERSION}.tar.gz
BUSYBOX_URL=https://busybox.net/downloads/busybox-${BUSYBOX_VERSION}.tar.bz2
LINUX_URL=https://www.kernel.org/pub/linux/kernel/v7.x/linux-${LINUX_VERSION}.tar.xz

Expand Down Expand Up @@ -63,7 +70,7 @@ mkdir -p "${LOGDIR}" "${STATE_DIR}"
# To populate missing checksums: sha256sum downloads/*
CHECKSUM_binutils="binutils-${BINUTILS_VERSION}.tar.xz=d75a94f4d73e7a4086f7513e67e439e8fcdcbb726ffe63f4661744e6256b2cf2"
CHECKSUM_gcc="gcc-${GCC_VERSION}.tar.xz=438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e"
CHECKSUM_uclibc="uClibc-ng-${UCLIBC_NG_VERSION}.tar.xz=8bc734b584e23ff6ae3d0ebb4c0fb1d1d814c58c82822b93130d436afa7ace8b"
CHECKSUM_uclibc="v${UCLIBC_NG_VERSION}.tar.gz=f49704e0affc75fde9ee4e870c20e53c1d807eca2a4683377b359b8361e84312"
CHECKSUM_busybox="busybox-${BUSYBOX_VERSION}.tar.bz2=3311dff32e746499f4df0d5df04d7eb396382d7e108bb9250e7b519b837043a4"
CHECKSUM_linux="linux-${LINUX_VERSION}.tar.xz=bb7f6d80b387c757b7d14bb93028fcb90f793c5c0d367736ee815a100b3891f0"

Expand Down Expand Up @@ -410,7 +417,12 @@ build_uClibc() {
echo "BUILD: building uClibc-${UCLIBC_NG_VERSION}"
fetch_file "${UCLIBC_NG_URL}" "${CHECKSUM_uclibc}"

extract_source "uClibc-ng-${UCLIBC_NG_VERSION}.tar.xz" "uClibc-ng-${UCLIBC_NG_VERSION}" -xJf
extract_source "v${UCLIBC_NG_VERSION}.tar.gz" "uClibc-ng-${UCLIBC_NG_VERSION}" -xzf
# GitHub source archive unpacks to lowercase 'uclibc-ng-X.Y.Z'; rename
# to the canonical-tarball capitalization so configs/ and stage_clean
# references stay valid. extract_source's own "reuse" check above
# already short-circuits on subsequent runs once the rename has taken.
[ -d "uClibc-ng-${UCLIBC_NG_VERSION}" ] || mv "uclibc-ng-${UCLIBC_NG_VERSION}" "uClibc-ng-${UCLIBC_NG_VERSION}"
cp configs/uClibc-ng-${UCLIBC_NG_VERSION}-${FLAVOR}.config uClibc-ng-${UCLIBC_NG_VERSION}/.config
cd uClibc-ng-${UCLIBC_NG_VERSION}

Expand Down Expand Up @@ -654,7 +666,7 @@ build_linux() {
cd linux-${LINUX_VERSION}

# Apply linux-tiny patches for reduced memory footprint and LTO support
for p in ../patches/0002-*.patch ../patches/0003-*.patch ../patches/0004-*.patch ../patches/0005-*.patch ../patches/0006-*.patch ../patches/0010-*.patch ../patches/0011-*.patch; do
for p in ../patches/0002-*.patch ../patches/0003-*.patch ../patches/0004-*.patch ../patches/0005-*.patch ../patches/0006-*.patch ../patches/0010-*.patch ../patches/0011-*.patch ../patches/0012-*.patch ../patches/0013-*.patch; do
[ -f "${p}" ] || continue
apply_patch_once "${p}"
done
Expand Down Expand Up @@ -896,6 +908,29 @@ build_linux() {
echo "# CONFIG_STACKPROTECTOR is not set" >>.config
echo "# CONFIG_STACKPROTECTOR_STRONG is not set" >>.config

# Scheduler trim: Linux 7.0 removed CONFIG_SCHED_DEBUG and unified
# debug.c into build_utility.c. Patch 0012 reintroduces a knob
# (SCHED_DEBUG_OUTPUT, default y) that wraps debug.c body in #ifdef
# and provides empty stubs for the externally-called symbols.
# /proc/<pid>/sched returns empty seq_file; OOPS sched_show_task
# path is unaffected (defined in core.c). Measured: -4,278 bytes /
# 16 symbols on the production vmlinux .text.
echo "# CONFIG_SCHED_DEBUG_OUTPUT is not set" >>.config

# Patch 0013 mirrors 0012 for deadline.c: SCHED_DEADLINE_CLASS
# default y; set n to wrap deadline.c body in #ifdef and substitute
# a stub class (DEFINE_SCHED_CLASS(dl) with pick_task=NULL_returner,
# all other callbacks NULL). __checkparam_dl returns false so
# sched_setattr with policy=6 is rejected with -EPERM and no task
# ever joins SCHED_DEADLINE. Any later attempt to program a DL
# server is rejected with -EOPNOTSUPP, so the scheduler must also
# keep the cgroup-bandwidth/group-sched knobs below disabled.
# Measured: -10,530 bytes / 81 symbols.
echo "# CONFIG_SCHED_DEADLINE_CLASS is not set" >>.config
echo "# CONFIG_PSI is not set" >>.config
echo "# CONFIG_CGROUPS is not set" >>.config
echo "# CONFIG_SCHED_AUTOGROUP is not set" >>.config

run_logged "olddefconfig" kernel_make olddefconfig

# Verify critical config options survived olddefconfig resolution.
Expand Down Expand Up @@ -953,7 +988,12 @@ build_linux() {
"# CONFIG_DEBUG_BUGVERBOSE is not set" \
"# CONFIG_RD_ZSTD is not set" \
"# CONFIG_RD_LZ4 is not set" \
"# CONFIG_RD_XZ is not set"; do
"# CONFIG_RD_XZ is not set" \
"# CONFIG_SCHED_DEBUG_OUTPUT is not set" \
"# CONFIG_SCHED_DEADLINE_CLASS is not set" \
"# CONFIG_PSI is not set" \
"# CONFIG_CGROUPS is not set" \
"# CONFIG_SCHED_AUTOGROUP is not set"; do
if ! grep -q "^${opt}\$" .config; then
echo "ERROR: expected '${opt}' in .config after olddefconfig"
exit 1
Expand Down Expand Up @@ -1003,9 +1043,13 @@ build_linux() {
# STACKPROTECTOR_STRONG -- depends on STACKPROTECTOR=y
# LOGO/A11Y_BRAILLE_CONSOLE -- depend on the VT stack
# DEVTMPFS_MOUNT -- depends on DEVTMPFS=y
# CGROUP_SCHED/*_GROUP_SCHED/CFS_BANDWIDTH -- depend on CGROUPS=y
for sym in SHMEM AUDIT POSIX_MQUEUE SECURITY TASKSTATS PCI \
STACKPROTECTOR_STRONG LOGO A11Y_BRAILLE_CONSOLE \
DEVTMPFS_MOUNT; do
DEVTMPFS_MOUNT \
CGROUP_SCHED FAIR_GROUP_SCHED CFS_BANDWIDTH RT_GROUP_SCHED \
SCHED_CORE NUMA_BALANCING UCLAMP_TASK \
SCHED_THERMAL_PRESSURE SCHEDSTATS; do
if grep -q "^CONFIG_${sym}=y\$" .config; then
echo "ERROR: CONFIG_${sym}=y survived olddefconfig (subsystem disable broken?)"
exit 1
Expand Down
101 changes: 101 additions & 0 deletions patches/0012-tiny-sched-no-debug-output.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
From: Jim Huang <jserv@ccns.ncku.edu.tw>
Subject: [PATCH] tiny: sched: gate debug.c behind CONFIG_SCHED_DEBUG_OUTPUT

Linux 7.0 removed the historical CONFIG_SCHED_DEBUG gate; debug.c is now
unconditionally included via build_utility.c. On a NOMMU image with no
userspace reader of /proc/<pid>/sched, no debugfs sched-domain consumer,
and no sysrq input device, the file is ~4KB of dead .text and .rodata.

Re-introduce a knob without resurrecting the old name (which other code
still references in deprecation comments). CONFIG_SCHED_DEBUG_OUTPUT
defaults to y so mainline behavior is preserved; setting it to n wraps
the body of debug.c in #ifdef and provides empty stubs for the
externally-called symbols that lack existing header stubs:

sched_debug_verbose -- topology.c reads this flag
sysrq_sched_debug_show -- core.c show_state_filter
resched_latency_warn -- core.c sched_tick latency check
print_cfs_rq / print_rt_rq -- print_*_stats bodies in fair.c, rt.c
print_dl_rq -- print_dl_stats body in deadline.c
print_numa_stats -- print_cfs_stats body in fair.c
(only when CONFIG_NUMA_BALANCING)
proc_sched_show_task -- fs/proc/base.c /proc/<pid>/sched read
proc_sched_set_task -- fs/proc/base.c /proc/<pid>/sched write
update_sched_domain_debugfs -- topology.c sched-domain rebuild path
dirty_sched_domain_sysctl -- topology.c sched-domain sysctl path

OOPS/panic backtraces are unaffected because sched_show_task and
dump_cpu_task live in core.c, not debug.c. /proc/<pid>/sched returns an
empty seq_file when read. Boot-path callers silently no-op.

Measured on Cortex-M4 nommu mps2-an386 (linux-7.0): SCHED_DEBUG_OUTPUT=n
drops 4,278 bytes / 16 symbols from .text per nm --size-sort against the
production vmlinux.

---
init/Kconfig | 14 ++++++++++++++
kernel/sched/debug.c | 22 ++++++++++++++++++++++
2 files changed, 36 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -932,6 +932,20 @@ config SCHED_PROXY_EXEC
This option enables proxy execution, a mechanism for mutex-owning
tasks to inherit the scheduling context of higher priority waiters.

+config SCHED_DEBUG_OUTPUT
+ bool "Scheduler debug/output paths"
+ default y
+ help
+ Build kernel/sched/debug.c, which provides /proc/<pid>/sched,
+ /sys/kernel/debug/sched/* (when DEBUG_FS=y), the sysrq scheduler
+ dump, and the print_cfs_rq / print_rt_rq / print_dl_rq /
+ print_numa_stats formatters.
+
+ Say N on size-constrained NOMMU images that never read
+ /proc/<pid>/sched and have no debugfs sched-domain consumer.
+ Boot-path callers become no-ops; OOPS/panic backtraces are
+ unaffected (sched_show_task lives in core.c).
+
endmenu

#
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -9,6 +9,8 @@
#include <linux/debugfs.h>
#include <linux/nmi.h>
#include "sched.h"
+
+#ifdef CONFIG_SCHED_DEBUG_OUTPUT

/*
* This allows printing both to /sys/kernel/debug/sched/debug and
@@ -1388,3 +1390,25 @@ void resched_latency_warn(int cpu, u64 latency)
cpu, latency, cpu_rq(cpu)->ticks_without_resched);
dump_stack();
}
+
+#else /* !CONFIG_SCHED_DEBUG_OUTPUT */
+
+__read_mostly bool sched_debug_verbose;
+
+void sysrq_sched_debug_show(void) { }
+void resched_latency_warn(int cpu, u64 latency) { }
+void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) { }
+void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) { }
+void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq) { }
+#ifdef CONFIG_NUMA_BALANCING
+void print_numa_stats(struct seq_file *m, int node, unsigned long tsf,
+ unsigned long tpf, unsigned long gsf, unsigned long gpf)
+{ }
+#endif
+void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
+ struct seq_file *m) { }
+void proc_sched_set_task(struct task_struct *p) { }
+void update_sched_domain_debugfs(void) { }
+void dirty_sched_domain_sysctl(int cpu) { }
+
+#endif /* CONFIG_SCHED_DEBUG_OUTPUT */
159 changes: 159 additions & 0 deletions patches/0013-tiny-sched-no-deadline-class.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
From: Jim Huang <jserv@ccns.ncku.edu.tw>
Subject: [PATCH] tiny: sched: gate deadline.c behind CONFIG_SCHED_DEADLINE_CLASS

Linux 7.0 deleted the historical CONFIG_SCHED_DEADLINE gate; deadline.c
is now unconditionally included via build_policy.c. On a NOMMU image
that never sets SCHED_DEADLINE policy (BusyBox CHRT applet is off, no
init script issues sched_setattr with policy=6), the file is ~10.5KB of
dead .text plus its DL bandwidth/server bookkeeping.

Re-introduce a knob without resurrecting the old name.
CONFIG_SCHED_DEADLINE_CLASS defaults to y so mainline behavior is
preserved; setting it to n wraps the body of deadline.c in #ifdef and
provides a minimal stub class plus stubs for every externally-called
helper. The stub class is registered via DEFINE_SCHED_CLASS(dl) so it
lands in the __dl_sched_class linker section between stop and rt --
core.c::sched_class_above() BUG_ON checks at sched_init pass. Only
.pick_task is implemented (returns NULL); all other callbacks remain
NULL because they fire only for tasks already in the class, and
__checkparam_dl() rejects every attribute set so no task can ever join.

External-API stubs match include/linux/sched/deadline.h and
kernel/sched/sched.h declarations:

Class chain:
dl_sched_class -- empty class with pick_task=NULL
Init paths (called from core.c, fair.c, topology.c):
init_dl_bw / init_dl_rq / init_dl_entity
init_sched_dl_class / sched_init_dl_servers
Sysctl/global validation (called from rt.c sysctl handler):
sched_dl_global_validate / sched_dl_do_global
Syscall path (sched_setattr / sched_getattr):
sched_dl_overflow -- returns -EPERM, blocks DL admission
__checkparam_dl -- returns false, blocks DL attribute sets
__setparam_dl / __getparam_dl / dl_param_changed
CPU hotplug / cpuset:
dl_cpuset_cpumask_can_shrink -- cpuset shrink validation
DL server (used by fair.c to back SCHED_OTHER bandwidth):
dl_server_init / _start / _stop / _update / _update_idle
__dl_server_attach_root / dl_server_apply_params
Bandwidth scaling helper:
dl_scaled_delta_exec -- returns delta_exec unchanged
Globals visible to topology.c / cgroup code:
dl_cookie / dl_bw_visited
Bandwidth-management helpers used by core.c / cpuset:
dl_bw_deactivate / dl_bw_alloc / dl_bw_free

The DL-server feature backs CFS bandwidth via a deadline entity per
runqueue. When the class is disabled, any attempt to program a DL
server fails with -EOPNOTSUPP instead of pretending to succeed; the
build disables the scheduler cgroup bandwidth knobs accordingly.

Measured on Cortex-M4 nommu mps2-an386 (linux-7.0): SCHED_DEADLINE_CLASS=n
drops 10,530 bytes / 81 symbols from .text per nm --size-sort.

---
init/Kconfig | 13 +++++++++
kernel/sched/deadline.c | 60 ++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -933,6 +933,19 @@ config SCHED_PROXY_EXEC
This option enables proxy execution, a mechanism for mutex-owning
tasks to inherit the scheduling context of higher priority waiters.

+config SCHED_DEADLINE_CLASS
+ bool "SCHED_DEADLINE earliest-deadline-first scheduling class"
+ default y
+ help
+ Build kernel/sched/deadline.c, which implements the SCHED_DEADLINE
+ policy (EDF + Constant Bandwidth Server) and the deadline-server
+ bandwidth backing for SCHED_OTHER.
+
+ Say N on size-constrained NOMMU images that never set SCHED_DEADLINE
+ policy and need every byte back. __checkparam_dl rejects all DL
+ attribute sets; sched_setattr with policy=6 returns -EPERM. Any
+ later attempt to program a DL server fails with -EOPNOTSUPP.
+
endmenu

#
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -20,6 +20,8 @@
#include <uapi/linux/sched/types.h>
#include "sched.h"
#include "pelt.h"
+
+#ifdef CONFIG_SCHED_DEADLINE_CLASS

/*
* Default limits for DL period; on the top end we guard against small util
@@ -3841,3 +3843,64 @@ void print_dl_stats(struct seq_file *m, int cpu)
{
print_dl_rq(m, cpu, &cpu_rq(cpu)->dl);
}
+
+#else /* !CONFIG_SCHED_DEADLINE_CLASS */
+
+#include <linux/sched/deadline.h>
+
+/*
+ * Stub deadline scheduling class. No task ever joins SCHED_DEADLINE
+ * because __checkparam_dl rejects every attribute set, so all callbacks
+ * except pick_task are unreachable and remain NULL. pick_task is the
+ * one method the chain walk in pick_next_task_balance / pick_next_task
+ * invokes unconditionally per class; returning NULL forwards control to
+ * the next class (rt -> fair -> idle).
+ */
+
+static struct task_struct *pick_task_dl_stub(struct rq *rq, struct rq_flags *rf)
+{
+ return NULL;
+}
+
+DEFINE_SCHED_CLASS(dl) = {
+ .pick_task = pick_task_dl_stub,
+};
+
+u64 dl_cookie;
+
+bool dl_bw_visited(int cpu, u64 cookie) { return false; }
+int dl_bw_deactivate(int cpu) { return 0; }
+int dl_bw_alloc(int cpu, u64 dl_bw) { return 0; }
+void dl_bw_free(int cpu, u64 dl_bw) { }
+
+void init_dl_bw(struct dl_bw *dl_b) { }
+void init_dl_rq(struct dl_rq *dl_rq) { }
+void init_dl_entity(struct sched_dl_entity *dl_se) { }
+void __init init_sched_dl_class(void) { }
+void sched_init_dl_servers(void) { }
+
+int sched_dl_global_validate(void) { return 0; }
+void sched_dl_do_global(void) { }
+int sched_dl_overflow(struct task_struct *p, int policy,
+ const struct sched_attr *attr) { return -EPERM; }
+void __setparam_dl(struct task_struct *p, const struct sched_attr *attr) { }
+void __getparam_dl(struct task_struct *p, struct sched_attr *attr) { }
+bool __checkparam_dl(const struct sched_attr *attr) { return false; }
+bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr)
+{ return false; }
+int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur,
+ const struct cpumask *trial) { return 1; }
+s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se,
+ s64 delta_exec) { return delta_exec; }
+
+void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
+ dl_server_pick_f pick_task) { }
+void dl_server_start(struct sched_dl_entity *dl_se) { }
+void dl_server_stop(struct sched_dl_entity *dl_se) { }
+void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec) { }
+void dl_server_update_idle(struct sched_dl_entity *dl_se, s64 delta_exec) { }
+void __dl_server_attach_root(struct sched_dl_entity *dl_se, struct rq *rq) { }
+int dl_server_apply_params(struct sched_dl_entity *dl_se, u64 runtime,
+ u64 period, bool init) { return -EOPNOTSUPP; }
+
+#endif /* CONFIG_SCHED_DEADLINE_CLASS */
Loading