diff options
Diffstat (limited to 'init')
| -rw-r--r-- | init/Kconfig | 52 | ||||
| -rw-r--r-- | init/calibrate.c | 19 | ||||
| -rw-r--r-- | init/init_task.c | 1 | ||||
| -rw-r--r-- | init/initramfs.c | 16 | ||||
| -rw-r--r-- | init/initramfs_test.c | 21 | ||||
| -rw-r--r-- | init/main.c | 89 |
6 files changed, 139 insertions, 59 deletions
diff --git a/init/Kconfig b/init/Kconfig index 10f2013b5321..8583d9f06c52 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -565,6 +565,7 @@ config VIRT_CPU_ACCOUNTING choice prompt "Cputime accounting" + default VIRT_CPU_ACCOUNTING_GEN if NO_HZ_FULL default TICK_CPU_ACCOUNTING # Kind of a stub config for the pure tick based cputime accounting @@ -948,6 +949,13 @@ config SCHED_PROXY_EXEC endmenu # +# For architectures that support present-but-inaccessible (PROT_NONE) page +# table entries detectable via pte_protnone() / pmd_protnone(): +# +config ARCH_HAS_PTE_PROTNONE + bool + +# # For architectures that want to enable the support for NUMA-affine scheduler # balancing logic: # @@ -1013,6 +1021,7 @@ config ARCH_WANT_NUMA_VARIABLE_LOCALITY config NUMA_BALANCING bool "Memory placement aware NUMA scheduler" depends on ARCH_SUPPORTS_NUMA_BALANCING + depends on ARCH_HAS_PTE_PROTNONE depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY depends on SMP && NUMA_MIGRATION && !PREEMPT_RT help @@ -1569,6 +1578,42 @@ config BOOT_CONFIG_EMBED_FILE This bootconfig will be used if there is no initrd or no other bootconfig in the initrd. +config ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG + bool + help + Silent symbol; no C code reads it directly. Architectures + select it once their setup_arch() calls + xbc_prepend_embedded_cmdline() before parse_early_param(). + Its only role is to gate the user-visible + CMDLINE_FROM_BOOTCONFIG option per-arch, the same + ARCH_SUPPORTS_* idiom used by ARCH_SUPPORTS_CFI, etc. + +config CMDLINE_FROM_BOOTCONFIG + bool "Render embedded bootconfig as kernel cmdline at build time" + depends on BOOT_CONFIG_EMBED_FILE != "" + depends on ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG + depends on CMDLINE = "" + default n + help + Render the "kernel" subtree of the embedded bootconfig file into a + flat cmdline string at kernel build time and prepend it to + boot_command_line during early architecture setup. This makes + early_param() handlers (e.g. mem=, earlycon=, loglevel=) see the + values supplied via the embedded bootconfig. + + The runtime bootconfig parser is unaffected, so tree-structured + consumers such as ftrace boot-time tracing keep working. + + Note: when an initrd also carries a bootconfig, its "kernel" + subtree is still parsed at runtime, but the embedded "kernel" + keys remain in boot_command_line for parse_early_param() and + end up later than the initrd keys in saved_command_line, so + parse_args() last-wins favors the embedded values. If you need + initrd to override embedded kernel.* keys, leave this option + off. + + If unsure, say N. + config CMDLINE_LOG_WRAP_IDEAL_LEN int "Length to try to wrap the cmdline when logged at boot" default 1021 @@ -1664,9 +1709,6 @@ config LD_ORPHAN_WARN_LEVEL default "error" if WERROR default "warn" -config SYSCTL - bool - config HAVE_UID16 bool @@ -1860,7 +1902,7 @@ config HAVE_FUTEX_ROBUST_UNLOCK bool config FUTEX_ROBUST_UNLOCK - def_bool FUTEX && HAVE_GENERIC_VDSO && GENERIC_IRQ_ENTRY && RSEQ && HAVE_FUTEX_ROBUST_UNLOCK + def_bool FUTEX && GENERIC_IRQ_ENTRY && RSEQ && HAVE_FUTEX_ROBUST_UNLOCK config EPOLL bool "Enable eventpoll support" if EXPERT @@ -2115,7 +2157,7 @@ config ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS from a kernel perspective. After the architecture enables this, a distribution can set - CONFIG_MSEAL_SYSTEM_MAPPING to manage access to the feature. + CONFIG_MSEAL_SYSTEM_MAPPINGS to manage access to the feature. For complete descriptions of memory sealing, please see Documentation/userspace-api/mseal.rst diff --git a/init/calibrate.c b/init/calibrate.c index 63be4c65bc52..2bfe97034e42 100644 --- a/init/calibrate.c +++ b/init/calibrate.c @@ -13,7 +13,6 @@ #include <linux/printk.h> #include <linux/smp.h> #include <linux/stddef.h> -#include <linux/timex.h> unsigned long lpj_fine; unsigned long preset_lpj; @@ -25,9 +24,9 @@ static int __init lpj_setup(char *str) __setup("lpj=", lpj_setup); -#ifdef ARCH_HAS_READ_CURRENT_TIMER +#ifdef CONFIG_ARCH_HAS_DELAY_TIMER -/* This routine uses the read_current_timer() routine and gets the +/* This routine uses the delay_read_timer() routine and gets the * loops per jiffy directly, instead of guessing it using delay(). * Also, this code tries to handle non-maskable asynchronous events * (like SMIs) @@ -48,13 +47,13 @@ static unsigned long calibrate_delay_direct(void) int min = -1; int i; - if (read_current_timer(&pre_start) < 0 ) + if (!delay_read_timer(&pre_start)) return 0; /* * A simple loop like * while ( jiffies < start_jiffies+1) - * start = read_current_timer(); + * start = delay_read_timer(); * will not do. As we don't really know whether jiffy switch * happened first or timer_value was read first. And some asynchronous * event can happen between these two events introducing errors in lpj. @@ -72,22 +71,22 @@ static unsigned long calibrate_delay_direct(void) for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { pre_start = 0; - read_current_timer(&start); + delay_read_timer(&start); start_jiffies = jiffies; while (time_before_eq(jiffies, start_jiffies + 1)) { pre_start = start; - read_current_timer(&start); + delay_read_timer(&start); } - read_current_timer(&post_start); + delay_read_timer(&post_start); pre_end = 0; end = post_start; while (time_before_eq(jiffies, start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) { pre_end = end; - read_current_timer(&end); + delay_read_timer(&end); } - read_current_timer(&post_end); + delay_read_timer(&post_end); timer_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS; diff --git a/init/init_task.c b/init/init_task.c index 5c7ad50ac685..adb207cd987c 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -163,6 +163,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = { RCU_POINTER_INITIALIZER(cred, &init_cred), .comm = INIT_TASK_COMM, .thread = INIT_THREAD, + .real_fs = &init_fs, .fs = &init_fs, .files = &init_files, #ifdef CONFIG_IO_URING diff --git a/init/initramfs.c b/init/initramfs.c index 20a18fcda48e..3cee8b50ad82 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -6,6 +6,7 @@ #include <linux/fcntl.h> #include <linux/file.h> #include <linux/fs.h> +#include <linux/fs_struct.h> #include <linux/hex.h> #include <linux/init.h> #include <linux/init_syscalls.h> @@ -618,7 +619,7 @@ void __init reserve_initrd_mem(void) phys_addr_t start; unsigned long size; - /* Ignore the virtul address computed during device tree parsing */ + /* Ignore the virtual address computed during device tree parsing */ initrd_start = initrd_end = 0; if (!phys_initrd_size) @@ -716,7 +717,7 @@ static void __init populate_initrd_image(char *err) } #endif /* CONFIG_BLK_DEV_RAM */ -static void __init do_populate_rootfs(void *unused, async_cookie_t cookie) +static void __init unpack_initramfs(async_cookie_t cookie) { /* Load the built in initramfs */ char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size); @@ -724,7 +725,7 @@ static void __init do_populate_rootfs(void *unused, async_cookie_t cookie) panic_show_mem("%s", err); /* Failed to decompress INTERNAL initramfs */ if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE)) - goto done; + return; if (IS_ENABLED(CONFIG_BLK_DEV_RAM)) printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n"); @@ -739,9 +740,14 @@ static void __init do_populate_rootfs(void *unused, async_cookie_t cookie) printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err); #endif } +} -done: - security_initramfs_populated(); +static void __init do_populate_rootfs(void *unused, async_cookie_t cookie) +{ + scoped_with_init_fs() { + unpack_initramfs(cookie); + security_initramfs_populated(); + } /* * If the initrd region is overlapped with crashkernel reserved region, diff --git a/init/initramfs_test.c b/init/initramfs_test.c index bc55306d226d..1154547721ea 100644 --- a/init/initramfs_test.c +++ b/init/initramfs_test.c @@ -3,6 +3,7 @@ #include <linux/fcntl.h> #include <linux/file.h> #include <linux/fs.h> +#include <linux/fs_struct.h> #include <linux/init.h> #include <linux/init_syscalls.h> #include <linux/initrd.h> @@ -513,7 +514,7 @@ static void __init initramfs_test_hdr_hex(struct kunit *test) char fdata[] = "this file data will not be unpacked"; struct initramfs_test_bufs { char cpio_src[(CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)) * 2]; - } *tbufs = kzalloc(sizeof(struct initramfs_test_bufs), GFP_KERNEL); + } *tbufs = kzalloc_obj(struct initramfs_test_bufs); struct initramfs_test_cpio c[] = { { .magic = "070701", .ino = 1, @@ -562,7 +563,7 @@ static struct kunit_case __refdata initramfs_test_cases[] = { {}, }; -static int __init initramfs_test_init(struct kunit_suite *suite) +static int __init initramfs_suite_init(struct kunit_suite *suite) { /* * unpack_to_rootfs() uses module-static state (victim, byte_count, @@ -574,9 +575,23 @@ static int __init initramfs_test_init(struct kunit_suite *suite) return 0; } +/* Tests run in a nullfs kthread; always use the init fs for path resolution. */ +static int __init initramfs_test_init(struct kunit *test) +{ + test->priv = __override_init_fs(); + return 0; +} + +static void __init initramfs_test_exit(struct kunit *test) +{ + __revert_init_fs(test->priv); +} + static struct kunit_suite __refdata initramfs_test_suite = { .name = "initramfs", - .suite_init = initramfs_test_init, + .suite_init = initramfs_suite_init, + .init = initramfs_test_init, + .exit = initramfs_test_exit, .test_cases = initramfs_test_cases, }; kunit_test_init_section_suites(&initramfs_test_suite); diff --git a/init/main.c b/init/main.c index e363232b428b..31f2bf54976a 100644 --- a/init/main.c +++ b/init/main.c @@ -103,6 +103,7 @@ #include <linux/stackdepot.h> #include <linux/randomize_kstack.h> #include <linux/pidfs.h> +#include <linux/fs_struct.h> #include <linux/ptdump.h> #include <linux/time_namespace.h> #include <linux/unaligned.h> @@ -276,7 +277,8 @@ static void * __init get_boot_config_from_initrd(size_t *_size) u8 *hdr; int i; - if (!initrd_end) + if (!initrd_end || initrd_end < initrd_start || + initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8) return NULL; data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN; @@ -293,16 +295,26 @@ static void * __init get_boot_config_from_initrd(size_t *_size) found: hdr = (u8 *)(data - 8); + if ((unsigned long)hdr < initrd_start) + return NULL; + size = get_unaligned_le32(hdr); csum = get_unaligned_le32(hdr + 4); - data = ((void *)hdr) - size; - if ((unsigned long)data < initrd_start) { - pr_err("bootconfig size %d is greater than initrd size %ld\n", + if (size > XBC_DATA_MAX) { + pr_err("bootconfig size %u is greater than max size %d\n", + size, XBC_DATA_MAX); + return NULL; + } + + if (size > ((unsigned long)hdr - initrd_start)) { + pr_err("bootconfig size %u is greater than initrd size %lu\n", size, initrd_end - initrd_start); return NULL; } + data = ((void *)hdr) - size; + if (xbc_calc_checksum(data, size) != csum) { pr_err("bootconfig checksum failed\n"); return NULL; @@ -356,45 +368,33 @@ static char * __init xbc_make_cmdline(const char *key) return new_cmdline; } -static int __init bootconfig_params(char *param, char *val, - const char *unused, void *arg) -{ - if (strcmp(param, "bootconfig") == 0) { - bootconfig_found = true; - } - return 0; -} - static int __init warn_bootconfig(char *str) { - /* The 'bootconfig' has been handled by bootconfig_params(). */ + /* The 'bootconfig' option is handled by setup_boot_config(). */ return 0; } static void __init setup_boot_config(void) { - static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; const char *msg, *data; - int pos, ret; + int pos, ret, offs; size_t size; - char *err; + bool from_embedded = false; /* Cut out the bootconfig data even if we have no bootconfig option */ data = get_boot_config_from_initrd(&size); /* If there is no bootconfig in initrd, try embedded one. */ - if (!data) + if (!data) { data = xbc_get_embedded_bootconfig(&size); + from_embedded = true; + } - strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); - err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL, - bootconfig_params); - - if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) + bootconfig_found = bootconfig_cmdline_requested(boot_command_line, &offs); + if (!(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) return; - /* parse_args() stops at the next param of '--' and returns an address */ - if (err) - initargs_offs = err - tmp_cmdline; + /* Offset of the init arguments after a "--", located by the helper. */ + initargs_offs = offs; if (!data) { /* If user intended to use bootconfig, show an error level message */ @@ -405,12 +405,6 @@ static void __init setup_boot_config(void) return; } - if (size >= XBC_DATA_MAX) { - pr_err("bootconfig size %ld greater than max size %d\n", - (long)size, XBC_DATA_MAX); - return; - } - ret = xbc_init(data, size, &msg, &pos); if (ret < 0) { if (pos < 0) @@ -421,8 +415,24 @@ static void __init setup_boot_config(void) } else { xbc_get_info(&ret, NULL); pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret); - /* keys starting with "kernel." are passed via cmdline */ - extra_command_line = xbc_make_cmdline("kernel"); + /* + * keys starting with "kernel." are passed via cmdline. When + * this bootconfig came from the embedded source and + * setup_arch() already prepended the rendered "kernel" subtree + * to boot_command_line, rendering again here would duplicate + * the keys in saved_command_line and make accumulating handlers + * (console=, earlycon=, ...) re-register the same value. Skip + * only when the prepend really happened. + * + * On arches that do not select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG, + * CONFIG_CMDLINE_FROM_BOOTCONFIG is unselectable and + * xbc_embedded_cmdline_applied() collapses to a stub returning + * false, so this path still runs and the embedded "kernel" + * keys reach the cmdline via the runtime parser exactly as + * before this series. + */ + if (!from_embedded || !xbc_embedded_cmdline_applied()) + extra_command_line = xbc_make_cmdline("kernel"); /* Also, "init." keys are init arguments */ extra_init_args = xbc_make_cmdline("init"); } @@ -670,6 +680,11 @@ static __initdata DECLARE_COMPLETION(kthreadd_done); static noinline void __ref __noreturn rest_init(void) { + struct kernel_clone_args init_args = { + .flags = (CLONE_VM | CLONE_UNTRACED), + .fn = kernel_init, + .fn_arg = NULL, + }; struct task_struct *tsk; int pid; @@ -679,7 +694,7 @@ static noinline void __ref __noreturn rest_init(void) * the init task will end up wanting to create kthreads, which, if * we schedule it before we create kthreadd, will OOPS. */ - pid = user_mode_thread(kernel_init, NULL, CLONE_FS); + pid = kernel_clone(&init_args); /* * Pin init on the boot CPU. Task migration is not properly working * until sched_init_smp() has been run. It will set the allowed @@ -1540,6 +1555,8 @@ static int __ref kernel_init(void *unused) { int ret; + init_userspace_fs(); + /* * Wait until kthreadd is all set-up. */ @@ -1636,7 +1653,7 @@ static noinline void __init kernel_init_freeable(void) */ set_mems_allowed(node_states[N_MEMORY]); - cad_pid = get_pid(task_pid(current)); + rcu_assign_pointer(cad_pid, get_pid(task_pid(current))); smp_prepare_cpus(setup_max_cpus); |
