Message ID | cover.1687344643.git.falcon@tinylab.org (mailing list archive) |
---|---|
Headers | show |
Series | selftests/nolibc: allow run with minimal kernel config | expand |
Hi Zhangjin, some general comments for the whole series. On 2023-06-21 20:52:30+0800, Zhangjin Wu wrote: > Hi, Willy > > This patchset mainly allows speed up the nolibc test with a minimal > kernel config. > > As the nolibc supported architectures become more and more, the 'run' > test with DEFCONFIG may cost several hours, which is not friendly to > develop testing and even for release testing, so, smaller kernel configs > may be required, and firstly, we should let nolibc-test work with less > kernel config options, this patchset aims to this goal. > > This patchset mainly remove the dependency from procfs, tmpfs, net and > memfd_create, many failures have been fixed up. > > When CONFIG_TMPFS and CONFIG_SHMEM are disabled, kernel will provide a > ramfs based tmpfs (mm/shmem.c), it will be used as a choice to fix up > some failures and also allow skip less tests. Did you look into how much this duplicates from the kernels already existing "tinyconfig" and "kvm_guest.config" functionality? And it would be interesting how much impact the enablement of procfs, tmpfs, net and memfd_create has in constrast to the minimal configuration. It seems unfortunate to me to complicate the testsuite to handle such uncommon scenarios. > Besides, it also adds musl support, improves glibc support and fixes up > a kernel cmdline passing use case. > > This is based on the dev.2023.06.14a branch of linux-rcu [1], all of the > supported architectures are tested (with local minimal configs, [5] > pasted the one for i386) without failures: > > arch/board | result > ------------|------------ > arm/vexpress-a9 | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/arm-vexpress-a9-nolibc-test.log > aarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/aarch64-virt-nolibc-test.log > ppc/g3beige | not supported > i386/pc | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/i386-pc-nolibc-test.log > x86_64/pc | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/x86_64-pc-nolibc-test.log > mipsel/malta | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/mipsel-malta-nolibc-test.log > loongarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/loongarch64-virt-nolibc-test.log > riscv64/virt | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log > riscv32/virt | no test log found > s390x/s390-ccw-virtio | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/s390x-s390-ccw-virtio-nolibc-test.log > > Notes: > * The skipped ones are -fstackprotector, chmod_self and chown_self > > The -fstackprotector skip is due to gcc version. > chmod_self and chmod_self skips are due to procfs not enabled > > * ppc/g3beige support is added locally, but not added in this patchset > > will send ppc support as a new patchset, it depends on v2 test > report patchset [3] and the v5 rv32 support, require changes on > Makefile > > * riscv32/virt support is still in review, see v5 rv32 support [4] > > This patchset doesn't depends on any of my other nolibc patch series, > but the new rmdir() routine added in this patchset may be requird to > apply the __sysret() from our v4 syscall helper series [2] after that > series being merged, currently, we use the old method to let it compile > without any dependency. > > Here explains all of the patches: > > * selftests/nolibc: stat_fault: silence NULL argument warning with glibc > selftests/nolibc: gettid: restore for glibc and musl > selftests/nolibc: add _LARGEFILE64_SOURCE for musl > > The above 3 patches adds musl compile support and improve glibc support. > > It is able to build and run nolibc-test with musl libc now, but there > are some failures/skips due to the musl its own issues/requirements: > > $ sudo ./nolibc-test | grep -E 'FAIL|SKIP' > 8 sbrk = 1 ENOMEM [FAIL] > 9 brk = -1 ENOMEM [FAIL] > 46 limit_int_fast16_min = -2147483648 [FAIL] > 47 limit_int_fast16_max = 2147483647 [FAIL] > 49 limit_int_fast32_min = -2147483648 [FAIL] > 50 limit_int_fast32_max = 2147483647 [FAIL] > 0 -fstackprotector not supported [SKIPPED] > > musl disabled sbrk and brk for some conflicts with its malloc and the > fast version of int types are defined in 32bit, which differs from nolibc > and glibc. musl reserved the sbrk(0) to allow get current brk, we > added a test for this in the v4 __sysret() helper series [2]. We could add new macros #define UINT_MAX(t) (~(t)0) #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) to get whatever is appropriate for the respective type. > > * selftests/nolibc: fix up kernel parameters support > > kernel cmdline allows pass two types of parameters, one is without > '=', another is with '=', the first one is passed as init arguments, > the sencond one is passed as init environment variables. > > Our nolibc-test prefer arguments to environment variables, this not > work when users add such parameters in the kernel cmdline: > > noapic NOLIBC_TEST=syscall > > So, this patch will verify the setting from arguments at first, if it > is no valid, will try the environment variables instead. This would be much simpler as: test = getenv("NOLIBC_TEST"); if (!test) test = argv[1]; It changes the semantics a bit, but it doesn't seem to be an issue. (Maybe gated behind getpid() == 1). > * selftests/nolibc: stat_timestamps: remove procfs dependency > > Use '/' instead of /proc/self, or we can add a 'has_proc' condition > for this test case, but it is not that necessary to skip the whole > stat_timestamps tests for such a subtest binding to /proc/self. > > Welcome suggestion from Thomas. As above, I think the impact of depending on CONFIG_PROC_FS is justifiable. The usage of /proc/self was actually intentional. This file has a timestamp of the start of the referenced process. So each invocation of nolibc-test tests a new timestamp. In contrast if nolibc-test is invocated from a prebaked filesystem the timestamp of "/" will always be fixed, reducing the chance to find errors. > * tools/nolibc: add rmdir() support > selftests/nolibc: add a new rmdir() test case > > rmdir() routine and test case are added for the coming requirement. > > Note, if the __sysret() patchset [2] is applied before us, this patch > should be rebased on it and apply the __sysret() helper. > > * selftests/nolibc: fix up failures when there is no procfs > > call rmdir() to remove /proc completely to rework the checking of > /proc, before, the existing of /proc not means the procfs is really > mounted. > > * selftests/nolibc: rename proc variable to has_proc > selftests/nolibc: rename euid0 variable to is_root > > align with the has_gettid, has_xxx variables. > > * selftests/nolibc: prepare tmpfs and hugetlbfs > selftests/nolibc: rename chmod_net to chmod_good > selftests/nolibc: link_cross: support tmpfs > selftests/nolibc: rename chroot_exe to chroot_file > > use file from /tmp instead of file from /proc when there is no procfs > this avoid skipping the chmod_net, link_cross, chroot_exe tests > > * selftests/nolibc: vfprintf: silence memfd_create() warning > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > memfd_create from kernel >= v6.2 forcely warn on missing > MFD_NOEXEC_SEAL flag, the first one silence it with such flag, for > older kernels, use 0 flag as before. Given this is only a problem when nolibc-test is PID1 and printing to the system console, we could also just disable warnings on the system console through syscall() or /proc/sys/kernel/printk. It would also avoid cluttering the tests for limited gain. > since memfd_create() depends on TMPFS or HUGETLBFS, the second one > skip the whole vfprintf instead of simply fail if memfd_create() not > work. > > the 3rd one futher try the ramfs based tmpfs even when memfd_create() > not work. > > At last, let's simply discuss about the configs, I have prepared minimal > configs for all of the nolibc supported architectures but not sure where > should we put them, what about tools/testing/selftests/nolibc/configs ? > > Thanks! > > Best regards, > Zhangjin > --- > > [1]: https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/ > [2]: https://lore.kernel.org/linux-riscv/cover.1687187451.git.falcon@tinylab.org/ > [3]: https://lore.kernel.org/lkml/cover.1687156559.git.falcon@tinylab.org/ > [4]: https://lore.kernel.org/linux-riscv/cover.1687176996.git.falcon@tinylab.org/ > [5]: https://pastebin.com/5jq0Vxbz > > Zhangjin Wu (17): > selftests/nolibc: stat_fault: silence NULL argument warning with glibc > selftests/nolibc: gettid: restore for glibc and musl > selftests/nolibc: add _LARGEFILE64_SOURCE for musl > selftests/nolibc: fix up kernel parameters support > selftests/nolibc: stat_timestamps: remove procfs dependency > tools/nolibc: add rmdir() support > selftests/nolibc: add a new rmdir() test case > selftests/nolibc: fix up failures when there is no procfs > selftests/nolibc: rename proc variable to has_proc > selftests/nolibc: rename euid0 variable to is_root > selftests/nolibc: prepare tmpfs and hugetlbfs > selftests/nolibc: rename chmod_net to chmod_good > selftests/nolibc: link_cross: support tmpfs > selftests/nolibc: rename chroot_exe to chroot_file > selftests/nolibc: vfprintf: silence memfd_create() warning > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > tools/include/nolibc/sys.h | 28 ++++ > tools/testing/selftests/nolibc/nolibc-test.c | 132 +++++++++++++++---- > 2 files changed, 138 insertions(+), 22 deletions(-) > > -- > 2.25.1 >
Hi, Thomas > Hi Zhangjin, > > some general comments for the whole series. > > On 2023-06-21 20:52:30+0800, Zhangjin Wu wrote: > > Hi, Willy > > > > This patchset mainly allows speed up the nolibc test with a minimal > > kernel config. > > > > As the nolibc supported architectures become more and more, the 'run' > > test with DEFCONFIG may cost several hours, which is not friendly to > > develop testing and even for release testing, so, smaller kernel configs > > may be required, and firstly, we should let nolibc-test work with less > > kernel config options, this patchset aims to this goal. > > > > This patchset mainly remove the dependency from procfs, tmpfs, net and > > memfd_create, many failures have been fixed up. > > > > When CONFIG_TMPFS and CONFIG_SHMEM are disabled, kernel will provide a > > ramfs based tmpfs (mm/shmem.c), it will be used as a choice to fix up > > some failures and also allow skip less tests. > > Did you look into how much this duplicates from the kernels already > existing "tinyconfig" and "kvm_guest.config" functionality? > Very good question and suggestion, thanks. it is just between tinyconfig and kvm_guest.config, the former is not enough, the later provides more. tinyconfig may be a very good base for us. Just tested some architectures, based on tinyconfig, seems we only need to enable very few options, for example, TTY, PRINTK, CONSOLE related and target virtual board related options, but it requires more time to just list the required options. The 'minimal' ones I have prepared were shrunk from the 'defconfig', now we need to add options from 'tinyconfig', with allnoconfig, it should be smaller and therefore faster ;-) Based on my local powerpc porting, I have prepared some changes like this: # extra kernel configs by architecture EXTCONFIG_powerpc = --enable SERIAL_PMACZILOG --enable CONFIG_SERIAL_PMACZILOG_CONSOLE EXTCONFIG = --set-str CONFIG_INITRAMFS_SOURCE $(CURDIR)/initramfs $(EXTCONFIG_$(ARCH)) ... menuconfig: $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) menuconfig extconfig: $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) olddefconfig kernel: initramfs extconfig $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) 'menuconfig' is added for development, for example, find why something not work and add the missing options. 'extconfig' is added to enable additional options (before, based on defconfig) to let nolibc-test happy (for powerpc, add missing console options which has been added as modules in default config). Based on your suggestion, this may be a good new target: tinyconfig: $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) mrproper tinyconfig prepare And this one, use 'allnoconfig' instead of 'olddefconfig': extconfig: $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) KCONFIG_ALLCONFIG=$(srctree)/.config allnoconfig So, the new 'tinyconfig' may function as the smallest test environment, for faster compile and as a boundary test of nolibc-test itself. But again, still need time to list the minimally required options, if they are few, listing them in the EXTCONFIG_<ARCH> line may be acceptable, but if the options are 'huge', standalone nolibc.config may be required, let's wait for one or two days. > And it would be interesting how much impact the enablement of procfs, > tmpfs, net and memfd_create has in constrast to the minimal > configuration. For the test speed (mainly kernel compile) itself, when for one architecture on a very good test host, the time cost increment is very little (see below), but it does save some, especially when for lots of architectures ;-) Comparing the rv64 testing speed on a Ubuntu 20.04 over '4G Mem + 4 Cores of i7-8550U CPU @ 1.80GHz' Virtual Machne, this time include: * nolibc-test sysroot install + build * kernel config + build * qemu boot with opensbi + u-boot + kernel v6.4-rcx Testing results: 'minimal': arch/board | result ------------|------------ riscv64/virt | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log LOG: see all results for all boards in /labs/linux-lab/logging/nolibc/nolibc-test.log real 1m57.395s user 4m50.002s sys 1m0.866s 'minimal' + procfs, net, shmem/tmpfs, devtmpfs/devmtmpfs_mount ...: arch/board | result ------------|------------ riscv64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log LOG: see all results for all boards in /labs/linux-lab/logging/nolibc/nolibc-test.log real 2m17.812s user 6m4.695s sys 1m7.061s It did save 20s (~17.1%) for us, not too much, but really faster. > It seems unfortunate to me to complicate the testsuite to handle such > uncommon scenarios. Yeah, such a config is not common, but as explained above, beside the compile speedup improvement, it is really a good boundary test environment for nolibc-test itself to make sure it work (no failure, less skips) at an extremely worst-case scene, although our changes looks many, but every one is as simple as CLOC ;-) And that also means, nolibc is able to run with a very 'tiny' kernel config and users could reuse our config fragments and add their own for their embedded devices. > > > Besides, it also adds musl support, improves glibc support and fixes up > > a kernel cmdline passing use case. > > > > This is based on the dev.2023.06.14a branch of linux-rcu [1], all of the > > supported architectures are tested (with local minimal configs, [5] > > pasted the one for i386) without failures: > > > > arch/board | result > > ------------|------------ > > arm/vexpress-a9 | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/arm-vexpress-a9-nolibc-test.log > > aarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/aarch64-virt-nolibc-test.log > > ppc/g3beige | not supported > > i386/pc | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/i386-pc-nolibc-test.log > > x86_64/pc | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/x86_64-pc-nolibc-test.log > > mipsel/malta | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/mipsel-malta-nolibc-test.log > > loongarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/loongarch64-virt-nolibc-test.log > > riscv64/virt | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log > > riscv32/virt | no test log found > > s390x/s390-ccw-virtio | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/s390x-s390-ccw-virtio-nolibc-test.log > > (snipped) > > It is able to build and run nolibc-test with musl libc now, but there > > are some failures/skips due to the musl its own issues/requirements: > > > > $ sudo ./nolibc-test | grep -E 'FAIL|SKIP' > > 8 sbrk = 1 ENOMEM [FAIL] > > 9 brk = -1 ENOMEM [FAIL] > > 46 limit_int_fast16_min = -2147483648 [FAIL] > > 47 limit_int_fast16_max = 2147483647 [FAIL] > > 49 limit_int_fast32_min = -2147483648 [FAIL] > > 50 limit_int_fast32_max = 2147483647 [FAIL] > > 0 -fstackprotector not supported [SKIPPED] > > > > musl disabled sbrk and brk for some conflicts with its malloc and the > > fast version of int types are defined in 32bit, which differs from nolibc > > and glibc. musl reserved the sbrk(0) to allow get current brk, we > > added a test for this in the v4 __sysret() helper series [2]. > > We could add new macros > > #define UINT_MAX(t) (~(t)0) > #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) > > to get whatever is appropriate for the respective type. > They work perfectly, thanks: /* for fast int test cases in stdlib test, musl use 32bit fast int */ #undef UINT_MAX #define UINT_MAX(t) (~(t)0) #undef SINT_MAX #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) #undef SINT_MIN #define SINT_MIN(t) (-SINT_MAX(t) - 1) ... CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) SINT_MIN(int_fast16_t)); break; CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) SINT_MAX(int_fast16_t)); break; CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINT_MAX(uint_fast16_t)); break; CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) SINT_MIN(int_fast32_t)); break; CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) SINT_MAX(int_fast32_t)); break; CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINT_MAX(uint_fast32_t)); break; To avoid overriding the existing macros, perhaps we should add something like UINT_TYPE_MAX(t), SINT_TYPE_MAX(t) and SINT_TYPE_MIN(t) ? > > > > * selftests/nolibc: fix up kernel parameters support > > > > kernel cmdline allows pass two types of parameters, one is without > > '=', another is with '=', the first one is passed as init arguments, > > the sencond one is passed as init environment variables. > > > > Our nolibc-test prefer arguments to environment variables, this not > > work when users add such parameters in the kernel cmdline: > > > > noapic NOLIBC_TEST=syscall > > > > So, this patch will verify the setting from arguments at first, if it > > is no valid, will try the environment variables instead. > > This would be much simpler as: > > test = getenv("NOLIBC_TEST"); > if (!test) > test = argv[1]; > > It changes the semantics a bit, but it doesn't seem to be an issue. > (Maybe gated behind getpid() == 1). Cool suggestion, it looks really better: if (getpid() == 1) { prepare(); /* kernel cmdline may pass: "noapic NOLIBC_TEST=syscall", * to init program: * * "noapic" as arguments, * "NOLIBC_TEST=syscall" as environment variables, * * to avoid getting null test in this case, parsing * environment variables at first. */ test = getenv("NOLIBC_TEST"); if (!test) test = argv[1]; } else { /* for normal nolibc-test program, prefer arguments */ test = argv[1]; if (!test) test = getenv("NOLIBC_TEST"); } > > > * selftests/nolibc: stat_timestamps: remove procfs dependency > > > > Use '/' instead of /proc/self, or we can add a 'has_proc' condition > > for this test case, but it is not that necessary to skip the whole > > stat_timestamps tests for such a subtest binding to /proc/self. > > > > Welcome suggestion from Thomas. > > As above, I think the impact of depending on CONFIG_PROC_FS is > justifiable. > > The usage of /proc/self was actually intentional. > This file has a timestamp of the start of the referenced process. > So each invocation of nolibc-test tests a new timestamp. > > In contrast if nolibc-test is invocated from a prebaked filesystem the > timestamp of "/" will always be fixed, reducing the chance to find > errors. Yeah, it is resonable to reserve this as /proc/self, for a balance, to avoid failure in the worst-case scene, let's add a 'has_proc' condition there instead, just like the other /proc/self based test cases do. > > > * tools/nolibc: add rmdir() support > > selftests/nolibc: add a new rmdir() test case > > (snipped) > > > > * selftests/nolibc: vfprintf: silence memfd_create() warning > > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > > > memfd_create from kernel >= v6.2 forcely warn on missing > > MFD_NOEXEC_SEAL flag, the first one silence it with such flag, for > > older kernels, use 0 flag as before. > > Given this is only a problem when nolibc-test is PID1 and printing to > the system console, we could also just disable warnings on the system > console through syscall() or /proc/sys/kernel/printk. Ok, I did think about disabling console for this call, but I was worried about the requirement of root (euid0) to do so, limiting it under PID1 may solve the root permission issue, but still need to find the right syscall to avoid the dependency of /proc/sys/kernel/printk, otherwise, to avoid failure for !procfs, the whole vfprintf will be skipped for such a warning, to be honest, it looks not a good direction. > > It would also avoid cluttering the tests for limited gain. > Hmm, if consider the more code lines about disabling/enabling console and the dependency of /proc/sys/kernel/printk, I do prefer current change. But I'm also interested in how the other applications developers to treat this warning, from the new kernel version side, we should use the latest non executable flags for security, but to let applications work with old kernels, we must support old flags, checking the kernel versions may be another choice. Perhaps it's time for us to add the 'uname()' for nolibc, but the version comparing may be not that easy when we are in c context ;-) https://www.man7.org/linux/man-pages/man2/uname.2.html So, the current method may be still a 'balanced' solution, it tries supported flags from new kernel to old kernel to get a better and working memfd_create() without the version checking, is this cleaner? int i; /* kernel >= v6.2 require MFD_NOEXEC_SEAL (0x0008U), but older ones not support this flag */ unsigned int flags[2] = {0x0008U, 0}; for (i = 0; i < 2; i ++) { /* try supported flags from new kernels to old kernels */ fd = memfd_create("vfprintf", flags[i]); if (fd != -1) break; } if (fd == -1) { ... } Thanks very much. Best regards, Zhangjin > > since memfd_create() depends on TMPFS or HUGETLBFS, the second one > > skip the whole vfprintf instead of simply fail if memfd_create() not > > work. > > > > the 3rd one futher try the ramfs based tmpfs even when memfd_create() > > not work. > > > > At last, let's simply discuss about the configs, I have prepared minimal > > configs for all of the nolibc supported architectures but not sure where > > should we put them, what about tools/testing/selftests/nolibc/configs ? > > > > Thanks! > > > > Best regards, > > Zhangjin > > --- > > > > [1]: https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/ > > [2]: https://lore.kernel.org/linux-riscv/cover.1687187451.git.falcon@tinylab.org/ > > [3]: https://lore.kernel.org/lkml/cover.1687156559.git.falcon@tinylab.org/ > > [4]: https://lore.kernel.org/linux-riscv/cover.1687176996.git.falcon@tinylab.org/ > > [5]: https://pastebin.com/5jq0Vxbz > > > > Zhangjin Wu (17): > > selftests/nolibc: stat_fault: silence NULL argument warning with glibc > > selftests/nolibc: gettid: restore for glibc and musl > > selftests/nolibc: add _LARGEFILE64_SOURCE for musl > > selftests/nolibc: fix up kernel parameters support > > selftests/nolibc: stat_timestamps: remove procfs dependency > > tools/nolibc: add rmdir() support > > selftests/nolibc: add a new rmdir() test case > > selftests/nolibc: fix up failures when there is no procfs > > selftests/nolibc: rename proc variable to has_proc > > selftests/nolibc: rename euid0 variable to is_root > > selftests/nolibc: prepare tmpfs and hugetlbfs > > selftests/nolibc: rename chmod_net to chmod_good > > selftests/nolibc: link_cross: support tmpfs > > selftests/nolibc: rename chroot_exe to chroot_file > > selftests/nolibc: vfprintf: silence memfd_create() warning > > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > > > tools/include/nolibc/sys.h | 28 ++++ > > tools/testing/selftests/nolibc/nolibc-test.c | 132 +++++++++++++++---- > > 2 files changed, 138 insertions(+), 22 deletions(-) > > > > -- > > 2.25.1 > >
On 2023-06-23 02:45:59+0800, Zhangjin Wu wrote: > > some general comments for the whole series. > > > > On 2023-06-21 20:52:30+0800, Zhangjin Wu wrote: > > > Hi, Willy > > > > > > This patchset mainly allows speed up the nolibc test with a minimal > > > kernel config. > > > > > > As the nolibc supported architectures become more and more, the 'run' > > > test with DEFCONFIG may cost several hours, which is not friendly to > > > develop testing and even for release testing, so, smaller kernel configs > > > may be required, and firstly, we should let nolibc-test work with less > > > kernel config options, this patchset aims to this goal. > > > > > > This patchset mainly remove the dependency from procfs, tmpfs, net and > > > memfd_create, many failures have been fixed up. > > > > > > When CONFIG_TMPFS and CONFIG_SHMEM are disabled, kernel will provide a > > > ramfs based tmpfs (mm/shmem.c), it will be used as a choice to fix up > > > some failures and also allow skip less tests. > > > > Did you look into how much this duplicates from the kernels already > > existing "tinyconfig" and "kvm_guest.config" functionality? > > > > Very good question and suggestion, thanks. it is just between tinyconfig > and kvm_guest.config, the former is not enough, the later provides more. > tinyconfig may be a very good base for us. > > Just tested some architectures, based on tinyconfig, seems we only need > to enable very few options, for example, TTY, PRINTK, CONSOLE related > and target virtual board related options, but it requires more time to > just list the required options. > > The 'minimal' ones I have prepared were shrunk from the 'defconfig', now > we need to add options from 'tinyconfig', with allnoconfig, it should be > smaller and therefore faster ;-) > > Based on my local powerpc porting, I have prepared some changes like > this: > > # extra kernel configs by architecture > EXTCONFIG_powerpc = --enable SERIAL_PMACZILOG --enable CONFIG_SERIAL_PMACZILOG_CONSOLE > EXTCONFIG = --set-str CONFIG_INITRAMFS_SOURCE $(CURDIR)/initramfs $(EXTCONFIG_$(ARCH)) > > ... >also > menuconfig: > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) menuconfig > > extconfig: > $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) olddefconfig > > kernel: initramfs extconfig > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) > > > 'menuconfig' is added for development, for example, find why something not work > and add the missing options. > > 'extconfig' is added to enable additional options (before, based on > defconfig) to let nolibc-test happy (for powerpc, add missing console > options which has been added as modules in default config). > > Based on your suggestion, this may be a good new target: > > tinyconfig: > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) mrproper tinyconfig prepare > > And this one, use 'allnoconfig' instead of 'olddefconfig': > > extconfig: > $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) KCONFIG_ALLCONFIG=$(srctree)/.config allnoconfig > > So, the new 'tinyconfig' may function as the smallest test environment, > for faster compile and as a boundary test of nolibc-test itself. > > But again, still need time to list the minimally required options, if they are > few, listing them in the EXTCONFIG_<ARCH> line may be acceptable, but if the > options are 'huge', standalone nolibc.config may be required, let's wait for > one or two days. FYI there are many more tests in tools/testing/selftests/ that need custom configs to run. Maybe we can reuse some of their configuration machinery. (And qemu machinery maybe) > > And it would be interesting how much impact the enablement of procfs, > > tmpfs, net and memfd_create has in constrast to the minimal > > configuration. > > For the test speed (mainly kernel compile) itself, when for one architecture on > a very good test host, the time cost increment is very little (see below), but it > does save some, especially when for lots of architectures ;-) > > Comparing the rv64 testing speed on a Ubuntu 20.04 over '4G Mem + 4 Cores of > i7-8550U CPU @ 1.80GHz' Virtual Machne, this time include: > > * nolibc-test sysroot install + build > * kernel config + build > * qemu boot with opensbi + u-boot + kernel v6.4-rcx > > Testing results: > > 'minimal': > > arch/board | result > ------------|------------ > riscv64/virt | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log > > LOG: see all results for all boards in /labs/linux-lab/logging/nolibc/nolibc-test.log > > > real 1m57.395s > user 4m50.002s > sys 1m0.866s > > 'minimal' + procfs, net, shmem/tmpfs, devtmpfs/devmtmpfs_mount ...: > > arch/board | result > ------------|------------ > riscv64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log > > LOG: see all results for all boards in /labs/linux-lab/logging/nolibc/nolibc-test.log > > > real 2m17.812s > user 6m4.695s > sys 1m7.061s > > It did save 20s (~17.1%) for us, not too much, but really faster. > > > It seems unfortunate to me to complicate the testsuite to handle such > > uncommon scenarios. > > Yeah, such a config is not common, but as explained above, beside the compile > speedup improvement, it is really a good boundary test environment for > nolibc-test itself to make sure it work (no failure, less skips) at an > extremely worst-case scene, although our changes looks many, but every one is > as simple as CLOC ;-) > > And that also means, nolibc is able to run with a very 'tiny' kernel > config and users could reuse our config fragments and add their own for > their embedded devices. It would mean that nolibc-test is able to run on *really* trimmed down systems, which seems of limited use. If the testsuite has more dependencies it would not stop nolibc itself to run on them. As for the CONFIG_NET dependency, which I would guess is one of the more expensive configs to enable: link_cross can be easily adapted to instead use /proc/self. chmod_net relies on /proc/$PID/net accepting chmod(). It is the only file in /proc/$PID/ that works that way. Maybe its a kernel bug anyways and we shouldn't rely on it anyways? I'm taking a look. > > > Besides, it also adds musl support, improves glibc support and fixes up > > > a kernel cmdline passing use case. > > > > > > This is based on the dev.2023.06.14a branch of linux-rcu [1], all of the > > > supported architectures are tested (with local minimal configs, [5] > > > pasted the one for i386) without failures: > > > > > > arch/board | result > > > ------------|------------ > > > arm/vexpress-a9 | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/arm-vexpress-a9-nolibc-test.log > > > aarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/aarch64-virt-nolibc-test.log > > > ppc/g3beige | not supported > > > i386/pc | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/i386-pc-nolibc-test.log > > > x86_64/pc | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/x86_64-pc-nolibc-test.log > > > mipsel/malta | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/mipsel-malta-nolibc-test.log > > > loongarch64/virt | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/loongarch64-virt-nolibc-test.log > > > riscv64/virt | 136 test(s) passed, 3 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/riscv64-virt-nolibc-test.log > > > riscv32/virt | no test log found > > > s390x/s390-ccw-virtio | 138 test(s) passed, 1 skipped, 0 failed. See all results in /labs/linux-lab/logging/nolibc/s390x-s390-ccw-virtio-nolibc-test.log > > > > > (snipped) > > > > It is able to build and run nolibc-test with musl libc now, but there > > > are some failures/skips due to the musl its own issues/requirements: > > > > > > $ sudo ./nolibc-test | grep -E 'FAIL|SKIP' > > > 8 sbrk = 1 ENOMEM [FAIL] > > > 9 brk = -1 ENOMEM [FAIL] > > > 46 limit_int_fast16_min = -2147483648 [FAIL] > > > 47 limit_int_fast16_max = 2147483647 [FAIL] > > > 49 limit_int_fast32_min = -2147483648 [FAIL] > > > 50 limit_int_fast32_max = 2147483647 [FAIL] > > > 0 -fstackprotector not supported [SKIPPED] > > > > > > musl disabled sbrk and brk for some conflicts with its malloc and the > > > fast version of int types are defined in 32bit, which differs from nolibc > > > and glibc. musl reserved the sbrk(0) to allow get current brk, we > > > added a test for this in the v4 __sysret() helper series [2]. > > > > We could add new macros > > > > #define UINT_MAX(t) (~(t)0) > > #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) > > > > to get whatever is appropriate for the respective type. > > > > They work perfectly, thanks: > > /* for fast int test cases in stdlib test, musl use 32bit fast int */ > #undef UINT_MAX > #define UINT_MAX(t) (~(t)0) > #undef SINT_MAX > #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) > #undef SINT_MIN > #define SINT_MIN(t) (-SINT_MAX(t) - 1) > > ... > > CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) SINT_MIN(int_fast16_t)); break; > CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) SINT_MAX(int_fast16_t)); break; > CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINT_MAX(uint_fast16_t)); break; > CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) SINT_MIN(int_fast32_t)); break; > CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) SINT_MAX(int_fast32_t)); break; > CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINT_MAX(uint_fast32_t)); break; > > To avoid overriding the existing macros, perhaps we should add something > like UINT_TYPE_MAX(t), SINT_TYPE_MAX(t) and SINT_TYPE_MIN(t) ? They should only be visible inside nolibc-test.c I think. But yes the UINT_MAX naming is bad. Also when going away from testing constants maybe we can get back some test strength by validating the sizeof() of the datatypes. <snip> > > > > > > * selftests/nolibc: vfprintf: silence memfd_create() warning > > > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > > > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > > > > > memfd_create from kernel >= v6.2 forcely warn on missing > > > MFD_NOEXEC_SEAL flag, the first one silence it with such flag, for > > > older kernels, use 0 flag as before. > > > > Given this is only a problem when nolibc-test is PID1 and printing to > > the system console, we could also just disable warnings on the system > > console through syscall() or /proc/sys/kernel/printk. > > Ok, I did think about disabling console for this call, but I was worried about > the requirement of root (euid0) to do so, limiting it under PID1 may solve the > root permission issue, but still need to find the right syscall to avoid the > dependency of /proc/sys/kernel/printk, otherwise, to avoid failure for !procfs, > the whole vfprintf will be skipped for such a warning, to be honest, it looks > not a good direction. This should work: syslog(__NR_syslog, 6 /* SYSLOG_ACTION_CONSOLE_OFF */); > > > > It would also avoid cluttering the tests for limited gain. > > > > Hmm, if consider the more code lines about disabling/enabling console and the > dependency of /proc/sys/kernel/printk, I do prefer current change. It should really only be the single line above. > But I'm also interested in how the other applications developers to treat this > warning, from the new kernel version side, we should use the latest non > executable flags for security, but to let applications work with old kernels, > we must support old flags, checking the kernel versions may be another choice. I know that systemd does it the same way as you proposed it, with non-negligible code overhead. But for nolibc-test I really don't see any security issue. > Perhaps it's time for us to add the 'uname()' for nolibc, but the > version comparing may be not that easy when we are in c context ;-) > > https://www.man7.org/linux/man-pages/man2/uname.2.html Please no :-) > So, the current method may be still a 'balanced' solution, it tries supported > flags from new kernel to old kernel to get a better and working memfd_create() > without the version checking, is this cleaner? > > int i; > /* kernel >= v6.2 require MFD_NOEXEC_SEAL (0x0008U), but older ones not support this flag */ It is not required, only desired. The functionality still works as expected. I don't think the "old" way can ever stop working as it would break userspace ABI. > unsigned int flags[2] = {0x0008U, 0}; > > for (i = 0; i < 2; i ++) { Loops like this should use ARRAY_SIZE() to calculate the termination condition. > /* try supported flags from new kernels to old kernels */ > fd = memfd_create("vfprintf", flags[i]); > if (fd != -1) > break; > } > > if (fd == -1) { > ... > } <snip> Thomas
On 2023-06-24 08:52:55+0200, Thomas Weißschuh wrote: > As for the CONFIG_NET dependency, which I would guess is one of the more > expensive configs to enable: > > link_cross can be easily adapted to instead use /proc/self. > > chmod_net relies on /proc/$PID/net accepting chmod(). > It is the only file in /proc/$PID/ that works that way. > > Maybe its a kernel bug anyways and we shouldn't rely on it anyways? > I'm taking a look. It indeed seems to be a kernel bug. The following patch aligns /proc/$PID/net with all the other /proc/$PID stuff. diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index a0c0419872e3..8c5e9abf4380 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -320,6 +320,7 @@ static int proc_tgid_net_getattr(struct mnt_idmap *idmap, const struct inode_operations proc_net_inode_operations = { .lookup = proc_tgid_net_lookup, + .setattr = proc_setattr, .getattr = proc_tgid_net_getattr, }; I'm not entirely sure about the process to synchronize the application of the fix in the procfs tree and the fix/removal of the testcase in the nolibc tree so we avoid broken states. Or if this would technically be a (relevant) break of userspace ABI and therefore has to stay as it is. Any ideas? Thomas
> Hi, Thomas > > On 2023-06-23 02:45:59+0800, Zhangjin Wu wrote: > > > some general comments for the whole series. > > > > > > On 2023-06-21 20:52:30+0800, Zhangjin Wu wrote: > > > > Hi, Willy > > > > > > > > This patchset mainly allows speed up the nolibc test with a minimal > > > > kernel config. > > > > (snip) > > Based on my local powerpc porting, I have prepared some changes like > > this: > > > > # extra kernel configs by architecture > > EXTCONFIG_powerpc = --enable SERIAL_PMACZILOG --enable CONFIG_SERIAL_PMACZILOG_CONSOLE > > EXTCONFIG = --set-str CONFIG_INITRAMFS_SOURCE $(CURDIR)/initramfs $(EXTCONFIG_$(ARCH)) > > > > ... > >also > > menuconfig: > > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) menuconfig > > > > extconfig: > > $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) > > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) olddefconfig > > > > kernel: initramfs extconfig > > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) > > > > > > 'menuconfig' is added for development, for example, find why something not work > > and add the missing options. > > > > 'extconfig' is added to enable additional options (before, based on > > defconfig) to let nolibc-test happy (for powerpc, add missing console > > options which has been added as modules in default config). > > > > Based on your suggestion, this may be a good new target: > > > > tinyconfig: > > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) mrproper tinyconfig prepare > > > > And this one, use 'allnoconfig' instead of 'olddefconfig': > > > > extconfig: > > $(Q)$(srctree)/scripts/config --file $(srctree)/.config $(EXTCONFIG) > > $(Q)$(MAKE) -C $(srctree) ARCH=$(KARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) KCONFIG_ALLCONFIG=$(srctree)/.config allnoconfig > > > > So, the new 'tinyconfig' may function as the smallest test environment, > > for faster compile and as a boundary test of nolibc-test itself. > > > > But again, still need time to list the minimally required options, if they are > > few, listing them in the EXTCONFIG_<ARCH> line may be acceptable, but if the > > options are 'huge', standalone nolibc.config may be required, let's wait for > > one or two days. > > FYI there are many more tests in tools/testing/selftests/ that need > custom configs to run. Maybe we can reuse some of their configuration > machinery. > (And qemu machinery maybe) > Yeah, thanks, these files may be very good references: $ find tools/testing/selftests/ -name "*config" | grep qemu tools/testing/selftests/wireguard/qemu/arch/aarch64.config tools/testing/selftests/wireguard/qemu/arch/aarch64_be.config tools/testing/selftests/wireguard/qemu/arch/arm.config tools/testing/selftests/wireguard/qemu/arch/armeb.config tools/testing/selftests/wireguard/qemu/arch/i686.config tools/testing/selftests/wireguard/qemu/arch/m68k.config tools/testing/selftests/wireguard/qemu/arch/mips.config tools/testing/selftests/wireguard/qemu/arch/mips64.config tools/testing/selftests/wireguard/qemu/arch/mips64el.config tools/testing/selftests/wireguard/qemu/arch/mipsel.config tools/testing/selftests/wireguard/qemu/arch/powerpc.config tools/testing/selftests/wireguard/qemu/arch/powerpc64.config tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config tools/testing/selftests/wireguard/qemu/arch/riscv32.config tools/testing/selftests/wireguard/qemu/arch/riscv64.config tools/testing/selftests/wireguard/qemu/arch/s390x.config tools/testing/selftests/wireguard/qemu/arch/um.config tools/testing/selftests/wireguard/qemu/arch/x86_64.config tools/testing/selftests/wireguard/qemu/debug.config tools/testing/selftests/wireguard/qemu/kernel.config And I have prepared most of them, just left 2-3 architectures. > > > And it would be interesting how much impact the enablement of procfs, > > > tmpfs, net and memfd_create has in constrast to the minimal > > > configuration. > > (snip) > > > > It did save 20s (~17.1%) for us, not too much, but really faster. > > > > > It seems unfortunate to me to complicate the testsuite to handle such > > > uncommon scenarios. > > > > Yeah, such a config is not common, but as explained above, beside the compile > > speedup improvement, it is really a good boundary test environment for > > nolibc-test itself to make sure it work (no failure, less skips) at an > > extremely worst-case scene, although our changes looks many, but every one is > > as simple as CLOC ;-) > > > > And that also means, nolibc is able to run with a very 'tiny' kernel > > config and users could reuse our config fragments and add their own for > > their embedded devices. > > It would mean that nolibc-test is able to run on *really* trimmed down > systems, which seems of limited use. > If the testsuite has more dependencies it would not stop nolibc itself > to run on them. > > As for the CONFIG_NET dependency, which I would guess is one of the more > expensive configs to enable: > > link_cross can be easily adapted to instead use /proc/self. > Yes, we can simply use /proc/self or proc/self/cmdline. > chmod_net relies on /proc/$PID/net accepting chmod(). > It is the only file in /proc/$PID/ that works that way. > Something like /tmp/xxx has been used in our patchset, to get a chmodable file, tmpfs is a good choice, even when the TMPFS (and SHMEM) option is disabled, a ramfs based tmpfs will be provided by kernel. > Maybe its a kernel bug anyways and we shouldn't rely on it anyways? > I'm taking a look. > Good catch, I have been also interested in such a curious difference, because all of the other proc interfaces are not chmodable, not sure if it is 'intentional', let's discuss in your patch thread, perhaps we should cc the /proc/self/net maintainers/authors ;-) > > > > (snipped) > > > > > > It is able to build and run nolibc-test with musl libc now, but there > > > > are some failures/skips due to the musl its own issues/requirements: > > > > > > > > $ sudo ./nolibc-test | grep -E 'FAIL|SKIP' > > > > 8 sbrk = 1 ENOMEM [FAIL] > > > > 9 brk = -1 ENOMEM [FAIL] > > > > 46 limit_int_fast16_min = -2147483648 [FAIL] > > > > 47 limit_int_fast16_max = 2147483647 [FAIL] > > > > 49 limit_int_fast32_min = -2147483648 [FAIL] > > > > 50 limit_int_fast32_max = 2147483647 [FAIL] > > > > 0 -fstackprotector not supported [SKIPPED] > > > > > > > > musl disabled sbrk and brk for some conflicts with its malloc and the > > > > fast version of int types are defined in 32bit, which differs from nolibc > > > > and glibc. musl reserved the sbrk(0) to allow get current brk, we > > > > added a test for this in the v4 __sysret() helper series [2]. > > > > > > We could add new macros > > > > > > #define UINT_MAX(t) (~(t)0) > > > #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) > > > > > > to get whatever is appropriate for the respective type. > > > > > > > They work perfectly, thanks: > > > > /* for fast int test cases in stdlib test, musl use 32bit fast int */ > > #undef UINT_MAX > > #define UINT_MAX(t) (~(t)0) > > #undef SINT_MAX > > #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) > > #undef SINT_MIN > > #define SINT_MIN(t) (-SINT_MAX(t) - 1) > > > > ... > > > > CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) SINT_MIN(int_fast16_t)); break; > > CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) SINT_MAX(int_fast16_t)); break; > > CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINT_MAX(uint_fast16_t)); break; > > CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) SINT_MIN(int_fast32_t)); break; > > CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) SINT_MAX(int_fast32_t)); break; > > CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINT_MAX(uint_fast32_t)); break; > > > > To avoid overriding the existing macros, perhaps we should add something > > like UINT_TYPE_MAX(t), SINT_TYPE_MAX(t) and SINT_TYPE_MIN(t) ? > > They should only be visible inside nolibc-test.c I think. Yeah, I did so. > But yes the UINT_MAX naming is bad. > > Also when going away from testing constants maybe we can get back some > test strength by validating the sizeof() of the datatypes. > It seems easier. > <snip> > > > > > > > > > * selftests/nolibc: vfprintf: silence memfd_create() warning > > > > selftests/nolibc: vfprintf: skip if neither tmpfs nor hugetlbfs > > > > selftests/nolibc: vfprintf: support tmpfs and hugetlbfs > > > > > > > > memfd_create from kernel >= v6.2 forcely warn on missing > > > > MFD_NOEXEC_SEAL flag, the first one silence it with such flag, for > > > > older kernels, use 0 flag as before. > > > > > > Given this is only a problem when nolibc-test is PID1 and printing to > > > the system console, we could also just disable warnings on the system > > > console through syscall() or /proc/sys/kernel/printk. > > > > Ok, I did think about disabling console for this call, but I was worried about > > the requirement of root (euid0) to do so, limiting it under PID1 may solve the > > root permission issue, but still need to find the right syscall to avoid the > > dependency of /proc/sys/kernel/printk, otherwise, to avoid failure for !procfs, > > the whole vfprintf will be skipped for such a warning, to be honest, it looks > > not a good direction. > > This should work: > > syslog(__NR_syslog, 6 /* SYSLOG_ACTION_CONSOLE_OFF */); > Thanks, will try it like this: syslog(__NR_syslog, 6 /* SYSLOG_ACTION_CONSOLE_OFF */); memfd_create() syslog(__NR_syslog, 7 /* SYSLOG_ACTION_CONSOLE_ON */); Putting it in prepare() may hide potential issues reported by kernel. > > > > > > It would also avoid cluttering the tests for limited gain. > > > > > > > Hmm, if consider the more code lines about disabling/enabling console and the > > dependency of /proc/sys/kernel/printk, I do prefer current change. > > It should really only be the single line above. > > > But I'm also interested in how the other applications developers to treat this > > warning, from the new kernel version side, we should use the latest non > > executable flags for security, but to let applications work with old kernels, > > we must support old flags, checking the kernel versions may be another choice. > > I know that systemd does it the same way as you proposed it, with > non-negligible code overhead. > > But for nolibc-test I really don't see any security issue. > Yes, but at least as a good reference when people want to reuse some codes from nolibc-test.c ;-) > > Perhaps it's time for us to add the 'uname()' for nolibc, but the > > version comparing may be not that easy when we are in c context ;-) > > > > https://www.man7.org/linux/man-pages/man2/uname.2.html > > Please no :-) > > > So, the current method may be still a 'balanced' solution, it tries supported > > flags from new kernel to old kernel to get a better and working memfd_create() > > without the version checking, is this cleaner? > > > > int i; > > /* kernel >= v6.2 require MFD_NOEXEC_SEAL (0x0008U), but older ones not support this flag */ > > It is not required, only desired. The functionality still works as > expected. I don't think the "old" way can ever stop working as it would > break userspace ABI. > > > unsigned int flags[2] = {0x0008U, 0}; > > > > for (i = 0; i < 2; i ++) { > > Loops like this should use ARRAY_SIZE() to calculate the termination > condition. Yeah, it should be: unsigned int flags[] = {0x0008U, 0}; for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i ++) ... Best regards, Zhangjin > > > /* try supported flags from new kernels to old kernels */ > > fd = memfd_create("vfprintf", flags[i]); > > if (fd != -1) > > break; > > } > > > > if (fd == -1) { > > ... > > } > > <snip> > > > Thomas
Hi, Thomas > > Hi Zhangjin, > > > > some general comments for the whole series. > > > > On 2023-06-21 20:52:30+0800, Zhangjin Wu wrote: > > > Hi, Willy > > > > > > This patchset mainly allows speed up the nolibc test with a minimal > > > kernel config. > > > > (snip) > > > > > > * selftests/nolibc: fix up kernel parameters support > > > > > > kernel cmdline allows pass two types of parameters, one is without > > > '=', another is with '=', the first one is passed as init arguments, > > > the sencond one is passed as init environment variables. > > > > > > Our nolibc-test prefer arguments to environment variables, this not > > > work when users add such parameters in the kernel cmdline: > > > > > > noapic NOLIBC_TEST=syscall > > > > > > So, this patch will verify the setting from arguments at first, if it > > > is no valid, will try the environment variables instead. > > > > This would be much simpler as: > > > > test = getenv("NOLIBC_TEST"); > > if (!test) > > test = argv[1]; > > > > It changes the semantics a bit, but it doesn't seem to be an issue. > > (Maybe gated behind getpid() == 1). > > Cool suggestion, it looks really better: > > if (getpid() == 1) { > prepare(); > > /* kernel cmdline may pass: "noapic NOLIBC_TEST=syscall", > * to init program: > * > * "noapic" as arguments, > * "NOLIBC_TEST=syscall" as environment variables, > * > * to avoid getting null test in this case, parsing > * environment variables at first. > */ > test = getenv("NOLIBC_TEST"); > if (!test) > test = argv[1]; > } else { > /* for normal nolibc-test program, prefer arguments */ > test = argv[1]; > if (!test) > test = getenv("NOLIBC_TEST"); > } > Test shows, when no NOLIBC_TEST environment variable passed to kernel cmdline, it will still branch to this code: test = argv[1]; /* nopaic ... */ And therefore report the whole test is ignored and no test will be run: Ignoring unknown test name 'noapic' So, we may still need to verify it like my originally proposed method, but let's further verify the one from NOLIBC_TEST=, we should tune the code a litle. Thanks, Zhangjin