History

Merge tag 'mm-nonmm-stable-2025-12-06-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM updates from Andrew Morton: - "panic: sys_info: Refactor and fix a potential issue" (Andy Shevchenko) fixes a build issue and does some cleanup in ib/sys_info.c - "Implement mul_u64_u64_div_u64_roundup()" (David Laight) enhances the 64-bit math code on behalf of a PWM driver and beefs up the test module for these library functions - "scripts/gdb/symbols: make BPF debug info available to GDB" (Ilya Leoshkevich) makes BPF symbol names, sizes, and line numbers available to the GDB debugger - "Enable hung_task and lockup cases to dump system info on demand" (Feng Tang) adds a sysctl which can be used to cause additional info dumping when the hung-task and lockup detectors fire - "lib/base64: add generic encoder/decoder, migrate users" (Kuan-Wei Chiu) adds a general base64 encoder/decoder to lib/ and migrates several users away from their private implementations - "rbree: inline rb_first() and rb_last()" (Eric Dumazet) makes TCP a little faster - "liveupdate: Rework KHO for in-kernel users" (Pasha Tatashin) reworks the KEXEC Handover interfaces in preparation for Live Update Orchestrator (LUO), and possibly for other future clients - "kho: simplify state machine and enable dynamic updates" (Pasha Tatashin) increases the flexibility of KEXEC Handover. Also preparation for LUO - "Live Update Orchestrator" (Pasha Tatashin) is a major new feature targeted at cloud environments. Quoting the cover letter: This series introduces the Live Update Orchestrator, a kernel subsystem designed to facilitate live kernel updates using a kexec-based reboot. This capability is critical for cloud environments, allowing hypervisors to be updated with minimal downtime for running virtual machines. LUO achieves this by preserving the state of selected resources, such as memory, devices and their dependencies, across the kernel transition. As a key feature, this series includes support for preserving memfd file descriptors, which allows critical in-memory data, such as guest RAM or any other large memory region, to be maintained in RAM across the kexec reboot. Mike Rappaport merits a mention here, for his extensive review and testing work. - "kexec: reorganize kexec and kdump sysfs" (Sourabh Jain) moves the kexec and kdump sysfs entries from /sys/kernel/ to /sys/kernel/kexec/ and adds back-compatibility symlinks which can hopefully be removed one day - "kho: fixes for vmalloc restoration" (Mike Rapoport) fixes a BUG which was being hit during KHO restoration of vmalloc() regions * tag 'mm-nonmm-stable-2025-12-06-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (139 commits) calibrate: update header inclusion Reinstate "resource: avoid unnecessary lookups in find_next_iomem_res()" vmcoreinfo: track and log recoverable hardware errors kho: fix restoring of contiguous ranges of order-0 pages kho: kho_restore_vmalloc: fix initialization of pages array MAINTAINERS: TPM DEVICE DRIVER: update the W-tag init: replace simple_strtoul with kstrtoul to improve lpj_setup KHO: fix boot failure due to kmemleak access to non-PRESENT pages Documentation/ABI: new kexec and kdump sysfs interface Documentation/ABI: mark old kexec sysfs deprecated kexec: move sysfs entries to /sys/kernel/kexec test_kho: always print restore status kho: free chunks using free_page() instead of kfree() selftests/liveupdate: add kexec test for multiple and empty sessions selftests/liveupdate: add simple kexec-based selftest for LUO selftests/liveupdate: add userspace API selftests docs: add documentation for memfd preservation via LUO mm: memfd_luo: allow preserving memfd liveupdate: luo_file: add private argument to store runtime state mm: shmem: export some functions to internal.h ...

Linus Torvalds committed 11 months ago

Commit 509d3f42 parents 09670b8 aa514a2439 files · +8031 −1801Browse files

Unified · Split

439 files
  1. .mailmap +6 −3
  2. CREDITS +4 −5
  3. Documentation/ABI/obsolete/sysfs-kernel-kexec-kdump +71 −0
  4. Documentation/ABI/testing/sysfs-kernel-kexec-kdump +61 −0
  5. Documentation/admin-guide/dynamic-debug-howto.rst +3 −2
  6. Documentation/admin-guide/kernel-parameters.txt +13 −7
  7. Documentation/admin-guide/sysctl/kernel.rst +26 −6
  8. Documentation/core-api/index.rst +1 −0
  9. Documentation/core-api/kho/concepts.rst +1 −1
  10. Documentation/core-api/liveupdate.rst +61 −0
  11. Documentation/dev-tools/checkpatch.rst +10 −0
  12. Documentation/driver-api/hw-recoverable-errors.rst +60 −0
  13. Documentation/driver-api/index.rst +1 −0
  14. Documentation/mm/index.rst +1 −0
  15. Documentation/mm/memfd_preservation.rst +23 −0
  16. Documentation/userspace-api/index.rst +1 −0
  17. Documentation/userspace-api/ioctl/ioctl-number.rst +2 −0
  18. Documentation/userspace-api/liveupdate.rst +20 −0
  19. MAINTAINERS +26 −8
  20. arch/Kconfig +8 −11
  21. arch/arm/Kconfig +0 −2
  22. arch/arm/configs/aspeed_g5_defconfig +1 −1
  23. arch/powerpc/include/asm/crash_reserve.h +8 −0
  24. arch/x86/include/asm/div64.h +31 −8
  25. arch/x86/kernel/cpu/mce/core.c +4 −0
  26. drivers/acpi/apei/ghes.c +36 −0
  27. drivers/nvme/common/auth.c +2 −2
  28. drivers/pci/pcie/aer.c +2 −0
  29. fs/ceph/crypto.c +4 −56
  30. fs/ceph/crypto.h +1 −5
  31. fs/ceph/dir.c +3 −2
  32. fs/ceph/inode.c +1 −1
  33. fs/crypto/fname.c +6 −83
  34. fs/nilfs2/ioctl.c +10 −25
  35. fs/ocfs2/dir.c +38 −4
  36. fs/ocfs2/inode.c +44 −5
  37. fs/ocfs2/move_extents.c +13 −1
  38. fs/ocfs2/ocfs2_fs.h +14 −8
  39. fs/ocfs2/refcounttree.c +3 −2
  40. fs/ocfs2/xattr.c +1 −1
  41. fs/proc/page.c +0 −1
  42. include/linux/base64.h +8 −2
  43. include/linux/compiler.h +0 −6
  44. include/linux/crash_reserve.h +6 −0
  45. include/linux/dynamic_debug.h +14 −3
  46. include/linux/kexec_handover.h +28 −29
  47. include/linux/kho/abi/luo.h +166 −0
  48. include/linux/kho/abi/memfd.h +77 −0
  49. include/linux/liveupdate.h +138 −0
  50. include/linux/math.h +9 −4
  51. include/linux/math64.h +58 −1
  52. include/linux/once_lite.h +1 −1
  53. include/linux/panic.h +0 −1
  54. include/linux/rbtree.h +30 −2
  55. include/linux/shmem_fs.h +23 −0
  56. include/linux/sys_info.h +1 −1
  57. include/linux/uaccess.h +4 −2
  58. include/linux/util_macros.h +2 −2
  59. include/linux/vmcore_info.h +8 −0
  60. include/linux/xxhash.h +1 −45
  61. include/uapi/linux/liveupdate.h +216 −0
  62. include/uapi/linux/vmcore.h +9 −0
  63. init/Kconfig +20 −0
  64. init/calibrate.c +8 −5
  65. init/main.c +96 −1
  66. ipc/namespace.c +5 −4
  67. kernel/Kconfig.kexec +0 −24
  68. kernel/Makefile +1 −2
  69. kernel/configs/debug.config +1 −1
  70. kernel/crash_reserve.c +3 −0
  71. kernel/exit.c +1 −3
  72. kernel/fork.c +53 −10
  73. kernel/hung_task.c +38 −18
  74. kernel/kexec_core.c +149 −12
  75. kernel/kexec_handover_internal.h +0 −20
  76. kernel/ksysfs.c +1 −67
  77. kernel/liveupdate/Kconfig +75 −0
  78. kernel/liveupdate/Makefile +12 −0
  79. kernel/liveupdate/kexec_handover.c +333 −383
  80. kernel/liveupdate/kexec_handover_debug.c +0 −0
  81. kernel/liveupdate/kexec_handover_debugfs.c +221 −0
  82. kernel/liveupdate/kexec_handover_internal.h +55 −0
  83. kernel/liveupdate/luo_core.c +450 −0
  84. kernel/liveupdate/luo_file.c +889 −0
  85. kernel/liveupdate/luo_internal.h +110 −0
  86. kernel/liveupdate/luo_session.c +646 −0
  87. kernel/module/main.c +1 −1
  88. kernel/panic.c +27 −25
  89. kernel/resource.c +9 −1
  90. kernel/scs.c +1 −1
  91. kernel/vmcore_info.c +17 −0
  92. kernel/watchdog.c +41 −3
  93. lib/Kconfig.debug +40 −23
  94. lib/base64.c +135 −54
  95. lib/dynamic_debug.c +1 −0
  96. lib/math/div64.c +124 −61
  97. lib/math/test_mul_u64_u64_div_u64.c +141 −50
  98. lib/plist.c +2 −2
  99. lib/ratelimit.c +1 −1
  100. lib/rbtree.c +0 −29
  101. lib/sys_info.c +106 −63
  102. lib/test_kho.c +80 −60
  103. lib/tests/Makefile +1 −0
  104. lib/tests/base64_kunit.c +294 −0
  105. lib/usercopy.c +2 −2
  106. lib/xxhash.c +0 −29
  107. lib/xz/xz_dec_bcj.c +0 −95
  108. lib/xz/xz_private.h +0 −4
  109. mm/Makefile +1 −0
  110. mm/internal.h +6 −0
  111. mm/memblock.c +50 −43
  112. mm/memfd_luo.c +516 −0
  113. mm/shmem.c +31 −18
  114. rust/helpers/rbtree.c +10 −0
  115. rust/helpers/uaccess.c +12 −0
  116. samples/Kconfig +11 −11
  117. samples/vfs/Makefile +1 −0
  118. scripts/checkpatch.pl +11 −0
  119. scripts/gdb/linux/bpf.py +253 −0
  120. scripts/gdb/linux/constants.py.in +3 −0
  121. scripts/gdb/linux/radixtree.py +132 −7
  122. scripts/gdb/linux/symbols.py +93 −12
  123. tools/testing/selftests/Makefile +1 −0
  124. tools/testing/selftests/acct/acct_syscall.c +1 −1
  125. tools/testing/selftests/alsa/conf.c +1 −1
  126. tools/testing/selftests/alsa/mixer-test.c +1 −1
  127. tools/testing/selftests/alsa/pcm-test.c +1 −1
  128. tools/testing/selftests/alsa/test-pcmtest-driver.c +1 −1
  129. tools/testing/selftests/alsa/utimer-test.c +1 −1
  130. tools/testing/selftests/arm64/abi/hwcap.c +1 −1
  131. tools/testing/selftests/arm64/abi/ptrace.c +1 −1
  132. tools/testing/selftests/arm64/abi/syscall-abi.c +1 −1
  133. tools/testing/selftests/arm64/fp/fp-ptrace.c +1 −1
  134. tools/testing/selftests/arm64/fp/fp-stress.c +1 −1
  135. tools/testing/selftests/arm64/fp/sve-probe-vls.c +1 −1
  136. tools/testing/selftests/arm64/fp/sve-ptrace.c +1 −1
  137. tools/testing/selftests/arm64/fp/vec-syscfg.c +1 −1
  138. tools/testing/selftests/arm64/fp/za-ptrace.c +1 −1
  139. tools/testing/selftests/arm64/fp/zt-ptrace.c +1 −1
  140. tools/testing/selftests/arm64/gcs/gcs-stress.c +1 −1
  141. tools/testing/selftests/arm64/pauth/pac.c +1 −1
  142. tools/testing/selftests/arm64/tags/tags_test.c +1 −1
  143. tools/testing/selftests/bpf/xskxceiver.c +1 −1
  144. tools/testing/selftests/breakpoints/breakpoint_test.c +1 −1
  145. tools/testing/selftests/breakpoints/breakpoint_test_arm64.c +1 −1
  146. tools/testing/selftests/breakpoints/step_after_suspend_test.c +1 −1
  147. tools/testing/selftests/cachestat/test_cachestat.c +1 −1
  148. tools/testing/selftests/capabilities/test_execve.c +1 −1
  149. tools/testing/selftests/capabilities/validate_cap.c +1 −1
  150. tools/testing/selftests/cgroup/test_core.c +1 −1
  151. tools/testing/selftests/cgroup/test_cpu.c +1 −1
  152. tools/testing/selftests/cgroup/test_cpuset.c +1 −1
  153. tools/testing/selftests/cgroup/test_freezer.c +1 −1
  154. tools/testing/selftests/cgroup/test_hugetlb_memcg.c +1 −1
  155. tools/testing/selftests/cgroup/test_kill.c +1 −1
  156. tools/testing/selftests/cgroup/test_kmem.c +1 −1
  157. tools/testing/selftests/cgroup/test_memcontrol.c +1 −1
  158. tools/testing/selftests/cgroup/test_pids.c +1 −1
  159. tools/testing/selftests/cgroup/test_zswap.c +1 −1
  160. tools/testing/selftests/clone3/clone3.c +1 −1
  161. tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c +1 −1
  162. tools/testing/selftests/clone3/clone3_clear_sighand.c +1 −1
  163. tools/testing/selftests/clone3/clone3_selftests.h +1 −1
  164. tools/testing/selftests/clone3/clone3_set_tid.c +1 −1
  165. tools/testing/selftests/connector/proc_filter.c +1 −1
  166. tools/testing/selftests/core/close_range_test.c +1 −1
  167. tools/testing/selftests/core/unshare_test.c +1 −1
  168. tools/testing/selftests/coredump/stackdump_test.c +1 −1
  169. tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c +1 −1
  170. tools/testing/selftests/drivers/dma-buf/udmabuf.c +1 −1
  171. tools/testing/selftests/drivers/net/gro.c +1 −1
  172. tools/testing/selftests/drivers/net/hw/toeplitz.c +1 −1
  173. tools/testing/selftests/drivers/ntsync/ntsync.c +1 −1
  174. tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c +1 −1
  175. tools/testing/selftests/exec/check-exec.c +1 −1
  176. tools/testing/selftests/exec/execveat.c +1 −1
  177. tools/testing/selftests/exec/load_address.c +1 −1
  178. tools/testing/selftests/exec/non-regular.c +1 −1
  179. tools/testing/selftests/exec/null-argv.c +1 −1
  180. tools/testing/selftests/exec/recursion-depth.c +1 −1
  181. tools/testing/selftests/fchmodat2/fchmodat2_test.c +1 −1
  182. tools/testing/selftests/filelock/ofdlocks.c +1 −1
  183. tools/testing/selftests/filesystems/anon_inode_test.c +1 −1
  184. tools/testing/selftests/filesystems/binderfs/binderfs_test.c +1 −1
  185. tools/testing/selftests/filesystems/devpts_pts.c +1 −1
  186. tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c +1 −1
  187. tools/testing/selftests/filesystems/eventfd/eventfd_test.c +1 −1
  188. tools/testing/selftests/filesystems/fclog.c +1 −1
  189. tools/testing/selftests/filesystems/file_stressor.c +1 −1
  190. tools/testing/selftests/filesystems/fuse/fusectl_test.c +1 −1
  191. tools/testing/selftests/filesystems/kernfs_test.c +1 −1
  192. tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c +1 −1
  193. tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c +1 −1
  194. tools/testing/selftests/filesystems/nsfs/iterate_mntns.c +1 −1
  195. tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c +1 −1
  196. tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c +1 −1
  197. tools/testing/selftests/filesystems/statmount/listmount_test.c +1 −1
  198. tools/testing/selftests/filesystems/statmount/statmount_test.c +1 −1
  199. tools/testing/selftests/filesystems/statmount/statmount_test_ns.c +1 −1
  200. tools/testing/selftests/filesystems/utils.c +1 −1
  201. tools/testing/selftests/futex/functional/futex_numa_mpol.c +1 −1
  202. tools/testing/selftests/futex/functional/futex_priv_hash.c +1 −1
  203. tools/testing/selftests/futex/functional/futex_requeue.c +1 −1
  204. tools/testing/selftests/futex/functional/futex_requeue_pi.c +1 −1
  205. tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c +1 −1
  206. tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c +1 −1
  207. tools/testing/selftests/futex/functional/futex_wait.c +1 −1
  208. tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c +1 −1
  209. tools/testing/selftests/futex/functional/futex_wait_timeout.c +1 −1
  210. tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c +1 −1
  211. tools/testing/selftests/futex/functional/futex_wait_wouldblock.c +1 −1
  212. tools/testing/selftests/futex/functional/futex_waitv.c +1 −1
  213. tools/testing/selftests/hid/hid_common.h +1 −1
  214. tools/testing/selftests/intel_pstate/aperf.c +1 −1
  215. tools/testing/selftests/iommu/iommufd_utils.h +1 −1
  216. tools/testing/selftests/ipc/msgque.c +1 −1
  217. tools/testing/selftests/ir/ir_loopback.c +1 −1
  218. tools/testing/selftests/kcmp/kcmp_test.c +1 −1
  219. tools/testing/selftests/kho/vmtest.sh +1 −0
  220. tools/testing/selftests/kselftest_harness.h +1 −1
  221. tools/testing/selftests/kselftest_harness/harness-selftest.c +1 −1
  222. tools/testing/selftests/landlock/audit.h +1 −1
  223. tools/testing/selftests/landlock/common.h +1 −1
  224. tools/testing/selftests/lib.mk +3 −0
  225. tools/testing/selftests/liveupdate/.gitignore +9 −0
  226. tools/testing/selftests/liveupdate/Makefile +34 −0
  227. tools/testing/selftests/liveupdate/config +11 −0
  228. tools/testing/selftests/liveupdate/do_kexec.sh +16 −0
  229. tools/testing/selftests/liveupdate/liveupdate.c +348 −0
  230. tools/testing/selftests/liveupdate/luo_kexec_simple.c +89 −0
  231. tools/testing/selftests/liveupdate/luo_multi_session.c +162 −0
  232. tools/testing/selftests/liveupdate/luo_test_utils.c +266 −0
  233. tools/testing/selftests/liveupdate/luo_test_utils.h +44 −0
  234. tools/testing/selftests/lsm/lsm_get_self_attr_test.c +1 −1
  235. tools/testing/selftests/lsm/lsm_list_modules_test.c +1 −1
  236. tools/testing/selftests/lsm/lsm_set_self_attr_test.c +1 −1
  237. tools/testing/selftests/media_tests/media_device_open.c +1 −1
  238. tools/testing/selftests/media_tests/media_device_test.c +1 −1
  239. tools/testing/selftests/membarrier/membarrier_test_impl.h +1 −1
  240. tools/testing/selftests/mincore/mincore_selftest.c +2 −2
  241. tools/testing/selftests/mm/compaction_test.c +1 −1
  242. tools/testing/selftests/mm/cow.c +1 −1
  243. tools/testing/selftests/mm/droppable.c +1 −1
  244. tools/testing/selftests/mm/guard-regions.c +1 −1
  245. tools/testing/selftests/mm/gup_longterm.c +1 −1
  246. tools/testing/selftests/mm/gup_test.c +1 −1
  247. tools/testing/selftests/mm/hmm-tests.c +1 −1
  248. tools/testing/selftests/mm/hugepage-mmap.c +1 −1
  249. tools/testing/selftests/mm/hugepage-mremap.c +1 −1
  250. tools/testing/selftests/mm/hugetlb-madvise.c +1 −1
  251. tools/testing/selftests/mm/hugetlb-read-hwpoison.c +1 −1
  252. tools/testing/selftests/mm/hugetlb-soft-offline.c +1 −1
  253. tools/testing/selftests/mm/hugetlb_dio.c +1 −1
  254. tools/testing/selftests/mm/hugetlb_fault_after_madv.c +1 −1
  255. tools/testing/selftests/mm/hugetlb_madv_vs_map.c +1 −1
  256. tools/testing/selftests/mm/ksm_functional_tests.c +1 −1
  257. tools/testing/selftests/mm/ksm_tests.c +1 −1
  258. tools/testing/selftests/mm/madv_populate.c +1 −1
  259. tools/testing/selftests/mm/map_fixed_noreplace.c +1 −1
  260. tools/testing/selftests/mm/map_hugetlb.c +1 −1
  261. tools/testing/selftests/mm/map_populate.c +1 −1
  262. tools/testing/selftests/mm/mdwe_test.c +1 −1
  263. tools/testing/selftests/mm/memfd_secret.c +1 −1
  264. tools/testing/selftests/mm/merge.c +1 −1
  265. tools/testing/selftests/mm/migration.c +1 −1
  266. tools/testing/selftests/mm/mkdirty.c +1 −1
  267. tools/testing/selftests/mm/mlock-random-test.c +1 −1
  268. tools/testing/selftests/mm/mlock2-tests.c +1 −1
  269. tools/testing/selftests/mm/mrelease_test.c +1 −1
  270. tools/testing/selftests/mm/mremap_dontunmap.c +1 −1
  271. tools/testing/selftests/mm/mremap_test.c +1 −1
  272. tools/testing/selftests/mm/mseal_test.c +1 −1
  273. tools/testing/selftests/mm/on-fault-limit.c +1 −1
  274. tools/testing/selftests/mm/pagemap_ioctl.c +1 −1
  275. tools/testing/selftests/mm/pfnmap.c +1 −1
  276. tools/testing/selftests/mm/pkey-helpers.h +1 −1
  277. tools/testing/selftests/mm/prctl_thp_disable.c +1 −1
  278. tools/testing/selftests/mm/process_madv.c +1 −1
  279. tools/testing/selftests/mm/rmap.c +1 −1
  280. tools/testing/selftests/mm/soft-dirty.c +1 −1
  281. tools/testing/selftests/mm/split_huge_page_test.c +1 −1
  282. tools/testing/selftests/mm/thuge-gen.c +1 −1
  283. tools/testing/selftests/mm/transhuge-stress.c +1 −1
  284. tools/testing/selftests/mm/uffd-common.h +1 −1
  285. tools/testing/selftests/mm/uffd-wp-mremap.c +1 −1
  286. tools/testing/selftests/mm/va_high_addr_switch.c +1 −1
  287. tools/testing/selftests/mm/virtual_address_range.c +1 −1
  288. tools/testing/selftests/mm/vm_util.c +1 −1
  289. tools/testing/selftests/mm/vm_util.h +1 −1
  290. tools/testing/selftests/mount_setattr/mount_setattr_test.c +1 −1
  291. tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c +1 −1
  292. tools/testing/selftests/mqueue/mq_open_tests.c +1 −1
  293. tools/testing/selftests/mqueue/mq_perf_tests.c +1 −1
  294. tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +2 −2
  295. tools/testing/selftests/namespaces/file_handle_test.c +1 −1
  296. tools/testing/selftests/namespaces/init_ino_test.c +1 −1
  297. tools/testing/selftests/namespaces/nsid_test.c +1 −1
  298. tools/testing/selftests/nci/nci_dev.c +1 −1
  299. tools/testing/selftests/net/af_unix/diag_uid.c +1 −1
  300. tools/testing/selftests/net/af_unix/msg_oob.c +1 −1
  301. tools/testing/selftests/net/af_unix/scm_inq.c +1 −1
  302. tools/testing/selftests/net/af_unix/scm_pidfd.c +1 −1
  303. tools/testing/selftests/net/af_unix/scm_rights.c +1 −1
  304. tools/testing/selftests/net/af_unix/unix_connect.c +1 −1
  305. tools/testing/selftests/net/bind_timewait.c +1 −1
  306. tools/testing/selftests/net/bind_wildcard.c +1 −1
  307. tools/testing/selftests/net/can/test_raw_filter.c +1 −1
  308. tools/testing/selftests/net/cmsg_sender.c +1 −1
  309. tools/testing/selftests/net/epoll_busy_poll.c +1 −1
  310. tools/testing/selftests/net/ip_local_port_range.c +1 −1
  311. tools/testing/selftests/net/ipsec.c +1 −1
  312. tools/testing/selftests/net/ipv6_fragmentation.c +1 −1
  313. tools/testing/selftests/net/netfilter/conntrack_dump_flush.c +1 −1
  314. tools/testing/selftests/net/netlink-dumps.c +1 −1
  315. tools/testing/selftests/net/ovpn/ovpn-cli.c +1 −1
  316. tools/testing/selftests/net/proc_net_pktgen.c +1 −1
  317. tools/testing/selftests/net/psock_fanout.c +1 −1
  318. tools/testing/selftests/net/psock_tpacket.c +1 −1
  319. tools/testing/selftests/net/reuseaddr_ports_exhausted.c +1 −1
  320. tools/testing/selftests/net/reuseport_bpf.c +1 −1
  321. tools/testing/selftests/net/reuseport_bpf_numa.c +1 −1
  322. tools/testing/selftests/net/rxtimestamp.c +1 −1
  323. tools/testing/selftests/net/sk_so_peek_off.c +1 −1
  324. tools/testing/selftests/net/so_incoming_cpu.c +1 −1
  325. tools/testing/selftests/net/socket.c +1 −1
  326. tools/testing/selftests/net/tap.c +1 −1
  327. tools/testing/selftests/net/tcp_ao/lib/setup.c +1 −1
  328. tools/testing/selftests/net/tcp_fastopen_backup_key.c +1 −1
  329. tools/testing/selftests/net/tcp_port_share.c +1 −1
  330. tools/testing/selftests/net/tls.c +1 −1
  331. tools/testing/selftests/net/tun.c +1 −1
  332. tools/testing/selftests/net/udpgso_bench_tx.c +1 −1
  333. tools/testing/selftests/openat2/helpers.h +1 −1
  334. tools/testing/selftests/openat2/openat2_test.c +1 −1
  335. tools/testing/selftests/openat2/rename_attack_test.c +1 −1
  336. tools/testing/selftests/openat2/resolve_test.c +1 −1
  337. tools/testing/selftests/pci_endpoint/pci_endpoint_test.c +1 −1
  338. tools/testing/selftests/perf_events/mmap.c +1 −1
  339. tools/testing/selftests/perf_events/remove_on_exec.c +1 −1
  340. tools/testing/selftests/perf_events/sigtrap_threads.c +1 −1
  341. tools/testing/selftests/perf_events/watermark_signal.c +1 −1
  342. tools/testing/selftests/pid_namespace/pid_max.c +1 −1
  343. tools/testing/selftests/pid_namespace/regression_enomem.c +1 −1
  344. tools/testing/selftests/pidfd/pidfd.h +1 −1
  345. tools/testing/selftests/pidfd/pidfd_bind_mount.c +1 −1
  346. tools/testing/selftests/pidfd/pidfd_fdinfo_test.c +1 −1
  347. tools/testing/selftests/pidfd/pidfd_file_handle_test.c +1 −1
  348. tools/testing/selftests/pidfd/pidfd_getfd_test.c +1 −1
  349. tools/testing/selftests/pidfd/pidfd_info_test.c +1 −1
  350. tools/testing/selftests/pidfd/pidfd_open_test.c +1 −1
  351. tools/testing/selftests/pidfd/pidfd_poll_test.c +1 −1
  352. tools/testing/selftests/pidfd/pidfd_setattr_test.c +1 −1
  353. tools/testing/selftests/pidfd/pidfd_setns_test.c +1 −1
  354. tools/testing/selftests/pidfd/pidfd_test.c +1 −1
  355. tools/testing/selftests/pidfd/pidfd_wait.c +1 −1
  356. tools/testing/selftests/pidfd/pidfd_xattr_test.c +1 −1
  357. tools/testing/selftests/prctl/set-anon-vma-name-test.c +1 −1
  358. tools/testing/selftests/prctl/set-process-name.c +1 −1
  359. tools/testing/selftests/proc/proc-maps-race.c +1 −1
  360. tools/testing/selftests/proc/proc-pid-vm.c +1 −1
  361. tools/testing/selftests/proc/proc-pidns.c +1 −1
  362. tools/testing/selftests/ptrace/get_set_sud.c +1 −1
  363. tools/testing/selftests/ptrace/get_syscall_info.c +1 −1
  364. tools/testing/selftests/ptrace/set_syscall_info.c +1 −1
  365. tools/testing/selftests/ptrace/vmaccess.c +1 −1
  366. tools/testing/selftests/resctrl/resctrl.h +1 −1
  367. tools/testing/selftests/ring-buffer/map_test.c +1 −1
  368. tools/testing/selftests/riscv/abi/pointer_masking.c +1 −1
  369. tools/testing/selftests/riscv/hwprobe/cbo.c +1 −1
  370. tools/testing/selftests/riscv/hwprobe/hwprobe.c +1 −1
  371. tools/testing/selftests/riscv/hwprobe/which-cpus.c +1 −1
  372. tools/testing/selftests/riscv/mm/mmap_bottomup.c +1 −1
  373. tools/testing/selftests/riscv/mm/mmap_default.c +1 −1
  374. tools/testing/selftests/riscv/mm/mmap_test.h +1 −1
  375. tools/testing/selftests/riscv/sigreturn/sigreturn.c +1 −1
  376. tools/testing/selftests/riscv/vector/v_initval.c +1 −1
  377. tools/testing/selftests/riscv/vector/vstate_prctl.c +1 −1
  378. tools/testing/selftests/rseq/basic_percpu_ops_test.c +1 −1
  379. tools/testing/selftests/rseq/rseq.c +1 −1
  380. tools/testing/selftests/rtc/rtctest.c +1 −1
  381. tools/testing/selftests/seccomp/seccomp_benchmark.c +1 −1
  382. tools/testing/selftests/seccomp/seccomp_bpf.c +1 −1
  383. tools/testing/selftests/sgx/main.c +1 −1
  384. tools/testing/selftests/signal/mangle_uc_sigmask.c +1 −1
  385. tools/testing/selftests/signal/sas.c +1 −1
  386. tools/testing/selftests/sparc64/drivers/adi-test.c +1 −1
  387. tools/testing/selftests/sync/sync_test.c +1 −1
  388. tools/testing/selftests/syscall_user_dispatch/sud_test.c +1 −1
  389. tools/testing/selftests/tdx/tdx_guest_test.c +1 −1
  390. tools/testing/selftests/timens/timens.h +1 −1
  391. tools/testing/selftests/timers/adjtick.c +1 −1
  392. tools/testing/selftests/timers/alarmtimer-suspend.c +1 −1
  393. tools/testing/selftests/timers/change_skew.c +1 −1
  394. tools/testing/selftests/timers/clocksource-switch.c +1 −1
  395. tools/testing/selftests/timers/freq-step.c +1 −1
  396. tools/testing/selftests/timers/inconsistency-check.c +1 −1
  397. tools/testing/selftests/timers/leap-a-day.c +1 −1
  398. tools/testing/selftests/timers/leapcrash.c +1 −1
  399. tools/testing/selftests/timers/mqueue-lat.c +1 −1
  400. tools/testing/selftests/timers/nanosleep.c +1 −1
  401. tools/testing/selftests/timers/nsleep-lat.c +1 −1
  402. tools/testing/selftests/timers/posix_timers.c +1 −1
  403. tools/testing/selftests/timers/raw_skew.c +1 −1
  404. tools/testing/selftests/timers/rtcpie.c +1 −1
  405. tools/testing/selftests/timers/set-2038.c +1 −1
  406. tools/testing/selftests/timers/set-tai.c +1 −1
  407. tools/testing/selftests/timers/set-timer-lat.c +1 −1
  408. tools/testing/selftests/timers/set-tz.c +1 −1
  409. tools/testing/selftests/timers/skew_consistency.c +1 −1
  410. tools/testing/selftests/timers/threadtest.c +1 −1
  411. tools/testing/selftests/timers/valid-adjtimex.c +1 −1
  412. tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c +1 −1
  413. tools/testing/selftests/tty/tty_tstamp_update.c +1 −1
  414. tools/testing/selftests/uevent/uevent_filtering.c +1 −1
  415. tools/testing/selftests/user_events/abi_test.c +1 −1
  416. tools/testing/selftests/user_events/dyn_test.c +1 −1
  417. tools/testing/selftests/user_events/ftrace_test.c +1 −1
  418. tools/testing/selftests/user_events/perf_test.c +1 −1
  419. tools/testing/selftests/user_events/user_events_selftests.h +1 −1
  420. tools/testing/selftests/vDSO/vdso_test_abi.c +1 −1
  421. tools/testing/selftests/vDSO/vdso_test_chacha.c +1 −1
  422. tools/testing/selftests/vDSO/vdso_test_correctness.c +1 −1
  423. tools/testing/selftests/vDSO/vdso_test_getcpu.c +1 −1
  424. tools/testing/selftests/vDSO/vdso_test_getrandom.c +1 −1
  425. tools/testing/selftests/vDSO/vdso_test_gettimeofday.c +1 −1
  426. tools/testing/selftests/vfio/lib/vfio_pci_device.c +1 −1
  427. tools/testing/selftests/vfio/lib/vfio_pci_driver.c +1 −1
  428. tools/testing/selftests/vfio/vfio_dma_mapping_test.c +1 −1
  429. tools/testing/selftests/vfio/vfio_iommufd_setup_test.c +1 −1
  430. tools/testing/selftests/vfio/vfio_pci_device_test.c +1 −1
  431. tools/testing/selftests/vfio/vfio_pci_driver_test.c +1 −1
  432. tools/testing/selftests/wireguard/qemu/kernel.config +1 −1
  433. tools/testing/selftests/x86/corrupt_xstate_header.c +1 −1
  434. tools/testing/selftests/x86/helpers.h +1 −1
  435. tools/testing/selftests/x86/lam.c +1 −1
  436. tools/testing/selftests/x86/syscall_numbering.c +1 −1
  437. tools/testing/selftests/x86/test_mremap_vdso.c +1 −1
  438. tools/testing/selftests/x86/test_vsyscall.c +1 −1
  439. tools/testing/selftests/x86/xstate.h +1 −1
.mailmap+6−3
@@ -303,6 +303,7 @@ Hans de Goede <hansg@kernel.org> <hdegoede@redhat.com> · 302 unmodified lines
303Hans Verkuil <hverkuil@kernel.org> <hverkuil@xs4all.nl>303Hans Verkuil <hverkuil@kernel.org> <hverkuil@xs4all.nl>
304Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>304Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>
305Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>305Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
306Hao Ge <hao.ge@linux.dev> <gehao@kylinos.cn>
306Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>307Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
307Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>308Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
308Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>309Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>
@@ -503,9 +504,7 @@ Mark Brown <broonie@sirena.org.uk> · 194 unmodified lines
503Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>504Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>
504Markus Schneider-Pargmann <msp@baylibre.com> <mpa@pengutronix.de>505Markus Schneider-Pargmann <msp@baylibre.com> <mpa@pengutronix.de>
505Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>506Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>
506Martin Kepplinger <martink@posteo.de> <martin.kepplinger@ginzinger.com>507Martin Kepplinger-Novakovic <martink@posteo.de> <martin.kepplinger-novakovic@ginzinger.com>
507Martin Kepplinger <martink@posteo.de> <martin.kepplinger@puri.sm>
508Martin Kepplinger <martink@posteo.de> <martin.kepplinger@theobroma-systems.com>
509Martyna Szapar-Mudlaw <martyna.szapar-mudlaw@linux.intel.com> <martyna.szapar-mudlaw@intel.com>508Martyna Szapar-Mudlaw <martyna.szapar-mudlaw@linux.intel.com> <martyna.szapar-mudlaw@intel.com>
510Mathieu Othacehe <othacehe@gnu.org> <m.othacehe@gmail.com>509Mathieu Othacehe <othacehe@gnu.org> <m.othacehe@gmail.com>
511Mat Martineau <martineau@kernel.org> <mathew.j.martineau@linux.intel.com>510Mat Martineau <martineau@kernel.org> <mathew.j.martineau@linux.intel.com>
@@ -856,6 +855,9 @@ Vivien Didelot <vivien.didelot@gmail.com> <vivien.didelot@savoirfairelinux.com> · 344 unmodified lines
856Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>855Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
857Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>856Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
858Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>857Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
858WangYuli <wangyuli@aosc.io> <wangyl5933@chinaunicom.cn>
859WangYuli <wangyuli@aosc.io> <wangyuli@deepin.org>
860WangYuli <wangyuli@aosc.io> <wangyuli@uniontech.com>
859Weiwen Hu <huweiwen@linux.alibaba.com> <sehuww@mail.scut.edu.cn>861Weiwen Hu <huweiwen@linux.alibaba.com> <sehuww@mail.scut.edu.cn>
860WeiXiong Liao <gmpy.liaowx@gmail.com> <liaoweixiong@allwinnertech.com>862WeiXiong Liao <gmpy.liaowx@gmail.com> <liaoweixiong@allwinnertech.com>
861Wen Gong <quic_wgong@quicinc.com> <wgong@codeaurora.org>863Wen Gong <quic_wgong@quicinc.com> <wgong@codeaurora.org>
@@ -867,6 +869,7 @@ Yakir Yang <kuankuan.y@gmail.com> <ykk@rock-chips.com> · 5 unmodified lines
867Yanteng Si <si.yanteng@linux.dev> <siyanteng@loongson.cn>869Yanteng Si <si.yanteng@linux.dev> <siyanteng@loongson.cn>
868Ying Huang <huang.ying.caritas@gmail.com> <ying.huang@intel.com>870Ying Huang <huang.ying.caritas@gmail.com> <ying.huang@intel.com>
869Yosry Ahmed <yosry.ahmed@linux.dev> <yosryahmed@google.com>871Yosry Ahmed <yosry.ahmed@linux.dev> <yosryahmed@google.com>
872Yu-Chun Lin <eleanor.lin@realtek.com> <eleanor15x@gmail.com>
870Yusuke Goda <goda.yusuke@renesas.com>873Yusuke Goda <goda.yusuke@renesas.com>
871Zack Rusin <zack.rusin@broadcom.com> <zackr@vmware.com>874Zack Rusin <zack.rusin@broadcom.com> <zackr@vmware.com>
872Zhu Yanjun <zyjzyj2000@gmail.com> <yanjunz@nvidia.com>875Zhu Yanjun <zyjzyj2000@gmail.com> <yanjunz@nvidia.com>
CREDITS+4−5
@@ -2056,16 +2056,15 @@ S: Korte Heul 95 · 2055 unmodified lines
2056S: 1403 ND BUSSUM2056S: 1403 ND BUSSUM
2057S: The Netherlands2057S: The Netherlands
2058 2058
2059N: Martin Kepplinger2059N: Martin Kepplinger-Novakovic
2060E: martink@posteo.de2060E: martink@posteo.de
2061E: martin.kepplinger@puri.sm
2062W: http://www.martinkepplinger.com
2063P: 4096R/5AB387D3 F208 2B88 0F9E 4239 3468 6E3F 5003 98DF 5AB3 87D32061P: 4096R/5AB387D3 F208 2B88 0F9E 4239 3468 6E3F 5003 98DF 5AB3 87D3
2064D: mma8452 accelerators iio driver2062D: mma8452 accelerators iio driver
2065D: pegasus_notetaker input driver2063D: pegasus_notetaker input driver
2064D: imx8m media and hi846 sensor driver
2066D: Kernel fixes and cleanups2065D: Kernel fixes and cleanups
2067S: Garnisonstraße 262066S: Keplerstr. 6
2068S: 4020 Linz2067S: 4050 Traun
2069S: Austria2068S: Austria
2070 2069
2071N: Karl Keyte2070N: Karl Keyte
Documentation/ABI/obsolete/sysfs-kernel-kexec-kdump+71−0
@@ -0,0 +1,71 @@
1NOTE: all the ABIs listed in this file are deprecated and will be removed after 2028.
2
3Here are the alternative ABIs:
4+------------------------------------+-----------------------------------------+
5| Deprecated | Alternative |
6+------------------------------------+-----------------------------------------+
7| /sys/kernel/kexec_loaded | /sys/kernel/kexec/loaded |
8+------------------------------------+-----------------------------------------+
9| /sys/kernel/kexec_crash_loaded | /sys/kernel/kexec/crash_loaded |
10+------------------------------------+-----------------------------------------+
11| /sys/kernel/kexec_crash_size | /sys/kernel/kexec/crash_size |
12+------------------------------------+-----------------------------------------+
13| /sys/kernel/crash_elfcorehdr_size | /sys/kernel/kexec/crash_elfcorehdr_size |
14+------------------------------------+-----------------------------------------+
15| /sys/kernel/kexec_crash_cma_ranges | /sys/kernel/kexec/crash_cma_ranges |
16+------------------------------------+-----------------------------------------+
17
18
19What: /sys/kernel/kexec_loaded
20Date: Jun 2006
21Contact: kexec@lists.infradead.org
22Description: read only
23 Indicates whether a new kernel image has been loaded
24 into memory using the kexec system call. It shows 1 if
25 a kexec image is present and ready to boot, or 0 if none
26 is loaded.
27User: kexec tools, kdump service
28
29What: /sys/kernel/kexec_crash_loaded
30Date: Jun 2006
31Contact: kexec@lists.infradead.org
32Description: read only
33 Indicates whether a crash (kdump) kernel is currently
34 loaded into memory. It shows 1 if a crash kernel has been
35 successfully loaded for panic handling, or 0 if no crash
36 kernel is present.
37User: Kexec tools, Kdump service
38
39What: /sys/kernel/kexec_crash_size
40Date: Dec 2009
41Contact: kexec@lists.infradead.org
42Description: read/write
43 Shows the amount of memory reserved for loading the crash
44 (kdump) kernel. It reports the size, in bytes, of the
45 crash kernel area defined by the crashkernel= parameter.
46 This interface also allows reducing the crashkernel
47 reservation by writing a smaller value, and the reclaimed
48 space is added back to the system RAM.
49User: Kdump service
50
51What: /sys/kernel/crash_elfcorehdr_size
52Date: Aug 2023
53Contact: kexec@lists.infradead.org
54Description: read only
55 Indicates the preferred size of the memory buffer for the
56 ELF core header used by the crash (kdump) kernel. It defines
57 how much space is needed to hold metadata about the crashed
58 system, including CPU and memory information. This information
59 is used by the user space utility kexec to support updating the
60 in-kernel kdump image during hotplug operations.
61User: Kexec tools
62
63What: /sys/kernel/kexec_crash_cma_ranges
64Date: Nov 2025
65Contact: kexec@lists.infradead.org
66Description: read only
67 Provides information about the memory ranges reserved from
68 the Contiguous Memory Allocator (CMA) area that are allocated
69 to the crash (kdump) kernel. It lists the start and end physical
70 addresses of CMA regions assigned for crashkernel use.
71User: kdump service
Documentation/ABI/testing/sysfs-kernel-kexec-kdump+61−0
@@ -0,0 +1,61 @@
1What: /sys/kernel/kexec/*
2Date: Nov 2025
3Contact: kexec@lists.infradead.org
4Description:
5 The /sys/kernel/kexec/* directory contains sysfs files
6 that provide information about the configuration status
7 of kexec and kdump.
8
9What: /sys/kernel/kexec/loaded
10Date: Nov 2025
11Contact: kexec@lists.infradead.org
12Description: read only
13 Indicates whether a new kernel image has been loaded
14 into memory using the kexec system call. It shows 1 if
15 a kexec image is present and ready to boot, or 0 if none
16 is loaded.
17User: kexec tools, kdump service
18
19What: /sys/kernel/kexec/crash_loaded
20Date: Nov 2025
21Contact: kexec@lists.infradead.org
22Description: read only
23 Indicates whether a crash (kdump) kernel is currently
24 loaded into memory. It shows 1 if a crash kernel has been
25 successfully loaded for panic handling, or 0 if no crash
26 kernel is present.
27User: Kexec tools, Kdump service
28
29What: /sys/kernel/kexec/crash_size
30Date: Nov 2025
31Contact: kexec@lists.infradead.org
32Description: read/write
33 Shows the amount of memory reserved for loading the crash
34 (kdump) kernel. It reports the size, in bytes, of the
35 crash kernel area defined by the crashkernel= parameter.
36 This interface also allows reducing the crashkernel
37 reservation by writing a smaller value, and the reclaimed
38 space is added back to the system RAM.
39User: Kdump service
40
41What: /sys/kernel/kexec/crash_elfcorehdr_size
42Date: Nov 2025
43Contact: kexec@lists.infradead.org
44Description: read only
45 Indicates the preferred size of the memory buffer for the
46 ELF core header used by the crash (kdump) kernel. It defines
47 how much space is needed to hold metadata about the crashed
48 system, including CPU and memory information. This information
49 is used by the user space utility kexec to support updating the
50 in-kernel kdump image during hotplug operations.
51User: Kexec tools
52
53What: /sys/kernel/kexec/crash_cma_ranges
54Date: Nov 2025
55Contact: kexec@lists.infradead.org
56Description: read only
57 Provides information about the memory ranges reserved from
58 the Contiguous Memory Allocator (CMA) area that are allocated
59 to the crash (kdump) kernel. It lists the start and end physical
60 addresses of CMA regions assigned for crashkernel use.
61User: kdump service
Documentation/admin-guide/dynamic-debug-howto.rst+3−2
@@ -223,12 +223,13 @@ The flags are:: · 222 unmodified lines
223 f Include the function name223 f Include the function name
224 s Include the source file name224 s Include the source file name
225 l Include line number225 l Include line number
226 d Include call trace
226 227
227For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only228For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only
228the ``p`` flag has meaning, other flags are ignored.229the ``p`` flag has meaning, other flags are ignored.
229 230
230Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification.231Note the regexp ``^[-+=][fslmptd_]+$`` matches a flags specification.
231To clear all flags at once, use ``=_`` or ``-fslmpt``.232To clear all flags at once, use ``=_`` or ``-fslmptd``.
232 233
233 234
234Debug messages during Boot Process235Debug messages during Boot Process
Documentation/admin-guide/kernel-parameters.txt+13−7
@@ -2114,14 +2114,20 @@ Kernel parameters · 2113 unmodified lines
2114 the added memory block itself do not be affected.2114 the added memory block itself do not be affected.
2115 2115
2116 hung_task_panic=2116 hung_task_panic=
2117 [KNL] Should the hung task detector generate panics.2117 [KNL] Number of hung tasks to trigger kernel panic.
2118 Format: 0 | 12118 Format: <int>
2119
2120 When set to a non-zero value, a kernel panic will be triggered if
2121 the number of detected hung tasks reaches this value.
2122
2123 0: don't panic
2124 1: panic immediately on first hung task
2125 N: panic after N hung tasks are detected in a single scan
2119 2126
2120 A value of 1 instructs the kernel to panic when a2127 The default value is controlled by the
2121 hung task is detected. The default value is controlled2128 CONFIG_BOOTPARAM_HUNG_TASK_PANIC build-time option. The value
2122 by the CONFIG_BOOTPARAM_HUNG_TASK_PANIC build-time2129 selected by this boot parameter can be changed later by the
2123 option. The value selected by this boot parameter can2130 kernel.hung_task_panic sysctl.
2124 be changed later by the kernel.hung_task_panic sysctl.
2125 2131
2126 hvc_iucv= [S390] Number of z/VM IUCV hypervisor console (HVC)2132 hvc_iucv= [S390] Number of z/VM IUCV hypervisor console (HVC)
2127 terminal devices. Valid values: 0..82133 terminal devices. Valid values: 0..8
Documentation/admin-guide/sysctl/kernel.rst+26−6
@@ -397,13 +397,14 @@ a hung task is detected. · 396 unmodified lines
397hung_task_panic397hung_task_panic
398===============398===============
399 399
400Controls the kernel's behavior when a hung task is detected.400When set to a non-zero value, a kernel panic will be triggered if the
401number of hung tasks found during a single scan reaches this value.
401This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.402This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
402 403
403= =================================================404= =======================================================
4040 Continue operation. This is the default behavior.4050 Continue operation. This is the default behavior.
4051 Panic immediately.406N Panic when N hung tasks are found during a single scan.
406= =================================================407= =======================================================
407 408
408 409
409hung_task_check_count410hung_task_check_count
@@ -421,6 +422,11 @@ the system boot. · 11 unmodified lines
421 422
422This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.423This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
423 424
425hung_task_sys_info
426==================
427A comma separated list of extra system information to be dumped when
428hung task is detected, for example, "tasks,mem,timers,locks,...".
429Refer 'panic_sys_info' section below for more details.
424 430
425hung_task_timeout_secs431hung_task_timeout_secs
426======================432======================
@@ -515,6 +521,15 @@ default), only processes with the CAP_SYS_ADMIN capability may create · 88 unmodified lines
515io_uring instances.521io_uring instances.
516 522
517 523
524kernel_sys_info
525===============
526A comma separated list of extra system information to be dumped when
527soft/hard lockup is detected, for example, "tasks,mem,timers,locks,...".
528Refer 'panic_sys_info' section below for more details.
529
530It serves as the default kernel control knob, which will take effect
531when a kernel module calls sys_info() with parameter==0.
532
518kexec_load_disabled533kexec_load_disabled
519===================534===================
520 535
@@ -576,6 +591,11 @@ if leaking kernel pointer values to unprivileged users is a concern. · 55 unmodified lines
576When ``kptr_restrict`` is set to 2, kernel pointers printed using591When ``kptr_restrict`` is set to 2, kernel pointers printed using
577%pK will be replaced with 0s regardless of privileges.592%pK will be replaced with 0s regardless of privileges.
578 593
594softlockup_sys_info & hardlockup_sys_info
595=========================================
596A comma separated list of extra system information to be dumped when
597soft/hard lockup is detected, for example, "tasks,mem,timers,locks,...".
598Refer 'panic_sys_info' section below for more details.
579 599
580modprobe600modprobe
581========601========
@@ -910,8 +930,8 @@ to 'panic_print'. Possible values are: · 328 unmodified lines
910============= ===================================================930============= ===================================================
911tasks print all tasks info931tasks print all tasks info
912mem print system memory info932mem print system memory info
913timer print timers info933timers print timers info
914lock print locks info if CONFIG_LOCKDEP is on934locks print locks info if CONFIG_LOCKDEP is on
915ftrace print ftrace buffer935ftrace print ftrace buffer
916all_bt print all CPUs backtrace (if available in the arch)936all_bt print all CPUs backtrace (if available in the arch)
917blocked_tasks print only tasks in uninterruptible (blocked) state937blocked_tasks print only tasks in uninterruptible (blocked) state
Documentation/core-api/index.rst+1−0
@@ -138,6 +138,7 @@ Documents that don't fit elsewhere or which have yet to be categorized. · 137 unmodified lines
138 :maxdepth: 1138 :maxdepth: 1
139 139
140 librs140 librs
141 liveupdate
141 netlink142 netlink
142 143
143.. only:: subproject and html144.. only:: subproject and html
Documentation/core-api/kho/concepts.rst+1−1
@@ -70,5 +70,5 @@ in the FDT. That state is called the KHO finalization phase. · 69 unmodified lines
70 70
71Public API71Public API
72==========72==========
73.. kernel-doc:: kernel/kexec_handover.c73.. kernel-doc:: kernel/liveupdate/kexec_handover.c
74 :export:74 :export:
Documentation/core-api/liveupdate.rst+61−0
@@ -0,0 +1,61 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3========================
4Live Update Orchestrator
5========================
6:Author: Pasha Tatashin <pasha.tatashin@soleen.com>
7
8.. kernel-doc:: kernel/liveupdate/luo_core.c
9 :doc: Live Update Orchestrator (LUO)
10
11LUO Sessions
12============
13.. kernel-doc:: kernel/liveupdate/luo_session.c
14 :doc: LUO Sessions
15
16LUO Preserving File Descriptors
17===============================
18.. kernel-doc:: kernel/liveupdate/luo_file.c
19 :doc: LUO File Descriptors
20
21Live Update Orchestrator ABI
22============================
23.. kernel-doc:: include/linux/kho/abi/luo.h
24 :doc: Live Update Orchestrator ABI
25
26The following types of file descriptors can be preserved
27
28.. toctree::
29 :maxdepth: 1
30
31 ../mm/memfd_preservation
32
33Public API
34==========
35.. kernel-doc:: include/linux/liveupdate.h
36
37.. kernel-doc:: include/linux/kho/abi/luo.h
38 :functions:
39
40.. kernel-doc:: kernel/liveupdate/luo_core.c
41 :export:
42
43.. kernel-doc:: kernel/liveupdate/luo_file.c
44 :export:
45
46Internal API
47============
48.. kernel-doc:: kernel/liveupdate/luo_core.c
49 :internal:
50
51.. kernel-doc:: kernel/liveupdate/luo_session.c
52 :internal:
53
54.. kernel-doc:: kernel/liveupdate/luo_file.c
55 :internal:
56
57See Also
58========
59
60- :doc:`Live Update uAPI </userspace-api/liveupdate>`
61- :doc:`/core-api/kho/concepts`
Documentation/dev-tools/checkpatch.rst+10−0
@@ -1238,6 +1238,16 @@ Others · 1237 unmodified lines
1238 The patch file does not appear to be in unified-diff format. Please1238 The patch file does not appear to be in unified-diff format. Please
1239 regenerate the patch file before sending it to the maintainer.1239 regenerate the patch file before sending it to the maintainer.
1240 1240
1241 **PLACEHOLDER_USE**
1242 Detects unhandled placeholder text left in cover letters or commit headers/logs.
1243 Common placeholders include lines like::
1244
1245 *** SUBJECT HERE ***
1246 *** BLURB HERE ***
1247
1248 These typically come from autogenerated templates. Replace them with a proper
1249 subject and description before sending.
1250
1241 **PRINTF_0XDECIMAL**1251 **PRINTF_0XDECIMAL**
1242 Prefixing 0x with decimal output is defective and should be corrected.1252 Prefixing 0x with decimal output is defective and should be corrected.
1243 1253
Documentation/driver-api/hw-recoverable-errors.rst+60−0
@@ -0,0 +1,60 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3=================================================
4Recoverable Hardware Error Tracking in vmcoreinfo
5=================================================
6
7Overview
8--------
9
10This feature provides a generic infrastructure within the Linux kernel to track
11and log recoverable hardware errors. These are hardware recoverable errors
12visible that might not cause immediate panics but may influence health, mainly
13because new code path will be executed in the kernel.
14
15By recording counts and timestamps of recoverable errors into the vmcoreinfo
16crash dump notes, this infrastructure aids post-mortem crash analysis tools in
17correlating hardware events with kernel failures. This enables faster triage
18and better understanding of root causes, especially in large-scale cloud
19environments where hardware issues are common.
20
21Benefits
22--------
23
24- Facilitates correlation of hardware recoverable errors with kernel panics or
25 unusual code paths that lead to system crashes.
26- Provides operators and cloud providers quick insights, improving reliability
27 and reducing troubleshooting time.
28- Complements existing full hardware diagnostics without replacing them.
29
30Data Exposure and Consumption
31-----------------------------
32
33- The tracked error data consists of per-error-type counts and timestamps of
34 last occurrence.
35- This data is stored in the `hwerror_data` array, categorized by error source
36 types like CPU, memory, PCI, CXL, and others.
37- It is exposed via vmcoreinfo crash dump notes and can be read using tools
38 like `crash`, `drgn`, or other kernel crash analysis utilities.
39- There is no other way to read these data other than from crash dumps.
40- These errors are divided by area, which includes CPU, Memory, PCI, CXL and
41 others.
42
43Typical usage example (in drgn REPL):
44
45.. code-block:: python
46
47 >>> prog['hwerror_data']
48 (struct hwerror_info[HWERR_RECOV_MAX]){
49 {
50 .count = (int)844,
51 .timestamp = (time64_t)1752852018,
52 },
53 ...
54 }
55
56Enabling
57--------
58
59- This feature is enabled when CONFIG_VMCORE_INFO is set.
60
Documentation/driver-api/index.rst+1−0
@@ -97,6 +97,7 @@ Subsystem-specific APIs · 96 unmodified lines
97 gpio/index97 gpio/index
98 hsi98 hsi
99 hte/index99 hte/index
100 hw-recoverable-errors
100 i2c101 i2c
101 iio/index102 iio/index
102 infiniband103 infiniband
Documentation/mm/index.rst+1−0
@@ -48,6 +48,7 @@ documentation, or deleted if it has served its purpose. · 47 unmodified lines
48 hugetlbfs_reserv48 hugetlbfs_reserv
49 ksm49 ksm
50 memory-model50 memory-model
51 memfd_preservation
51 mmu_notifier52 mmu_notifier
52 multigen_lru53 multigen_lru
53 numa54 numa
Documentation/mm/memfd_preservation.rst+23−0
@@ -0,0 +1,23 @@
1.. SPDX-License-Identifier: GPL-2.0-or-later
2
3==========================
4Memfd Preservation via LUO
5==========================
6
7.. kernel-doc:: mm/memfd_luo.c
8 :doc: Memfd Preservation via LUO
9
10Memfd Preservation ABI
11======================
12
13.. kernel-doc:: include/linux/kho/abi/memfd.h
14 :doc: DOC: memfd Live Update ABI
15
16.. kernel-doc:: include/linux/kho/abi/memfd.h
17 :internal:
18
19See Also
20========
21
22- :doc:`/core-api/liveupdate`
23- :doc:`/core-api/kho/concepts`
Documentation/userspace-api/index.rst+1−0
@@ -61,6 +61,7 @@ Everything else · 60 unmodified lines
61 :maxdepth: 161 :maxdepth: 1
62 62
63 ELF63 ELF
64 liveupdate
64 netlink/index65 netlink/index
65 sysfs-platform_profile66 sysfs-platform_profile
66 vduse67 vduse
Documentation/userspace-api/ioctl/ioctl-number.rst+2−0
@@ -385,6 +385,8 @@ Code Seq# Include File Comments · 384 unmodified lines
3850xB8 01-02 uapi/misc/mrvl_cn10k_dpi.h Marvell CN10K DPI driver3850xB8 01-02 uapi/misc/mrvl_cn10k_dpi.h Marvell CN10K DPI driver
3860xB8 all uapi/linux/mshv.h Microsoft Hyper-V /dev/mshv driver3860xB8 all uapi/linux/mshv.h Microsoft Hyper-V /dev/mshv driver
387 <mailto:linux-hyperv@vger.kernel.org>387 <mailto:linux-hyperv@vger.kernel.org>
3880xBA 00-0F uapi/linux/liveupdate.h Pasha Tatashin
389 <mailto:pasha.tatashin@soleen.com>
3880xC0 00-0F linux/usb/iowarrior.h3900xC0 00-0F linux/usb/iowarrior.h
3890xCA 00-0F uapi/misc/cxl.h Dead since 6.153910xCA 00-0F uapi/misc/cxl.h Dead since 6.15
3900xCA 10-2F uapi/misc/ocxl.h3920xCA 10-2F uapi/misc/ocxl.h
Documentation/userspace-api/liveupdate.rst+20−0
@@ -0,0 +1,20 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3================
4Live Update uAPI
5================
6:Author: Pasha Tatashin <pasha.tatashin@soleen.com>
7
8ioctl interface
9===============
10.. kernel-doc:: kernel/liveupdate/luo_core.c
11 :doc: LUO ioctl Interface
12
13ioctl uAPI
14===========
15.. kernel-doc:: include/uapi/linux/liveupdate.h
16
17See Also
18========
19
20- :doc:`Live Update Orchestrator </core-api/liveupdate>`
MAINTAINERS+26−8
@@ -11659,7 +11659,7 @@ T: git git://linuxtv.org/media.git · 11658 unmodified lines
11659F: drivers/media/i2c/hi556.c11659F: drivers/media/i2c/hi556.c
11660 11660
11661HYNIX HI846 SENSOR DRIVER11661HYNIX HI846 SENSOR DRIVER
11662M: Martin Kepplinger <martin.kepplinger@puri.sm>11662M: Martin Kepplinger-Novakovic <martink@posteo.de>
11663L: linux-media@vger.kernel.org11663L: linux-media@vger.kernel.org
11664S: Maintained11664S: Maintained
11665F: drivers/media/i2c/hi846.c11665F: drivers/media/i2c/hi846.c
@@ -11744,6 +11744,7 @@ HUNG TASK DETECTOR · 78 unmodified lines
11744M: Andrew Morton <akpm@linux-foundation.org>11744M: Andrew Morton <akpm@linux-foundation.org>
11745R: Lance Yang <lance.yang@linux.dev>11745R: Lance Yang <lance.yang@linux.dev>
11746R: Masami Hiramatsu <mhiramat@kernel.org>11746R: Masami Hiramatsu <mhiramat@kernel.org>
11747R: Petr Mladek <pmladek@suse.com>
11747L: linux-kernel@vger.kernel.org11748L: linux-kernel@vger.kernel.org
11748S: Maintained11749S: Maintained
11749F: include/linux/hung_task.h11750F: include/linux/hung_task.h
@@ -13891,14 +13892,15 @@ F: kernel/kexec* · 2141 unmodified lines
13891KEXEC HANDOVER (KHO)13892KEXEC HANDOVER (KHO)
13892M: Alexander Graf <graf@amazon.com>13893M: Alexander Graf <graf@amazon.com>
13893M: Mike Rapoport <rppt@kernel.org>13894M: Mike Rapoport <rppt@kernel.org>
13894M: Changyuan Lyu <changyuanl@google.com>13895M: Pasha Tatashin <pasha.tatashin@soleen.com>
13896R: Pratyush Yadav <pratyush@kernel.org>
13895L: kexec@lists.infradead.org13897L: kexec@lists.infradead.org
13896L: linux-mm@kvack.org13898L: linux-mm@kvack.org
13897S: Maintained13899S: Maintained
13898F: Documentation/admin-guide/mm/kho.rst13900F: Documentation/admin-guide/mm/kho.rst
13899F: Documentation/core-api/kho/*13901F: Documentation/core-api/kho/*
13900F: include/linux/kexec_handover.h13902F: include/linux/kexec_handover.h
13901F: kernel/kexec_handover.c13903F: kernel/liveupdate/kexec_handover*
13902F: lib/test_kho.c13904F: lib/test_kho.c
13903F: tools/testing/selftests/kho/13905F: tools/testing/selftests/kho/
13904 13906
@@ -14567,6 +14569,22 @@ F: samples/livepatch/ · 662 unmodified lines
14567F: scripts/livepatch/14569F: scripts/livepatch/
14568F: tools/testing/selftests/livepatch/14570F: tools/testing/selftests/livepatch/
14569 14571
14572LIVE UPDATE
14573M: Pasha Tatashin <pasha.tatashin@soleen.com>
14574M: Mike Rapoport <rppt@kernel.org>
14575R: Pratyush Yadav <pratyush@kernel.org>
14576L: linux-kernel@vger.kernel.org
14577S: Maintained
14578F: Documentation/core-api/liveupdate.rst
14579F: Documentation/mm/memfd_preservation.rst
14580F: Documentation/userspace-api/liveupdate.rst
14581F: include/linux/liveupdate.h
14582F: include/linux/liveupdate/
14583F: include/uapi/linux/liveupdate.h
14584F: kernel/liveupdate/
14585F: mm/memfd_luo.c
14586F: tools/testing/selftests/liveupdate/
14587
14570LLC (802.2)14588LLC (802.2)
14571L: netdev@vger.kernel.org14589L: netdev@vger.kernel.org
14572S: Odd fixes14590S: Odd fixes
@@ -15668,7 +15686,7 @@ F: include/media/imx.h · 1095 unmodified lines
15668MEDIA DRIVERS FOR FREESCALE IMX7/815686MEDIA DRIVERS FOR FREESCALE IMX7/8
15669M: Rui Miguel Silva <rmfrfs@gmail.com>15687M: Rui Miguel Silva <rmfrfs@gmail.com>
15670M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>15688M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
15671M: Martin Kepplinger <martin.kepplinger@puri.sm>15689M: Martin Kepplinger-Novakovic <martink@posteo.de>
15672R: Purism Kernel Team <kernel@puri.sm>15690R: Purism Kernel Team <kernel@puri.sm>
15673R: Frank Li <Frank.Li@nxp.com>15691R: Frank Li <Frank.Li@nxp.com>
15674L: imx@lists.linux.dev15692L: imx@lists.linux.dev
@@ -18420,10 +18438,11 @@ F: net/sunrpc/ · 2745 unmodified lines
18420 18438
18421NILFS2 FILESYSTEM18439NILFS2 FILESYSTEM
18422M: Ryusuke Konishi <konishi.ryusuke@gmail.com>18440M: Ryusuke Konishi <konishi.ryusuke@gmail.com>
18441M: Viacheslav Dubeyko <slava@dubeyko.com>
18423L: linux-nilfs@vger.kernel.org18442L: linux-nilfs@vger.kernel.org
18424S: Supported18443S: Maintained
18425W: https://nilfs.sourceforge.io/18444W: https://nilfs.sourceforge.io/
18426T: git https://github.com/konis/nilfs2.git18445T: git git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/nilfs2.git
18427F: Documentation/filesystems/nilfs2.rst18446F: Documentation/filesystems/nilfs2.rst
18428F: fs/nilfs2/18447F: fs/nilfs2/
18429F: include/trace/events/nilfs2.h18448F: include/trace/events/nilfs2.h
@@ -25103,7 +25122,6 @@ F: drivers/regulator/sy8106a-regulator.c · 6673 unmodified lines
25103 25122
25104SYNC FILE FRAMEWORK25123SYNC FILE FRAMEWORK
25105M: Sumit Semwal <sumit.semwal@linaro.org>25124M: Sumit Semwal <sumit.semwal@linaro.org>
25106R: Gustavo Padovan <gustavo@padovan.org>
25107L: linux-media@vger.kernel.org25125L: linux-media@vger.kernel.org
25108L: dri-devel@lists.freedesktop.org25126L: dri-devel@lists.freedesktop.org
25109S: Maintained25127S: Maintained
@@ -26308,7 +26326,7 @@ M: Jarkko Sakkinen <jarkko@kernel.org> · 1198 unmodified lines
26308R: Jason Gunthorpe <jgg@ziepe.ca>26326R: Jason Gunthorpe <jgg@ziepe.ca>
26309L: linux-integrity@vger.kernel.org26327L: linux-integrity@vger.kernel.org
26310S: Maintained26328S: Maintained
26311W: https://codeberg.org/jarkko/linux-tpmdd-test26329W: https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd-test.git/about/
26312Q: https://patchwork.kernel.org/project/linux-integrity/list/26330Q: https://patchwork.kernel.org/project/linux-integrity/list/
26313T: git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git26331T: git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git
26314F: Documentation/devicetree/bindings/tpm/26332F: Documentation/devicetree/bindings/tpm/
arch/Kconfig+8−11
@@ -232,17 +232,14 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS · 231 unmodified lines
232config ARCH_USE_BUILTIN_BSWAP232config ARCH_USE_BUILTIN_BSWAP
233 bool233 bool
234 help234 help
235 Modern versions of GCC (since 4.4) have builtin functions235 GCC and Clang have builtin functions for handling byte-swapping.
236 for handling byte-swapping. Using these, instead of the old236 Using these allows the compiler to see what's happening and
237 inline assembler that the architecture code provides in the237 offers more opportunity for optimisation. In particular, the
238 __arch_bswapXX() macros, allows the compiler to see what's238 compiler will be able to combine the byteswap with a nearby load
239 happening and offers more opportunity for optimisation. In239 or store and use load-and-swap or store-and-swap instructions if
240 particular, the compiler will be able to combine the byteswap240 the architecture has them. It should almost *never* result in code
241 with a nearby load or store and use load-and-swap or241 which is worse than the hand-coded assembler in <asm/swab.h>.
242 store-and-swap instructions if the architecture has them. It242 But just in case it does, the use of the builtins is optional.
243 should almost *never* result in code which is worse than the
244 hand-coded assembler in <asm/swab.h>. But just in case it
245 does, the use of the builtins is optional.
246 243
247 Any architecture with load-and-swap or store-and-swap244 Any architecture with load-and-swap or store-and-swap
248 instructions should set this. And it shouldn't hurt to set it245 instructions should set this. And it shouldn't hurt to set it
arch/arm/Kconfig+0−2
@@ -1161,8 +1161,6 @@ config AEABI · 1160 unmodified lines
1161 disambiguate both ABIs and allow for backward compatibility support1161 disambiguate both ABIs and allow for backward compatibility support
1162 (selected with CONFIG_OABI_COMPAT).1162 (selected with CONFIG_OABI_COMPAT).
1163 1163
1164 To use this you need GCC version 4.0.0 or later.
1165
1166config OABI_COMPAT1164config OABI_COMPAT
1167 bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"1165 bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"
1168 depends on AEABI && !THUMB2_KERNEL1166 depends on AEABI && !THUMB2_KERNEL
arch/arm/configs/aspeed_g5_defconfig+1−1
@@ -308,7 +308,7 @@ CONFIG_PANIC_ON_OOPS=y · 307 unmodified lines
308CONFIG_PANIC_TIMEOUT=-1308CONFIG_PANIC_TIMEOUT=-1
309CONFIG_SOFTLOCKUP_DETECTOR=y309CONFIG_SOFTLOCKUP_DETECTOR=y
310CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y310CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
311CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y311CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1
312CONFIG_WQ_WATCHDOG=y312CONFIG_WQ_WATCHDOG=y
313# CONFIG_SCHED_DEBUG is not set313# CONFIG_SCHED_DEBUG is not set
314CONFIG_FUNCTION_TRACER=y314CONFIG_FUNCTION_TRACER=y
arch/powerpc/include/asm/crash_reserve.h+8−0
@@ -5,4 +5,12 @@ · 4 unmodified lines
5/* crash kernel regions are Page size agliged */5/* crash kernel regions are Page size agliged */
6#define CRASH_ALIGN PAGE_SIZE6#define CRASH_ALIGN PAGE_SIZE
7 7
8#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
9static inline bool arch_add_crash_res_to_iomem(void)
10{
11 return false;
12}
13#define arch_add_crash_res_to_iomem arch_add_crash_res_to_iomem
14#endif
15
8#endif /* _ASM_POWERPC_CRASH_RESERVE_H */16#endif /* _ASM_POWERPC_CRASH_RESERVE_H */
arch/x86/include/asm/div64.h+31−8
@@ -60,6 +60,12 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) · 59 unmodified lines
60}60}
61#define div_u64_rem div_u64_rem61#define div_u64_rem div_u64_rem
62 62
63/*
64 * gcc tends to zero extend 32bit values and do full 64bit maths.
65 * Define asm functions that avoid this.
66 * (clang generates better code for the C versions.)
67 */
68#ifndef __clang__
63static inline u64 mul_u32_u32(u32 a, u32 b)69static inline u64 mul_u32_u32(u32 a, u32 b)
64{70{
65 u32 high, low;71 u32 high, low;
@@ -71,6 +77,19 @@ static inline u64 mul_u32_u32(u32 a, u32 b) · 5 unmodified lines
71}77}
72#define mul_u32_u32 mul_u32_u3278#define mul_u32_u32 mul_u32_u32
73 79
80static inline u64 add_u64_u32(u64 a, u32 b)
81{
82 u32 high = a >> 32, low = a;
83
84 asm ("addl %[b], %[low]; adcl $0, %[high]"
85 : [low] "+r" (low), [high] "+r" (high)
86 : [b] "rm" (b) );
87
88 return low | (u64)high << 32;
89}
90#define add_u64_u32 add_u64_u32
91#endif
92
74/*93/*
75 * __div64_32() is never called on x86, so prevent the94 * __div64_32() is never called on x86, so prevent the
76 * generic definition from getting built.95 * generic definition from getting built.
@@ -84,21 +103,25 @@ static inline u64 mul_u32_u32(u32 a, u32 b) · 7 unmodified lines
84 * Will generate an #DE when the result doesn't fit u64, could fix with an103 * Will generate an #DE when the result doesn't fit u64, could fix with an
85 * __ex_table[] entry when it becomes an issue.104 * __ex_table[] entry when it becomes an issue.
86 */105 */
87static inline u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div)106static inline u64 mul_u64_add_u64_div_u64(u64 rax, u64 mul, u64 add, u64 div)
88{107{
89 u64 q;108 u64 rdx;
109
110 asm ("mulq %[mul]" : "+a" (rax), "=d" (rdx) : [mul] "rm" (mul));
111
112 if (!statically_true(!add))
113 asm ("addq %[add], %[lo]; adcq $0, %[hi]" :
114 [lo] "+r" (rax), [hi] "+r" (rdx) : [add] "irm" (add));
90 115
91 asm ("mulq %2; divq %3" : "=a" (q)116 asm ("divq %[div]" : "+a" (rax), "+d" (rdx) : [div] "rm" (div));
92 : "a" (a), "rm" (mul), "rm" (div)
93 : "rdx");
94 117
95 return q;118 return rax;
96}119}
97#define mul_u64_u64_div_u64 mul_u64_u64_div_u64120#define mul_u64_add_u64_div_u64 mul_u64_add_u64_div_u64
98 121
99static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div)122static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div)
100{123{
101 return mul_u64_u64_div_u64(a, mul, div);124 return mul_u64_add_u64_div_u64(a, mul, 0, div);
102}125}
103#define mul_u64_u32_div mul_u64_u32_div126#define mul_u64_u32_div mul_u64_u32_div
104 127
arch/x86/kernel/cpu/mce/core.c+4−0
@@ -45,6 +45,7 @@ · 44 unmodified lines
45#include <linux/task_work.h>45#include <linux/task_work.h>
46#include <linux/hardirq.h>46#include <linux/hardirq.h>
47#include <linux/kexec.h>47#include <linux/kexec.h>
48#include <linux/vmcore_info.h>
48 49
49#include <asm/fred.h>50#include <asm/fred.h>
50#include <asm/cpu_device_id.h>51#include <asm/cpu_device_id.h>
@@ -1729,6 +1730,9 @@ noinstr void do_machine_check(struct pt_regs *regs) · 1678 unmodified lines
1729 }1730 }
1730 1731
1731out:1732out:
1733 /* Given it didn't panic, mark it as recoverable */
1734 hwerr_log_error_type(HWERR_RECOV_OTHERS);
1735
1732 instrumentation_end();1736 instrumentation_end();
1733 1737
1734clear:1738clear:
drivers/acpi/apei/ghes.c+36−0
@@ -44,6 +44,7 @@ · 43 unmodified lines
44#include <linux/uuid.h>44#include <linux/uuid.h>
45#include <linux/ras.h>45#include <linux/ras.h>
46#include <linux/task_work.h>46#include <linux/task_work.h>
47#include <linux/vmcore_info.h>
47 48
48#include <acpi/actbl1.h>49#include <acpi/actbl1.h>
49#include <acpi/ghes.h>50#include <acpi/ghes.h>
@@ -864,6 +865,40 @@ int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd) · 814 unmodified lines
864}865}
865EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL");866EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL");
866 867
868static void ghes_log_hwerr(int sev, guid_t *sec_type)
869{
870 if (sev != CPER_SEV_RECOVERABLE)
871 return;
872
873 if (guid_equal(sec_type, &CPER_SEC_PROC_ARM) ||
874 guid_equal(sec_type, &CPER_SEC_PROC_GENERIC) ||
875 guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
876 hwerr_log_error_type(HWERR_RECOV_CPU);
877 return;
878 }
879
880 if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR) ||
881 guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID) ||
882 guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID) ||
883 guid_equal(sec_type, &CPER_SEC_CXL_MEM_MODULE_GUID)) {
884 hwerr_log_error_type(HWERR_RECOV_CXL);
885 return;
886 }
887
888 if (guid_equal(sec_type, &CPER_SEC_PCIE) ||
889 guid_equal(sec_type, &CPER_SEC_PCI_X_BUS)) {
890 hwerr_log_error_type(HWERR_RECOV_PCI);
891 return;
892 }
893
894 if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
895 hwerr_log_error_type(HWERR_RECOV_MEMORY);
896 return;
897 }
898
899 hwerr_log_error_type(HWERR_RECOV_OTHERS);
900}
901
867static void ghes_do_proc(struct ghes *ghes,902static void ghes_do_proc(struct ghes *ghes,
868 const struct acpi_hest_generic_status *estatus)903 const struct acpi_hest_generic_status *estatus)
869{904{
@@ -885,6 +920,7 @@ static void ghes_do_proc(struct ghes *ghes, · 15 unmodified lines
885 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)920 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
886 fru_text = gdata->fru_text;921 fru_text = gdata->fru_text;
887 922
923 ghes_log_hwerr(sev, sec_type);
888 if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {924 if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
889 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);925 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
890 926
drivers/nvme/common/auth.c+2−2
@@ -178,7 +178,7 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret, · 177 unmodified lines
178 if (!key)178 if (!key)
179 return ERR_PTR(-ENOMEM);179 return ERR_PTR(-ENOMEM);
180 180
181 key_len = base64_decode(secret, allocated_len, key->key);181 key_len = base64_decode(secret, allocated_len, key->key, true, BASE64_STD);
182 if (key_len < 0) {182 if (key_len < 0) {
183 pr_debug("base64 key decoding error %d\n",183 pr_debug("base64 key decoding error %d\n",
184 key_len);184 key_len);
@@ -663,7 +663,7 @@ int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size_t psk_len, · 478 unmodified lines
663 if (ret)663 if (ret)
664 goto out_free_digest;664 goto out_free_digest;
665 665
666 ret = base64_encode(digest, digest_len, enc);666 ret = base64_encode(digest, digest_len, enc, true, BASE64_STD);
667 if (ret < hmac_len) {667 if (ret < hmac_len) {
668 ret = -ENOKEY;668 ret = -ENOKEY;
669 goto out_free_digest;669 goto out_free_digest;
drivers/pci/pcie/aer.c+2−0
@@ -30,6 +30,7 @@ · 29 unmodified lines
30#include <linux/kfifo.h>30#include <linux/kfifo.h>
31#include <linux/ratelimit.h>31#include <linux/ratelimit.h>
32#include <linux/slab.h>32#include <linux/slab.h>
33#include <linux/vmcore_info.h>
33#include <acpi/apei.h>34#include <acpi/apei.h>
34#include <acpi/ghes.h>35#include <acpi/ghes.h>
35#include <ras/ras_event.h>36#include <ras/ras_event.h>
@@ -765,6 +766,7 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev, · 729 unmodified lines
765 break;766 break;
766 case AER_NONFATAL:767 case AER_NONFATAL:
767 aer_info->dev_total_nonfatal_errs++;768 aer_info->dev_total_nonfatal_errs++;
769 hwerr_log_error_type(HWERR_RECOV_PCI);
768 counter = &aer_info->dev_nonfatal_errs[0];770 counter = &aer_info->dev_nonfatal_errs[0];
769 max = AER_MAX_TYPEOF_UNCOR_ERRS;771 max = AER_MAX_TYPEOF_UNCOR_ERRS;
770 break;772 break;
fs/ceph/crypto.c+4−56
@@ -15,59 +15,6 @@ · 14 unmodified lines
15#include "mds_client.h"15#include "mds_client.h"
16#include "crypto.h"16#include "crypto.h"
17 17
18/*
19 * The base64url encoding used by fscrypt includes the '_' character, which may
20 * cause problems in snapshot names (which can not start with '_'). Thus, we
21 * used the base64 encoding defined for IMAP mailbox names (RFC 3501) instead,
22 * which replaces '-' and '_' by '+' and ','.
23 */
24static const char base64_table[65] =
25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
26
27int ceph_base64_encode(const u8 *src, int srclen, char *dst)
28{
29 u32 ac = 0;
30 int bits = 0;
31 int i;
32 char *cp = dst;
33
34 for (i = 0; i < srclen; i++) {
35 ac = (ac << 8) | src[i];
36 bits += 8;
37 do {
38 bits -= 6;
39 *cp++ = base64_table[(ac >> bits) & 0x3f];
40 } while (bits >= 6);
41 }
42 if (bits)
43 *cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
44 return cp - dst;
45}
46
47int ceph_base64_decode(const char *src, int srclen, u8 *dst)
48{
49 u32 ac = 0;
50 int bits = 0;
51 int i;
52 u8 *bp = dst;
53
54 for (i = 0; i < srclen; i++) {
55 const char *p = strchr(base64_table, src[i]);
56
57 if (p == NULL || src[i] == 0)
58 return -1;
59 ac = (ac << 6) | (p - base64_table);
60 bits += 6;
61 if (bits >= 8) {
62 bits -= 8;
63 *bp++ = (u8)(ac >> bits);
64 }
65 }
66 if (ac & ((1 << bits) - 1))
67 return -1;
68 return bp - dst;
69}
70
71static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len)18static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len)
72{19{
73 struct ceph_inode_info *ci = ceph_inode(inode);20 struct ceph_inode_info *ci = ceph_inode(inode);
@@ -318,7 +265,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen) · 244 unmodified lines
318 }265 }
319 266
320 /* base64 encode the encrypted name */267 /* base64 encode the encrypted name */
321 elen = ceph_base64_encode(cryptbuf, len, p);268 elen = base64_encode(cryptbuf, len, p, false, BASE64_IMAP);
322 doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);269 doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
323 270
324 /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */271 /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
@@ -412,7 +359,8 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname, · 87 unmodified lines
412 tname = &_tname;359 tname = &_tname;
413 }360 }
414 361
415 declen = ceph_base64_decode(name, name_len, tname->name);362 declen = base64_decode(name, name_len,
363 tname->name, false, BASE64_IMAP);
416 if (declen <= 0) {364 if (declen <= 0) {
417 ret = -EIO;365 ret = -EIO;
418 goto out;366 goto out;
@@ -426,7 +374,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname, · 7 unmodified lines
426 374
427 ret = fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname);375 ret = fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname);
428 if (!ret && (dir != fname->dir)) {376 if (!ret && (dir != fname->dir)) {
429 char tmp_buf[CEPH_BASE64_CHARS(NAME_MAX)];377 char tmp_buf[BASE64_CHARS(NAME_MAX)];
430 378
431 name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",379 name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
432 oname->len, oname->name, dir->i_ino);380 oname->len, oname->name, dir->i_ino);
fs/ceph/crypto.h+1−5
@@ -8,6 +8,7 @@ · 7 unmodified lines
8 8
9#include <crypto/sha2.h>9#include <crypto/sha2.h>
10#include <linux/fscrypt.h>10#include <linux/fscrypt.h>
11#include <linux/base64.h>
11 12
12#define CEPH_FSCRYPT_BLOCK_SHIFT 1213#define CEPH_FSCRYPT_BLOCK_SHIFT 12
13#define CEPH_FSCRYPT_BLOCK_SIZE (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT)14#define CEPH_FSCRYPT_BLOCK_SIZE (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT)
@@ -89,11 +90,6 @@ static inline u32 ceph_fscrypt_auth_len(struct ceph_fscrypt_auth *fa) · 75 unmodified lines
89 */90 */
90#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE)91#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE)
91 92
92#define CEPH_BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
93
94int ceph_base64_encode(const u8 *src, int srclen, char *dst);
95int ceph_base64_decode(const char *src, int srclen, u8 *dst);
96
97void ceph_fscrypt_set_ops(struct super_block *sb);93void ceph_fscrypt_set_ops(struct super_block *sb);
98 94
99void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc);95void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc);
fs/ceph/dir.c+3−2
@@ -998,13 +998,14 @@ static int prep_encrypted_symlink_target(struct ceph_mds_request *req, · 997 unmodified lines
998 if (err)998 if (err)
999 goto out;999 goto out;
1000 1000
1001 req->r_path2 = kmalloc(CEPH_BASE64_CHARS(osd_link.len) + 1, GFP_KERNEL);1001 req->r_path2 = kmalloc(BASE64_CHARS(osd_link.len) + 1, GFP_KERNEL);
1002 if (!req->r_path2) {1002 if (!req->r_path2) {
1003 err = -ENOMEM;1003 err = -ENOMEM;
1004 goto out;1004 goto out;
1005 }1005 }
1006 1006
1007 len = ceph_base64_encode(osd_link.name, osd_link.len, req->r_path2);1007 len = base64_encode(osd_link.name, osd_link.len,
1008 req->r_path2, false, BASE64_IMAP);
1008 req->r_path2[len] = '\0';1009 req->r_path2[len] = '\0';
1009out:1010out:
1010 fscrypt_fname_free_buffer(&osd_link);1011 fscrypt_fname_free_buffer(&osd_link);
fs/ceph/inode.c+1−1
@@ -947,7 +947,7 @@ static int decode_encrypted_symlink(struct ceph_mds_client *mdsc, · 946 unmodified lines
947 if (!sym)947 if (!sym)
948 return -ENOMEM;948 return -ENOMEM;
949 949
950 declen = ceph_base64_decode(encsym, enclen, sym);950 declen = base64_decode(encsym, enclen, sym, false, BASE64_IMAP);
951 if (declen < 0) {951 if (declen < 0) {
952 pr_err_client(cl,952 pr_err_client(cl,
953 "can't decode symlink (%d). Content: %.*s\n",953 "can't decode symlink (%d). Content: %.*s\n",
fs/crypto/fname.c+6−83
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#include <linux/export.h>16#include <linux/export.h>
17#include <linux/namei.h>17#include <linux/namei.h>
18#include <linux/scatterlist.h>18#include <linux/scatterlist.h>
19#include <linux/base64.h>
19 20
20#include "fscrypt_private.h"21#include "fscrypt_private.h"
21 22
@@ -71,7 +72,7 @@ struct fscrypt_nokey_name { · 49 unmodified lines
71 72
72/* Encoded size of max-size no-key name */73/* Encoded size of max-size no-key name */
73#define FSCRYPT_NOKEY_NAME_MAX_ENCODED \74#define FSCRYPT_NOKEY_NAME_MAX_ENCODED \
74 FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX)75 BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX)
75 76
76static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)77static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
77{78{
@@ -162,84 +163,6 @@ static int fname_decrypt(const struct inode *inode, · 84 unmodified lines
162 return 0;163 return 0;
163}164}
164 165
165static const char base64url_table[65] =
166 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
167
168#define FSCRYPT_BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
169
170/**
171 * fscrypt_base64url_encode() - base64url-encode some binary data
172 * @src: the binary data to encode
173 * @srclen: the length of @src in bytes
174 * @dst: (output) the base64url-encoded string. Not NUL-terminated.
175 *
176 * Encodes data using base64url encoding, i.e. the "Base 64 Encoding with URL
177 * and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used,
178 * as it's unneeded and not required by the RFC. base64url is used instead of
179 * base64 to avoid the '/' character, which isn't allowed in filenames.
180 *
181 * Return: the length of the resulting base64url-encoded string in bytes.
182 * This will be equal to FSCRYPT_BASE64URL_CHARS(srclen).
183 */
184static int fscrypt_base64url_encode(const u8 *src, int srclen, char *dst)
185{
186 u32 ac = 0;
187 int bits = 0;
188 int i;
189 char *cp = dst;
190
191 for (i = 0; i < srclen; i++) {
192 ac = (ac << 8) | src[i];
193 bits += 8;
194 do {
195 bits -= 6;
196 *cp++ = base64url_table[(ac >> bits) & 0x3f];
197 } while (bits >= 6);
198 }
199 if (bits)
200 *cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
201 return cp - dst;
202}
203
204/**
205 * fscrypt_base64url_decode() - base64url-decode a string
206 * @src: the string to decode. Doesn't need to be NUL-terminated.
207 * @srclen: the length of @src in bytes
208 * @dst: (output) the decoded binary data
209 *
210 * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding with
211 * URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't
212 * accepted, nor are non-encoding characters such as whitespace.
213 *
214 * This implementation hasn't been optimized for performance.
215 *
216 * Return: the length of the resulting decoded binary data in bytes,
217 * or -1 if the string isn't a valid base64url string.
218 */
219static int fscrypt_base64url_decode(const char *src, int srclen, u8 *dst)
220{
221 u32 ac = 0;
222 int bits = 0;
223 int i;
224 u8 *bp = dst;
225
226 for (i = 0; i < srclen; i++) {
227 const char *p = strchr(base64url_table, src[i]);
228
229 if (p == NULL || src[i] == 0)
230 return -1;
231 ac = (ac << 6) | (p - base64url_table);
232 bits += 6;
233 if (bits >= 8) {
234 bits -= 8;
235 *bp++ = (u8)(ac >> bits);
236 }
237 }
238 if (ac & ((1 << bits) - 1))
239 return -1;
240 return bp - dst;
241}
242
243bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,166bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
244 u32 orig_len, u32 max_len,167 u32 orig_len, u32 max_len,
245 u32 *encrypted_len_ret)168 u32 *encrypted_len_ret)
@@ -387,8 +310,8 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode, · 141 unmodified lines
387 nokey_name.sha256);310 nokey_name.sha256);
388 size = FSCRYPT_NOKEY_NAME_MAX;311 size = FSCRYPT_NOKEY_NAME_MAX;
389 }312 }
390 oname->len = fscrypt_base64url_encode((const u8 *)&nokey_name, size,313 oname->len = base64_encode((const u8 *)&nokey_name, size,
391 oname->name);314 oname->name, false, BASE64_URLSAFE);
392 return 0;315 return 0;
393}316}
394EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);317EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
@@ -467,8 +390,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, · 72 unmodified lines
467 if (fname->crypto_buf.name == NULL)390 if (fname->crypto_buf.name == NULL)
468 return -ENOMEM;391 return -ENOMEM;
469 392
470 ret = fscrypt_base64url_decode(iname->name, iname->len,393 ret = base64_decode(iname->name, iname->len,
471 fname->crypto_buf.name);394 fname->crypto_buf.name, false, BASE64_URLSAFE);
472 if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||395 if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
473 (ret > offsetof(struct fscrypt_nokey_name, sha256) &&396 (ret > offsetof(struct fscrypt_nokey_name, sha256) &&
474 ret != FSCRYPT_NOKEY_NAME_MAX)) {397 ret != FSCRYPT_NOKEY_NAME_MAX)) {
fs/nilfs2/ioctl.c+10−25
@@ -49,7 +49,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, · 48 unmodified lines
49 void *, size_t, size_t))49 void *, size_t, size_t))
50{50{
51 void *buf;51 void *buf;
52 void __user *base = (void __user *)(unsigned long)argv->v_base;52 void __user *base = u64_to_user_ptr(argv->v_base);
53 size_t maxmembs, total, n;53 size_t maxmembs, total, n;
54 ssize_t nr;54 ssize_t nr;
55 int ret, i;55 int ret, i;
@@ -836,7 +836,6 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, · 780 unmodified lines
836 sizeof(struct nilfs_bdesc),836 sizeof(struct nilfs_bdesc),
837 sizeof(__u64),837 sizeof(__u64),
838 };838 };
839 void __user *base;
840 void *kbufs[5];839 void *kbufs[5];
841 struct the_nilfs *nilfs;840 struct the_nilfs *nilfs;
842 size_t len, nsegs;841 size_t len, nsegs;
@@ -863,7 +862,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, · 20 unmodified lines
863 * use kmalloc() for its buffer because the memory used for the862 * use kmalloc() for its buffer because the memory used for the
864 * segment numbers is small enough.863 * segment numbers is small enough.
865 */864 */
866 kbufs[4] = memdup_array_user((void __user *)(unsigned long)argv[4].v_base,865 kbufs[4] = memdup_array_user(u64_to_user_ptr(argv[4].v_base),
867 nsegs, sizeof(__u64));866 nsegs, sizeof(__u64));
868 if (IS_ERR(kbufs[4])) {867 if (IS_ERR(kbufs[4])) {
869 ret = PTR_ERR(kbufs[4]);868 ret = PTR_ERR(kbufs[4]);
@@ -883,20 +882,14 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, · 13 unmodified lines
883 goto out_free;882 goto out_free;
884 883
885 len = argv[n].v_size * argv[n].v_nmembs;884 len = argv[n].v_size * argv[n].v_nmembs;
886 base = (void __user *)(unsigned long)argv[n].v_base;
887 if (len == 0) {885 if (len == 0) {
888 kbufs[n] = NULL;886 kbufs[n] = NULL;
889 continue;887 continue;
890 }888 }
891 889
892 kbufs[n] = vmalloc(len);890 kbufs[n] = vmemdup_user(u64_to_user_ptr(argv[n].v_base), len);
893 if (!kbufs[n]) {891 if (IS_ERR(kbufs[n])) {
894 ret = -ENOMEM;892 ret = PTR_ERR(kbufs[n]);
895 goto out_free;
896 }
897 if (copy_from_user(kbufs[n], base, len)) {
898 ret = -EFAULT;
899 vfree(kbufs[n]);
900 goto out_free;893 goto out_free;
901 }894 }
902 }895 }
@@ -928,7 +921,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, · 25 unmodified lines
928 921
929out_free:922out_free:
930 while (--n >= 0)923 while (--n >= 0)
931 vfree(kbufs[n]);924 kvfree(kbufs[n]);
932 kfree(kbufs[4]);925 kfree(kbufs[4]);
933out:926out:
934 mnt_drop_write_file(filp);927 mnt_drop_write_file(filp);
@@ -1181,7 +1174,6 @@ static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, · 246 unmodified lines
1181 struct nilfs_transaction_info ti;1174 struct nilfs_transaction_info ti;
1182 struct nilfs_argv argv;1175 struct nilfs_argv argv;
1183 size_t len;1176 size_t len;
1184 void __user *base;
1185 void *kbuf;1177 void *kbuf;
1186 int ret;1178 int ret;
1187 1179
@@ -1212,18 +1204,12 @@ static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, · 24 unmodified lines
1212 goto out;1204 goto out;
1213 }1205 }
1214 1206
1215 base = (void __user *)(unsigned long)argv.v_base;1207 kbuf = vmemdup_user(u64_to_user_ptr(argv.v_base), len);
1216 kbuf = vmalloc(len);1208 if (IS_ERR(kbuf)) {
1217 if (!kbuf) {1209 ret = PTR_ERR(kbuf);
1218 ret = -ENOMEM;
1219 goto out;1210 goto out;
1220 }1211 }
1221 1212
1222 if (copy_from_user(kbuf, base, len)) {
1223 ret = -EFAULT;
1224 goto out_free;
1225 }
1226
1227 nilfs_transaction_begin(inode->i_sb, &ti, 0);1213 nilfs_transaction_begin(inode->i_sb, &ti, 0);
1228 ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size,1214 ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size,
1229 argv.v_nmembs);1215 argv.v_nmembs);
@@ -1232,8 +1218,7 @@ static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, · 2 unmodified lines
1232 else1218 else
1233 nilfs_transaction_commit(inode->i_sb); /* never fails */1219 nilfs_transaction_commit(inode->i_sb); /* never fails */
1234 1220
1235out_free:1221 kvfree(kbuf);
1236 vfree(kbuf);
1237out:1222out:
1238 mnt_drop_write_file(filp);1223 mnt_drop_write_file(filp);
1239 return ret;1224 return ret;
fs/ocfs2/dir.c+38−4
@@ -302,8 +302,21 @@ static int ocfs2_check_dir_entry(struct inode *dir, · 301 unmodified lines
302 unsigned long offset)302 unsigned long offset)
303{303{
304 const char *error_msg = NULL;304 const char *error_msg = NULL;
305 const int rlen = le16_to_cpu(de->rec_len);305 unsigned long next_offset;
306 const unsigned long next_offset = ((char *) de - buf) + rlen;306 int rlen;
307
308 if (offset > size - OCFS2_DIR_REC_LEN(1)) {
309 /* Dirent is (maybe partially) beyond the buffer
310 * boundaries so touching 'de' members is unsafe.
311 */
312 mlog(ML_ERROR, "directory entry (#%llu: offset=%lu) "
313 "too close to end or out-of-bounds",
314 (unsigned long long)OCFS2_I(dir)->ip_blkno, offset);
315 return 0;
316 }
317
318 rlen = le16_to_cpu(de->rec_len);
319 next_offset = ((char *) de - buf) + rlen;
307 320
308 if (unlikely(rlen < OCFS2_DIR_REC_LEN(1)))321 if (unlikely(rlen < OCFS2_DIR_REC_LEN(1)))
309 error_msg = "rec_len is smaller than minimal";322 error_msg = "rec_len is smaller than minimal";
@@ -778,6 +791,14 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, · 468 unmodified lines
778 struct ocfs2_extent_block *eb;791 struct ocfs2_extent_block *eb;
779 struct ocfs2_extent_rec *rec = NULL;792 struct ocfs2_extent_rec *rec = NULL;
780 793
794 if (le16_to_cpu(el->l_count) !=
795 ocfs2_extent_recs_per_dx_root(inode->i_sb)) {
796 ret = ocfs2_error(inode->i_sb,
797 "Inode %lu has invalid extent list length %u\n",
798 inode->i_ino, le16_to_cpu(el->l_count));
799 goto out;
800 }
801
781 if (el->l_tree_depth) {802 if (el->l_tree_depth) {
782 ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash,803 ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash,
783 &eb_bh);804 &eb_bh);
@@ -3423,6 +3444,14 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, · 2639 unmodified lines
3423 offset += le16_to_cpu(de->rec_len);3444 offset += le16_to_cpu(de->rec_len);
3424 }3445 }
3425 3446
3447 if (!last_de) {
3448 ret = ocfs2_error(sb, "Directory entry (#%llu: size=%lld) "
3449 "is unexpectedly short",
3450 (unsigned long long)OCFS2_I(dir)->ip_blkno,
3451 i_size_read(dir));
3452 goto out;
3453 }
3454
3426 /*3455 /*
3427 * We're going to require expansion of the directory - figure3456 * We're going to require expansion of the directory - figure
3428 * out how many blocks we'll need so that a place for the3457 * out how many blocks we'll need so that a place for the
@@ -4104,10 +4133,15 @@ static int ocfs2_expand_inline_dx_root(struct inode *dir, · 675 unmodified lines
4104 }4133 }
4105 4134
4106 dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE;4135 dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE;
4107 memset(&dx_root->dr_list, 0, osb->sb->s_blocksize -4136
4108 offsetof(struct ocfs2_dx_root_block, dr_list));4137 dx_root->dr_list.l_tree_depth = 0;
4109 dx_root->dr_list.l_count =4138 dx_root->dr_list.l_count =
4110 cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb));4139 cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb));
4140 dx_root->dr_list.l_next_free_rec = 0;
4141 memset(&dx_root->dr_list.l_recs, 0,
4142 osb->sb->s_blocksize -
4143 (offsetof(struct ocfs2_dx_root_block, dr_list) +
4144 offsetof(struct ocfs2_extent_list, l_recs)));
4111 4145
4112 /* This should never fail considering we start with an empty4146 /* This should never fail considering we start with an empty
4113 * dx_root. */4147 * dx_root. */
fs/ocfs2/inode.c+44−5
@@ -201,13 +201,15 @@ bail: · 200 unmodified lines
201static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)201static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
202{202{
203 /* inodes flagged with other stuff in id2 */203 /* inodes flagged with other stuff in id2 */
204 if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL |204 if (le32_to_cpu(di->i_flags) &
205 OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL))205 (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL |
206 OCFS2_DEALLOC_FL))
206 return 0;207 return 0;
207 /* i_flags doesn't indicate when id2 is a fast symlink */208 /* i_flags doesn't indicate when id2 is a fast symlink */
208 if (S_ISLNK(di->i_mode) && di->i_size && di->i_clusters == 0)209 if (S_ISLNK(le16_to_cpu(di->i_mode)) && le64_to_cpu(di->i_size) &&
210 !le32_to_cpu(di->i_clusters))
209 return 0;211 return 0;
210 if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)212 if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)
211 return 0;213 return 0;
212 214
213 return 1;215 return 1;
@@ -1460,7 +1462,7 @@ int ocfs2_validate_inode_block(struct super_block *sb, · 1246 unmodified lines
1460 goto bail;1462 goto bail;
1461 }1463 }
1462 1464
1463 if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {1465 if (!(le32_to_cpu(di->i_flags) & OCFS2_VALID_FL)) {
1464 rc = ocfs2_error(sb,1466 rc = ocfs2_error(sb,
1465 "Invalid dinode #%llu: OCFS2_VALID_FL not set\n",1467 "Invalid dinode #%llu: OCFS2_VALID_FL not set\n",
1466 (unsigned long long)bh->b_blocknr);1468 (unsigned long long)bh->b_blocknr);
@@ -1484,6 +1486,41 @@ int ocfs2_validate_inode_block(struct super_block *sb, · 17 unmodified lines
1484 goto bail;1486 goto bail;
1485 }1487 }
1486 1488
1489 if ((le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) &&
1490 le32_to_cpu(di->i_clusters)) {
1491 rc = ocfs2_error(sb, "Invalid dinode %llu: %u clusters\n",
1492 (unsigned long long)bh->b_blocknr,
1493 le32_to_cpu(di->i_clusters));
1494 goto bail;
1495 }
1496
1497 if (le32_to_cpu(di->i_flags) & OCFS2_CHAIN_FL) {
1498 struct ocfs2_chain_list *cl = &di->id2.i_chain;
1499 u16 bpc = 1 << (OCFS2_SB(sb)->s_clustersize_bits -
1500 sb->s_blocksize_bits);
1501
1502 if (le16_to_cpu(cl->cl_count) != ocfs2_chain_recs_per_inode(sb)) {
1503 rc = ocfs2_error(sb, "Invalid dinode %llu: chain list count %u\n",
1504 (unsigned long long)bh->b_blocknr,
1505 le16_to_cpu(cl->cl_count));
1506 goto bail;
1507 }
1508 if (le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)) {
1509 rc = ocfs2_error(sb, "Invalid dinode %llu: chain list index %u\n",
1510 (unsigned long long)bh->b_blocknr,
1511 le16_to_cpu(cl->cl_next_free_rec));
1512 goto bail;
1513 }
1514 if (OCFS2_SB(sb)->bitmap_blkno &&
1515 OCFS2_SB(sb)->bitmap_blkno != le64_to_cpu(di->i_blkno) &&
1516 le16_to_cpu(cl->cl_bpc) != bpc) {
1517 rc = ocfs2_error(sb, "Invalid dinode %llu: bits per cluster %u\n",
1518 (unsigned long long)bh->b_blocknr,
1519 le16_to_cpu(cl->cl_bpc));
1520 goto bail;
1521 }
1522 }
1523
1487 rc = 0;1524 rc = 0;
1488 1525
1489bail:1526bail:
@@ -1671,6 +1708,8 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh, · 181 unmodified lines
1671 rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,1708 rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,
1672 1, &tmp, flags, ocfs2_validate_inode_block);1709 1, &tmp, flags, ocfs2_validate_inode_block);
1673 1710
1711 if (rc < 0)
1712 make_bad_inode(inode);
1674 /* If ocfs2_read_blocks() got us a new bh, pass it up. */1713 /* If ocfs2_read_blocks() got us a new bh, pass it up. */
1675 if (!rc && !*bh)1714 if (!rc && !*bh)
1676 *bh = tmp;1715 *bh = tmp;
fs/ocfs2/move_extents.c+13−1
@@ -98,7 +98,13 @@ static int __ocfs2_move_extent(handle_t *handle, · 97 unmodified lines
98 98
99 rec = &el->l_recs[index];99 rec = &el->l_recs[index];
100 100
101 BUG_ON(ext_flags != rec->e_flags);101 if (ext_flags != rec->e_flags) {
102 ret = ocfs2_error(inode->i_sb,
103 "Inode %llu has corrupted extent %d with flags 0x%x at cpos %u\n",
104 (unsigned long long)ino, index, rec->e_flags, cpos);
105 goto out;
106 }
107
102 /*108 /*
103 * after moving/defraging to new location, the extent is not going109 * after moving/defraging to new location, the extent is not going
104 * to be refcounted anymore.110 * to be refcounted anymore.
@@ -1036,6 +1042,12 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp) · 931 unmodified lines
1036 if (range.me_threshold > i_size_read(inode))1042 if (range.me_threshold > i_size_read(inode))
1037 range.me_threshold = i_size_read(inode);1043 range.me_threshold = i_size_read(inode);
1038 1044
1045 if (range.me_flags & ~(OCFS2_MOVE_EXT_FL_AUTO_DEFRAG |
1046 OCFS2_MOVE_EXT_FL_PART_DEFRAG)) {
1047 status = -EINVAL;
1048 goto out_free;
1049 }
1050
1039 if (range.me_flags & OCFS2_MOVE_EXT_FL_AUTO_DEFRAG) {1051 if (range.me_flags & OCFS2_MOVE_EXT_FL_AUTO_DEFRAG) {
1040 context->auto_defrag = 1;1052 context->auto_defrag = 1;
1041 1053
fs/ocfs2/ocfs2_fs.h+14−8
@@ -468,7 +468,8 @@ struct ocfs2_extent_list { · 467 unmodified lines
468 __le16 l_reserved1;468 __le16 l_reserved1;
469 __le64 l_reserved2; /* Pad to469 __le64 l_reserved2; /* Pad to
470 sizeof(ocfs2_extent_rec) */470 sizeof(ocfs2_extent_rec) */
471/*10*/ struct ocfs2_extent_rec l_recs[]; /* Extent records */471 /* Extent records */
472/*10*/ struct ocfs2_extent_rec l_recs[] __counted_by_le(l_count);
472};473};
473 474
474/*475/*
@@ -482,7 +483,8 @@ struct ocfs2_chain_list { · 7 unmodified lines
482 __le16 cl_count; /* Total chains in this list */483 __le16 cl_count; /* Total chains in this list */
483 __le16 cl_next_free_rec; /* Next unused chain slot */484 __le16 cl_next_free_rec; /* Next unused chain slot */
484 __le64 cl_reserved1;485 __le64 cl_reserved1;
485/*10*/ struct ocfs2_chain_rec cl_recs[]; /* Chain records */486 /* Chain records */
487/*10*/ struct ocfs2_chain_rec cl_recs[] __counted_by_le(cl_count);
486};488};
487 489
488/*490/*
@@ -494,7 +496,8 @@ struct ocfs2_truncate_log { · 5 unmodified lines
494/*00*/ __le16 tl_count; /* Total records in this log */496/*00*/ __le16 tl_count; /* Total records in this log */
495 __le16 tl_used; /* Number of records in use */497 __le16 tl_used; /* Number of records in use */
496 __le32 tl_reserved1;498 __le32 tl_reserved1;
497/*08*/ struct ocfs2_truncate_rec tl_recs[]; /* Truncate records */499 /* Truncate records */
500/*08*/ struct ocfs2_truncate_rec tl_recs[] __counted_by_le(tl_count);
498};501};
499 502
500/*503/*
@@ -796,9 +799,10 @@ struct ocfs2_dx_entry_list { · 295 unmodified lines
796 * possible in de_entries */799 * possible in de_entries */
797 __le16 de_num_used; /* Current number of800 __le16 de_num_used; /* Current number of
798 * de_entries entries */801 * de_entries entries */
799 struct ocfs2_dx_entry de_entries[]; /* Indexed dir entries802 /* Indexed dir entries in a packed
800 * in a packed array of803 * array of length de_num_used.
801 * length de_num_used */804 */
805 struct ocfs2_dx_entry de_entries[] __counted_by_le(de_count);
802};806};
803 807
804#define OCFS2_DX_FLAG_INLINE 0x01808#define OCFS2_DX_FLAG_INLINE 0x01
@@ -934,7 +938,8 @@ struct ocfs2_refcount_list { · 129 unmodified lines
934 __le16 rl_used; /* Current number of used records */938 __le16 rl_used; /* Current number of used records */
935 __le32 rl_reserved2;939 __le32 rl_reserved2;
936 __le64 rl_reserved1; /* Pad to sizeof(ocfs2_refcount_record) */940 __le64 rl_reserved1; /* Pad to sizeof(ocfs2_refcount_record) */
937/*10*/ struct ocfs2_refcount_rec rl_recs[]; /* Refcount records */941 /* Refcount records */
942/*10*/ struct ocfs2_refcount_rec rl_recs[] __counted_by_le(rl_count);
938};943};
939 944
940 945
@@ -1020,7 +1025,8 @@ struct ocfs2_xattr_header { · 79 unmodified lines
1020 buckets. A block uses1025 buckets. A block uses
1021 xb_check and sets1026 xb_check and sets
1022 this field to zero.) */1027 this field to zero.) */
1023 struct ocfs2_xattr_entry xh_entries[]; /* xattr entry list. */1028 /* xattr entry list. */
1029 struct ocfs2_xattr_entry xh_entries[] __counted_by_le(xh_count);
1024};1030};
1025 1031
1026/*1032/*
fs/ocfs2/refcounttree.c+3−2
@@ -34,6 +34,7 @@ · 33 unmodified lines
34#include <linux/pagevec.h>34#include <linux/pagevec.h>
35#include <linux/swap.h>35#include <linux/swap.h>
36#include <linux/security.h>36#include <linux/security.h>
37#include <linux/string.h>
37#include <linux/fsnotify.h>38#include <linux/fsnotify.h>
38#include <linux/quotaops.h>39#include <linux/quotaops.h>
39#include <linux/namei.h>40#include <linux/namei.h>
@@ -621,7 +622,7 @@ static int ocfs2_create_refcount_tree(struct inode *inode, · 581 unmodified lines
621 /* Initialize ocfs2_refcount_block. */622 /* Initialize ocfs2_refcount_block. */
622 rb = (struct ocfs2_refcount_block *)new_bh->b_data;623 rb = (struct ocfs2_refcount_block *)new_bh->b_data;
623 memset(rb, 0, inode->i_sb->s_blocksize);624 memset(rb, 0, inode->i_sb->s_blocksize);
624 strcpy((void *)rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE);625 strscpy(rb->rf_signature, OCFS2_REFCOUNT_BLOCK_SIGNATURE);
625 rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);626 rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
626 rb->rf_suballoc_loc = cpu_to_le64(suballoc_loc);627 rb->rf_suballoc_loc = cpu_to_le64(suballoc_loc);
627 rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);628 rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
@@ -1562,7 +1563,7 @@ static int ocfs2_new_leaf_refcount_block(handle_t *handle, · 934 unmodified lines
1562 /* Initialize ocfs2_refcount_block. */1563 /* Initialize ocfs2_refcount_block. */
1563 new_rb = (struct ocfs2_refcount_block *)new_bh->b_data;1564 new_rb = (struct ocfs2_refcount_block *)new_bh->b_data;
1564 memset(new_rb, 0, sb->s_blocksize);1565 memset(new_rb, 0, sb->s_blocksize);
1565 strcpy((void *)new_rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE);1566 strscpy(new_rb->rf_signature, OCFS2_REFCOUNT_BLOCK_SIGNATURE);
1566 new_rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);1567 new_rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
1567 new_rb->rf_suballoc_loc = cpu_to_le64(suballoc_loc);1568 new_rb->rf_suballoc_loc = cpu_to_le64(suballoc_loc);
1568 new_rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);1569 new_rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
fs/ocfs2/xattr.c+1−1
@@ -2908,7 +2908,7 @@ static int ocfs2_create_xattr_block(struct inode *inode, · 2907 unmodified lines
2908 /* Initialize ocfs2_xattr_block */2908 /* Initialize ocfs2_xattr_block */
2909 xblk = (struct ocfs2_xattr_block *)new_bh->b_data;2909 xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
2910 memset(xblk, 0, inode->i_sb->s_blocksize);2910 memset(xblk, 0, inode->i_sb->s_blocksize);
2911 strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);2911 strscpy(xblk->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE);
2912 xblk->xb_suballoc_slot = cpu_to_le16(ctxt->meta_ac->ac_alloc_slot);2912 xblk->xb_suballoc_slot = cpu_to_le16(ctxt->meta_ac->ac_alloc_slot);
2913 xblk->xb_suballoc_loc = cpu_to_le64(suballoc_loc);2913 xblk->xb_suballoc_loc = cpu_to_le64(suballoc_loc);
2914 xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);2914 xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
fs/proc/page.c+0−1
@@ -20,7 +20,6 @@ · 19 unmodified lines
20 20
21#define KPMSIZE sizeof(u64)21#define KPMSIZE sizeof(u64)
22#define KPMMASK (KPMSIZE - 1)22#define KPMMASK (KPMSIZE - 1)
23#define KPMBITS (KPMSIZE * BITS_PER_BYTE)
24 23
25enum kpage_operation {24enum kpage_operation {
26 KPAGE_FLAGS,25 KPAGE_FLAGS,
include/linux/base64.h+8−2
@@ -8,9 +8,15 @@ · 7 unmodified lines
8 8
9#include <linux/types.h>9#include <linux/types.h>
10 10
11enum base64_variant {
12 BASE64_STD, /* RFC 4648 (standard) */
13 BASE64_URLSAFE, /* RFC 4648 (base64url) */
14 BASE64_IMAP, /* RFC 3501 */
15};
16
11#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)17#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
12 18
13int base64_encode(const u8 *src, int len, char *dst);19int base64_encode(const u8 *src, int len, char *dst, bool padding, enum base64_variant variant);
14int base64_decode(const char *src, int len, u8 *dst);20int base64_decode(const char *src, int len, u8 *dst, bool padding, enum base64_variant variant);
15 21
16#endif /* _LINUX_BASE64_H */22#endif /* _LINUX_BASE64_H */
include/linux/compiler.h+0−6
@@ -273,12 +273,6 @@ static inline void *offset_to_ptr(const int *off) · 272 unmodified lines
273 273
274#endif /* __ASSEMBLY__ */274#endif /* __ASSEMBLY__ */
275 275
276#ifdef CONFIG_64BIT
277#define ARCH_SEL(a,b) a
278#else
279#define ARCH_SEL(a,b) b
280#endif
281
282/*276/*
283 * Force the compiler to emit 'sym' as a symbol, so that we can reference277 * Force the compiler to emit 'sym' as a symbol, so that we can reference
284 * it from inline assembler. Necessary in case 'sym' could be inlined278 * it from inline assembler. Necessary in case 'sym' could be inlined
include/linux/crash_reserve.h+6−0
@@ -32,6 +32,12 @@ int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, · 31 unmodified lines
32void __init reserve_crashkernel_cma(unsigned long long cma_size);32void __init reserve_crashkernel_cma(unsigned long long cma_size);
33 33
34#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION34#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
35#ifndef arch_add_crash_res_to_iomem
36static inline bool arch_add_crash_res_to_iomem(void)
37{
38 return true;
39}
40#endif
35#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE41#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
36#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)42#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
37#endif43#endif
include/linux/dynamic_debug.h+14−3
@@ -38,11 +38,12 @@ struct _ddebug { · 37 unmodified lines
38#define _DPRINTK_FLAGS_INCL_LINENO (1<<3)38#define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
39#define _DPRINTK_FLAGS_INCL_TID (1<<4)39#define _DPRINTK_FLAGS_INCL_TID (1<<4)
40#define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5)40#define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5)
41#define _DPRINTK_FLAGS_INCL_STACK (1<<6)
41 42
42#define _DPRINTK_FLAGS_INCL_ANY \43#define _DPRINTK_FLAGS_INCL_ANY \
43 (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\44 (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\
44 _DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID |\45 _DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID |\
45 _DPRINTK_FLAGS_INCL_SOURCENAME)46 _DPRINTK_FLAGS_INCL_SOURCENAME | _DPRINTK_FLAGS_INCL_STACK)
46 47
47#if defined DEBUG48#if defined DEBUG
48#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT49#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
@@ -160,6 +161,12 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, · 111 unmodified lines
160 const struct ib_device *ibdev,161 const struct ib_device *ibdev,
161 const char *fmt, ...);162 const char *fmt, ...);
162 163
164#define __dynamic_dump_stack(desc) \
165{ \
166 if (desc.flags & _DPRINTK_FLAGS_INCL_STACK) \
167 dump_stack(); \
168}
169
163#define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt) \170#define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt) \
164 static struct _ddebug __aligned(8) \171 static struct _ddebug __aligned(8) \
165 __section("__dyndbg") name = { \172 __section("__dyndbg") name = { \
@@ -220,8 +227,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, · 54 unmodified lines
220 */227 */
221#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do { \228#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do { \
222 DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \229 DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \
223 if (DYNAMIC_DEBUG_BRANCH(id)) \230 if (DYNAMIC_DEBUG_BRANCH(id)) { \
224 func(&id, ##__VA_ARGS__); \231 func(&id, ##__VA_ARGS__); \
232 __dynamic_dump_stack(id); \
233 } \
225} while (0)234} while (0)
226#define __dynamic_func_call(id, fmt, func, ...) \235#define __dynamic_func_call(id, fmt, func, ...) \
227 __dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt, \236 __dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt, \
@@ -229,8 +238,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, · 1 unmodified line
229 238
230#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do { \239#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do { \
231 DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \240 DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \
232 if (DYNAMIC_DEBUG_BRANCH(id)) \241 if (DYNAMIC_DEBUG_BRANCH(id)) { \
233 func(__VA_ARGS__); \242 func(__VA_ARGS__); \
243 __dynamic_dump_stack(id); \
244 } \
234} while (0)245} while (0)
235#define __dynamic_func_call_no_desc(id, fmt, func, ...) \246#define __dynamic_func_call_no_desc(id, fmt, func, ...) \
236 __dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT, \247 __dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT, \
include/linux/kexec_handover.h+28−29
@@ -2,22 +2,16 @@ · 1 unmodified line
2#ifndef LINUX_KEXEC_HANDOVER_H2#ifndef LINUX_KEXEC_HANDOVER_H
3#define LINUX_KEXEC_HANDOVER_H3#define LINUX_KEXEC_HANDOVER_H
4 4
5#include <linux/types.h>5#include <linux/err.h>
6#include <linux/errno.h>6#include <linux/errno.h>
7#include <linux/types.h>
7 8
8struct kho_scratch {9struct kho_scratch {
9 phys_addr_t addr;10 phys_addr_t addr;
10 phys_addr_t size;11 phys_addr_t size;
11};12};
12 13
13/* KHO Notifier index */
14enum kho_event {
15 KEXEC_KHO_FINALIZE = 0,
16 KEXEC_KHO_ABORT = 1,
17};
18
19struct folio;14struct folio;
20struct notifier_block;
21struct page;15struct page;
22 16
23#define DECLARE_KHOSER_PTR(name, type) \17#define DECLARE_KHOSER_PTR(name, type) \
@@ -37,8 +31,6 @@ struct page; · 13 unmodified lines
37 (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \31 (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
38 })32 })
39 33
40struct kho_serialization;
41
42struct kho_vmalloc_chunk;34struct kho_vmalloc_chunk;
43struct kho_vmalloc {35struct kho_vmalloc {
44 DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *);36 DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *);
@@ -52,17 +44,21 @@ bool kho_is_enabled(void); · 7 unmodified lines
52bool is_kho_boot(void);44bool is_kho_boot(void);
53 45
54int kho_preserve_folio(struct folio *folio);46int kho_preserve_folio(struct folio *folio);
47void kho_unpreserve_folio(struct folio *folio);
55int kho_preserve_pages(struct page *page, unsigned int nr_pages);48int kho_preserve_pages(struct page *page, unsigned int nr_pages);
49void kho_unpreserve_pages(struct page *page, unsigned int nr_pages);
56int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation);50int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation);
51void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation);
52void *kho_alloc_preserve(size_t size);
53void kho_unpreserve_free(void *mem);
54void kho_restore_free(void *mem);
57struct folio *kho_restore_folio(phys_addr_t phys);55struct folio *kho_restore_folio(phys_addr_t phys);
58struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages);56struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages);
59void *kho_restore_vmalloc(const struct kho_vmalloc *preservation);57void *kho_restore_vmalloc(const struct kho_vmalloc *preservation);
60int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt);58int kho_add_subtree(const char *name, void *fdt);
59void kho_remove_subtree(void *fdt);
61int kho_retrieve_subtree(const char *name, phys_addr_t *phys);60int kho_retrieve_subtree(const char *name, phys_addr_t *phys);
62 61
63int register_kho_notifier(struct notifier_block *nb);
64int unregister_kho_notifier(struct notifier_block *nb);
65
66void kho_memory_init(void);62void kho_memory_init(void);
67 63
68void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,64void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
@@ -83,17 +79,31 @@ static inline int kho_preserve_folio(struct folio *folio) · 14 unmodified lines
83 return -EOPNOTSUPP;79 return -EOPNOTSUPP;
84}80}
85 81
82static inline void kho_unpreserve_folio(struct folio *folio) { }
83
86static inline int kho_preserve_pages(struct page *page, unsigned int nr_pages)84static inline int kho_preserve_pages(struct page *page, unsigned int nr_pages)
87{85{
88 return -EOPNOTSUPP;86 return -EOPNOTSUPP;
89}87}
90 88
89static inline void kho_unpreserve_pages(struct page *page, unsigned int nr_pages) { }
90
91static inline int kho_preserve_vmalloc(void *ptr,91static inline int kho_preserve_vmalloc(void *ptr,
92 struct kho_vmalloc *preservation)92 struct kho_vmalloc *preservation)
93{93{
94 return -EOPNOTSUPP;94 return -EOPNOTSUPP;
95}95}
96 96
97static inline void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation) { }
98
99static inline void *kho_alloc_preserve(size_t size)
100{
101 return ERR_PTR(-EOPNOTSUPP);
102}
103
104static inline void kho_unpreserve_free(void *mem) { }
105static inline void kho_restore_free(void *mem) { }
106
97static inline struct folio *kho_restore_folio(phys_addr_t phys)107static inline struct folio *kho_restore_folio(phys_addr_t phys)
98{108{
99 return NULL;109 return NULL;
@@ -110,30 +120,19 @@ static inline void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) · 10 unmodified lines
110 return NULL;120 return NULL;
111}121}
112 122
113static inline int kho_add_subtree(struct kho_serialization *ser,123static inline int kho_add_subtree(const char *name, void *fdt)
114 const char *name, void *fdt)
115{
116 return -EOPNOTSUPP;
117}
118
119static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
120{124{
121 return -EOPNOTSUPP;125 return -EOPNOTSUPP;
122}126}
123 127
124static inline int register_kho_notifier(struct notifier_block *nb)128static inline void kho_remove_subtree(void *fdt) { }
125{
126 return -EOPNOTSUPP;
127}
128 129
129static inline int unregister_kho_notifier(struct notifier_block *nb)130static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
130{131{
131 return -EOPNOTSUPP;132 return -EOPNOTSUPP;
132}133}
133 134
134static inline void kho_memory_init(void)135static inline void kho_memory_init(void) { }
135{
136}
137 136
138static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,137static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
139 phys_addr_t scratch_phys, u64 scratch_len)138 phys_addr_t scratch_phys, u64 scratch_len)
include/linux/kho/abi/luo.h+166−0
@@ -0,0 +1,166 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8/**
9 * DOC: Live Update Orchestrator ABI
10 *
11 * This header defines the stable Application Binary Interface used by the
12 * Live Update Orchestrator to pass state from a pre-update kernel to a
13 * post-update kernel. The ABI is built upon the Kexec HandOver framework
14 * and uses a Flattened Device Tree to describe the preserved data.
15 *
16 * This interface is a contract. Any modification to the FDT structure, node
17 * properties, compatible strings, or the layout of the `__packed` serialization
18 * structures defined here constitutes a breaking change. Such changes require
19 * incrementing the version number in the relevant `_COMPATIBLE` string to
20 * prevent a new kernel from misinterpreting data from an old kernel.
21 *
22 * Changes are allowed provided the compatibility version is incremented;
23 * however, backward/forward compatibility is only guaranteed for kernels
24 * supporting the same ABI version.
25 *
26 * FDT Structure Overview:
27 * The entire LUO state is encapsulated within a single KHO entry named "LUO".
28 * This entry contains an FDT with the following layout:
29 *
30 * .. code-block:: none
31 *
32 * / {
33 * compatible = "luo-v1";
34 * liveupdate-number = <...>;
35 *
36 * luo-session {
37 * compatible = "luo-session-v1";
38 * luo-session-header = <phys_addr_of_session_header_ser>;
39 * };
40 * };
41 *
42 * Main LUO Node (/):
43 *
44 * - compatible: "luo-v1"
45 * Identifies the overall LUO ABI version.
46 * - liveupdate-number: u64
47 * A counter tracking the number of successful live updates performed.
48 *
49 * Session Node (luo-session):
50 * This node describes all preserved user-space sessions.
51 *
52 * - compatible: "luo-session-v1"
53 * Identifies the session ABI version.
54 * - luo-session-header: u64
55 * The physical address of a `struct luo_session_header_ser`. This structure
56 * is the header for a contiguous block of memory containing an array of
57 * `struct luo_session_ser`, one for each preserved session.
58 *
59 * Serialization Structures:
60 * The FDT properties point to memory regions containing arrays of simple,
61 * `__packed` structures. These structures contain the actual preserved state.
62 *
63 * - struct luo_session_header_ser:
64 * Header for the session array. Contains the total page count of the
65 * preserved memory block and the number of `struct luo_session_ser`
66 * entries that follow.
67 *
68 * - struct luo_session_ser:
69 * Metadata for a single session, including its name and a physical pointer
70 * to another preserved memory block containing an array of
71 * `struct luo_file_ser` for all files in that session.
72 *
73 * - struct luo_file_ser:
74 * Metadata for a single preserved file. Contains the `compatible` string to
75 * find the correct handler in the new kernel, a user-provided `token` for
76 * identification, and an opaque `data` handle for the handler to use.
77 */
78
79#ifndef _LINUX_KHO_ABI_LUO_H
80#define _LINUX_KHO_ABI_LUO_H
81
82#include <uapi/linux/liveupdate.h>
83
84/*
85 * The LUO FDT hooks all LUO state for sessions, fds, etc.
86 * In the root it also carries "liveupdate-number" 64-bit property that
87 * corresponds to the number of live-updates performed on this machine.
88 */
89#define LUO_FDT_SIZE PAGE_SIZE
90#define LUO_FDT_KHO_ENTRY_NAME "LUO"
91#define LUO_FDT_COMPATIBLE "luo-v1"
92#define LUO_FDT_LIVEUPDATE_NUM "liveupdate-number"
93
94#define LIVEUPDATE_HNDL_COMPAT_LENGTH 48
95
96/**
97 * struct luo_file_ser - Represents the serialized preserves files.
98 * @compatible: File handler compatible string.
99 * @data: Private data
100 * @token: User provided token for this file
101 *
102 * If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
103 */
104struct luo_file_ser {
105 char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
106 u64 data;
107 u64 token;
108} __packed;
109
110/**
111 * struct luo_file_set_ser - Represents the serialized metadata for file set
112 * @files: The physical address of a contiguous memory block that holds
113 * the serialized state of files (array of luo_file_ser) in this file
114 * set.
115 * @count: The total number of files that were part of this session during
116 * serialization. Used for iteration and validation during
117 * restoration.
118 */
119struct luo_file_set_ser {
120 u64 files;
121 u64 count;
122} __packed;
123
124/*
125 * LUO FDT session node
126 * LUO_FDT_SESSION_HEADER: is a u64 physical address of struct
127 * luo_session_header_ser
128 */
129#define LUO_FDT_SESSION_NODE_NAME "luo-session"
130#define LUO_FDT_SESSION_COMPATIBLE "luo-session-v2"
131#define LUO_FDT_SESSION_HEADER "luo-session-header"
132
133/**
134 * struct luo_session_header_ser - Header for the serialized session data block.
135 * @count: The number of `struct luo_session_ser` entries that immediately
136 * follow this header in the memory block.
137 *
138 * This structure is located at the beginning of a contiguous block of
139 * physical memory preserved across the kexec. It provides the necessary
140 * metadata to interpret the array of session entries that follow.
141 *
142 * If this structure is modified, `LUO_FDT_SESSION_COMPATIBLE` must be updated.
143 */
144struct luo_session_header_ser {
145 u64 count;
146} __packed;
147
148/**
149 * struct luo_session_ser - Represents the serialized metadata for a LUO session.
150 * @name: The unique name of the session, provided by the userspace at
151 * the time of session creation.
152 * @file_set_ser: Serialized files belonging to this session,
153 *
154 * This structure is used to package session-specific metadata for transfer
155 * between kernels via Kexec Handover. An array of these structures (one per
156 * session) is created and passed to the new kernel, allowing it to reconstruct
157 * the session context.
158 *
159 * If this structure is modified, `LUO_FDT_SESSION_COMPATIBLE` must be updated.
160 */
161struct luo_session_ser {
162 char name[LIVEUPDATE_SESSION_NAME_LENGTH];
163 struct luo_file_set_ser file_set_ser;
164} __packed;
165
166#endif /* _LINUX_KHO_ABI_LUO_H */
include/linux/kho/abi/memfd.h+77−0
@@ -0,0 +1,77 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 *
7 * Copyright (C) 2025 Amazon.com Inc. or its affiliates.
8 * Pratyush Yadav <ptyadav@amazon.de>
9 */
10
11#ifndef _LINUX_KHO_ABI_MEMFD_H
12#define _LINUX_KHO_ABI_MEMFD_H
13
14#include <linux/types.h>
15#include <linux/kexec_handover.h>
16
17/**
18 * DOC: memfd Live Update ABI
19 *
20 * This header defines the ABI for preserving the state of a memfd across a
21 * kexec reboot using the LUO.
22 *
23 * The state is serialized into a packed structure `struct memfd_luo_ser`
24 * which is handed over to the next kernel via the KHO mechanism.
25 *
26 * This interface is a contract. Any modification to the structure layout
27 * constitutes a breaking change. Such changes require incrementing the
28 * version number in the MEMFD_LUO_FH_COMPATIBLE string.
29 */
30
31/**
32 * MEMFD_LUO_FOLIO_DIRTY - The folio is dirty.
33 *
34 * This flag indicates the folio contains data from user. A non-dirty folio is
35 * one that was allocated (say using fallocate(2)) but not written to.
36 */
37#define MEMFD_LUO_FOLIO_DIRTY BIT(0)
38
39/**
40 * MEMFD_LUO_FOLIO_UPTODATE - The folio is up-to-date.
41 *
42 * An up-to-date folio has been zeroed out. shmem zeroes out folios on first
43 * use. This flag tracks which folios need zeroing.
44 */
45#define MEMFD_LUO_FOLIO_UPTODATE BIT(1)
46
47/**
48 * struct memfd_luo_folio_ser - Serialized state of a single folio.
49 * @pfn: The page frame number of the folio.
50 * @flags: Flags to describe the state of the folio.
51 * @index: The page offset (pgoff_t) of the folio within the original file.
52 */
53struct memfd_luo_folio_ser {
54 u64 pfn:52;
55 u64 flags:12;
56 u64 index;
57} __packed;
58
59/**
60 * struct memfd_luo_ser - Main serialization structure for a memfd.
61 * @pos: The file's current position (f_pos).
62 * @size: The total size of the file in bytes (i_size).
63 * @nr_folios: Number of folios in the folios array.
64 * @folios: KHO vmalloc descriptor pointing to the array of
65 * struct memfd_luo_folio_ser.
66 */
67struct memfd_luo_ser {
68 u64 pos;
69 u64 size;
70 u64 nr_folios;
71 struct kho_vmalloc folios;
72} __packed;
73
74/* The compatibility string for memfd file handler */
75#define MEMFD_LUO_FH_COMPATIBLE "memfd-v1"
76
77#endif /* _LINUX_KHO_ABI_MEMFD_H */
include/linux/liveupdate.h+138−0
@@ -0,0 +1,138 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7#ifndef _LINUX_LIVEUPDATE_H
8#define _LINUX_LIVEUPDATE_H
9
10#include <linux/bug.h>
11#include <linux/compiler.h>
12#include <linux/kho/abi/luo.h>
13#include <linux/list.h>
14#include <linux/types.h>
15#include <uapi/linux/liveupdate.h>
16
17struct liveupdate_file_handler;
18struct file;
19
20/**
21 * struct liveupdate_file_op_args - Arguments for file operation callbacks.
22 * @handler: The file handler being called.
23 * @retrieved: The retrieve status for the 'can_finish / finish'
24 * operation.
25 * @file: The file object. For retrieve: [OUT] The callback sets
26 * this to the new file. For other ops: [IN] The caller sets
27 * this to the file being operated on.
28 * @serialized_data: The opaque u64 handle, preserve/prepare/freeze may update
29 * this field.
30 * @private_data: Private data for the file used to hold runtime state that
31 * is not preserved. Set by the handler's .preserve()
32 * callback, and must be freed in the handler's
33 * .unpreserve() callback.
34 *
35 * This structure bundles all parameters for the file operation callbacks.
36 * The 'data' and 'file' fields are used for both input and output.
37 */
38struct liveupdate_file_op_args {
39 struct liveupdate_file_handler *handler;
40 bool retrieved;
41 struct file *file;
42 u64 serialized_data;
43 void *private_data;
44};
45
46/**
47 * struct liveupdate_file_ops - Callbacks for live-updatable files.
48 * @can_preserve: Required. Lightweight check to see if this handler is
49 * compatible with the given file.
50 * @preserve: Required. Performs state-saving for the file.
51 * @unpreserve: Required. Cleans up any resources allocated by @preserve.
52 * @freeze: Optional. Final actions just before kernel transition.
53 * @unfreeze: Optional. Undo freeze operations.
54 * @retrieve: Required. Restores the file in the new kernel.
55 * @can_finish: Optional. Check if this FD can finish, i.e. all restoration
56 * pre-requirements for this FD are satisfied. Called prior to
57 * finish, in order to do successful finish calls for all
58 * resources in the session.
59 * @finish: Required. Final cleanup in the new kernel.
60 * @owner: Module reference
61 *
62 * All operations (except can_preserve) receive a pointer to a
63 * 'struct liveupdate_file_op_args' containing the necessary context.
64 */
65struct liveupdate_file_ops {
66 bool (*can_preserve)(struct liveupdate_file_handler *handler,
67 struct file *file);
68 int (*preserve)(struct liveupdate_file_op_args *args);
69 void (*unpreserve)(struct liveupdate_file_op_args *args);
70 int (*freeze)(struct liveupdate_file_op_args *args);
71 void (*unfreeze)(struct liveupdate_file_op_args *args);
72 int (*retrieve)(struct liveupdate_file_op_args *args);
73 bool (*can_finish)(struct liveupdate_file_op_args *args);
74 void (*finish)(struct liveupdate_file_op_args *args);
75 struct module *owner;
76};
77
78/**
79 * struct liveupdate_file_handler - Represents a handler for a live-updatable file type.
80 * @ops: Callback functions
81 * @compatible: The compatibility string (e.g., "memfd-v1", "vfiofd-v1")
82 * that uniquely identifies the file type this handler
83 * supports. This is matched against the compatible string
84 * associated with individual &struct file instances.
85 *
86 * Modules that want to support live update for specific file types should
87 * register an instance of this structure. LUO uses this registration to
88 * determine if a given file can be preserved and to find the appropriate
89 * operations to manage its state across the update.
90 */
91struct liveupdate_file_handler {
92 const struct liveupdate_file_ops *ops;
93 const char compatible[LIVEUPDATE_HNDL_COMPAT_LENGTH];
94
95 /* private: */
96
97 /*
98 * Used for linking this handler instance into a global list of
99 * registered file handlers.
100 */
101 struct list_head __private list;
102};
103
104#ifdef CONFIG_LIVEUPDATE
105
106/* Return true if live update orchestrator is enabled */
107bool liveupdate_enabled(void);
108
109/* Called during kexec to tell LUO that entered into reboot */
110int liveupdate_reboot(void);
111
112int liveupdate_register_file_handler(struct liveupdate_file_handler *fh);
113int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
114
115#else /* CONFIG_LIVEUPDATE */
116
117static inline bool liveupdate_enabled(void)
118{
119 return false;
120}
121
122static inline int liveupdate_reboot(void)
123{
124 return 0;
125}
126
127static inline int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
128{
129 return -EOPNOTSUPP;
130}
131
132static inline int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
133{
134 return -EOPNOTSUPP;
135}
136
137#endif /* CONFIG_LIVEUPDATE */
138#endif /* _LINUX_LIVEUPDATE_H */
include/linux/math.h+9−4
@@ -148,11 +148,16 @@ __STRUCT_FRACT(u32) · 147 unmodified lines
148 148
149/**149/**
150 * abs - return absolute value of an argument150 * abs - return absolute value of an argument
151 * @x: the value. If it is unsigned type, it is converted to signed type first.151 * @x: the value.
152 * char is treated as if it was signed (regardless of whether it really is)
153 * but the macro's return type is preserved as char.
154 *152 *
155 * Return: an absolute value of x.153 * If it is unsigned type, @x is converted to signed type first.
154 * char is treated as if it was signed (regardless of whether it really is)
155 * but the macro's return type is preserved as char.
156 *
157 * NOTE, for signed type if @x is the minimum, the returned result is undefined
158 * as there is not enough bits to represent it as a positive number.
159 *
160 * Return: an absolute value of @x.
156 */161 */
157#define abs(x) __abs_choose_expr(x, long long, \162#define abs(x) __abs_choose_expr(x, long long, \
158 __abs_choose_expr(x, long, \163 __abs_choose_expr(x, long, \
include/linux/math64.h+58−1
@@ -158,6 +158,17 @@ static inline u64 mul_u32_u32(u32 a, u32 b) · 157 unmodified lines
158}158}
159#endif159#endif
160 160
161#ifndef add_u64_u32
162/*
163 * Many a GCC version also messes this up.
164 * Zero extending b and then spilling everything to stack.
165 */
166static inline u64 add_u64_u32(u64 a, u32 b)
167{
168 return a + b;
169}
170#endif
171
161#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)172#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
162 173
163#ifndef mul_u64_u32_shr174#ifndef mul_u64_u32_shr
@@ -282,7 +293,53 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) · 118 unmodified lines
282}293}
283#endif /* mul_u64_u32_div */294#endif /* mul_u64_u32_div */
284 295
285u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);296/**
297 * mul_u64_add_u64_div_u64 - unsigned 64bit multiply, add, and divide
298 * @a: first unsigned 64bit multiplicand
299 * @b: second unsigned 64bit multiplicand
300 * @c: unsigned 64bit addend
301 * @d: unsigned 64bit divisor
302 *
303 * Multiply two 64bit values together to generate a 128bit product
304 * add a third value and then divide by a fourth.
305 * The Generic code divides by 0 if @d is zero and returns ~0 on overflow.
306 * Architecture specific code may trap on zero or overflow.
307 *
308 * Return: (@a * @b + @c) / @d
309 */
310u64 mul_u64_add_u64_div_u64(u64 a, u64 b, u64 c, u64 d);
311
312/**
313 * mul_u64_u64_div_u64 - unsigned 64bit multiply and divide
314 * @a: first unsigned 64bit multiplicand
315 * @b: second unsigned 64bit multiplicand
316 * @d: unsigned 64bit divisor
317 *
318 * Multiply two 64bit values together to generate a 128bit product
319 * and then divide by a third value.
320 * The Generic code divides by 0 if @d is zero and returns ~0 on overflow.
321 * Architecture specific code may trap on zero or overflow.
322 *
323 * Return: @a * @b / @d
324 */
325#define mul_u64_u64_div_u64(a, b, d) mul_u64_add_u64_div_u64(a, b, 0, d)
326
327/**
328 * mul_u64_u64_div_u64_roundup - unsigned 64bit multiply and divide rounded up
329 * @a: first unsigned 64bit multiplicand
330 * @b: second unsigned 64bit multiplicand
331 * @d: unsigned 64bit divisor
332 *
333 * Multiply two 64bit values together to generate a 128bit product
334 * and then divide and round up.
335 * The Generic code divides by 0 if @d is zero and returns ~0 on overflow.
336 * Architecture specific code may trap on zero or overflow.
337 *
338 * Return: (@a * @b + @d - 1) / @d
339 */
340#define mul_u64_u64_div_u64_roundup(a, b, d) \
341 ({ u64 _tmp = (d); mul_u64_add_u64_div_u64(a, b, _tmp - 1, _tmp); })
342
286 343
287/**344/**
288 * DIV64_U64_ROUND_UP - unsigned 64bit divide with 64bit divisor rounded up345 * DIV64_U64_ROUND_UP - unsigned 64bit divide with 64bit divisor rounded up
include/linux/once_lite.h+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16 bool __ret_cond = !!(condition); \16 bool __ret_cond = !!(condition); \
17 bool __ret_once = false; \17 bool __ret_once = false; \
18 \18 \
19 if (unlikely(__ret_cond && !__already_done)) { \19 if (unlikely(__ret_cond) && unlikely(!__already_done)) {\
20 __already_done = true; \20 __already_done = true; \
21 __ret_once = true; \21 __ret_once = true; \
22 } \22 } \
include/linux/panic.h+0−1
@@ -86,7 +86,6 @@ static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout) · 85 unmodified lines
86struct taint_flag {86struct taint_flag {
87 char c_true; /* character printed when tainted */87 char c_true; /* character printed when tainted */
88 char c_false; /* character printed when not tainted */88 char c_false; /* character printed when not tainted */
89 bool module; /* also show as a per-module taint flag */
90 const char *desc; /* verbose description of the set taint flag */89 const char *desc; /* verbose description of the set taint flag */
91};90};
92 91
include/linux/rbtree.h+30−2
@@ -43,8 +43,36 @@ extern void rb_erase(struct rb_node *, struct rb_root *); · 42 unmodified lines
43/* Find logical next and previous nodes in a tree */43/* Find logical next and previous nodes in a tree */
44extern struct rb_node *rb_next(const struct rb_node *);44extern struct rb_node *rb_next(const struct rb_node *);
45extern struct rb_node *rb_prev(const struct rb_node *);45extern struct rb_node *rb_prev(const struct rb_node *);
46extern struct rb_node *rb_first(const struct rb_root *);46
47extern struct rb_node *rb_last(const struct rb_root *);47/*
48 * This function returns the first node (in sort order) of the tree.
49 */
50static inline struct rb_node *rb_first(const struct rb_root *root)
51{
52 struct rb_node *n;
53
54 n = root->rb_node;
55 if (!n)
56 return NULL;
57 while (n->rb_left)
58 n = n->rb_left;
59 return n;
60}
61
62/*
63 * This function returns the last node (in sort order) of the tree.
64 */
65static inline struct rb_node *rb_last(const struct rb_root *root)
66{
67 struct rb_node *n;
68
69 n = root->rb_node;
70 if (!n)
71 return NULL;
72 while (n->rb_right)
73 n = n->rb_right;
74 return n;
75}
48 76
49/* Postorder iteration - always visit the parent after its children */77/* Postorder iteration - always visit the parent after its children */
50extern struct rb_node *rb_first_postorder(const struct rb_root *);78extern struct rb_node *rb_first_postorder(const struct rb_root *);
include/linux/shmem_fs.h+23−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
10#include <linux/xattr.h>10#include <linux/xattr.h>
11#include <linux/fs_parser.h>11#include <linux/fs_parser.h>
12#include <linux/userfaultfd_k.h>12#include <linux/userfaultfd_k.h>
13#include <linux/bits.h>
13 14
14struct swap_iocb;15struct swap_iocb;
15 16
@@ -19,6 +20,19 @@ struct swap_iocb; · 3 unmodified lines
19#define SHMEM_MAXQUOTAS 220#define SHMEM_MAXQUOTAS 2
20#endif21#endif
21 22
23/* Suppress pre-accounting of the entire object size. */
24#define SHMEM_F_NORESERVE BIT(0)
25/* Disallow swapping. */
26#define SHMEM_F_LOCKED BIT(1)
27/*
28 * Disallow growing, shrinking, or hole punching in the inode. Combined with
29 * folio pinning, makes sure the inode's mapping stays fixed.
30 *
31 * In some ways similar to F_SEAL_GROW | F_SEAL_SHRINK, but can be removed and
32 * isn't directly visible to userspace.
33 */
34#define SHMEM_F_MAPPING_FROZEN BIT(2)
35
22struct shmem_inode_info {36struct shmem_inode_info {
23 spinlock_t lock;37 spinlock_t lock;
24 unsigned int seals; /* shmem seals */38 unsigned int seals; /* shmem seals */
@@ -186,6 +200,15 @@ static inline bool shmem_file(struct file *file) · 161 unmodified lines
186 return shmem_mapping(file->f_mapping);200 return shmem_mapping(file->f_mapping);
187}201}
188 202
203/* Must be called with inode lock taken exclusive. */
204static inline void shmem_freeze(struct inode *inode, bool freeze)
205{
206 if (freeze)
207 SHMEM_I(inode)->flags |= SHMEM_F_MAPPING_FROZEN;
208 else
209 SHMEM_I(inode)->flags &= ~SHMEM_F_MAPPING_FROZEN;
210}
211
189/*212/*
190 * If fallocate(FALLOC_FL_KEEP_SIZE) has been used, there may be pages213 * If fallocate(FALLOC_FL_KEEP_SIZE) has been used, there may be pages
191 * beyond i_size's notion of EOF, which fallocate has committed to reserving:214 * beyond i_size's notion of EOF, which fallocate has committed to reserving:
include/linux/sys_info.h+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#define SYS_INFO_LOCKS 0x0000000814#define SYS_INFO_LOCKS 0x00000008
15#define SYS_INFO_FTRACE 0x0000001015#define SYS_INFO_FTRACE 0x00000010
16#define SYS_INFO_PANIC_CONSOLE_REPLAY 0x0000002016#define SYS_INFO_PANIC_CONSOLE_REPLAY 0x00000020
17#define SYS_INFO_ALL_CPU_BT 0x0000004017#define SYS_INFO_ALL_BT 0x00000040
18#define SYS_INFO_BLOCKED_TASKS 0x0000008018#define SYS_INFO_BLOCKED_TASKS 0x00000080
19 19
20void sys_info(unsigned long si_mask);20void sys_info(unsigned long si_mask);
include/linux/uaccess.h+4−2
@@ -161,8 +161,6 @@ __copy_to_user(void __user *to, const void *from, unsigned long n) · 160 unmodified lines
161 * directly in the normal copy_to/from_user(), the other ones go161 * directly in the normal copy_to/from_user(), the other ones go
162 * through an extern _copy_to/from_user(), which expands the same code162 * through an extern _copy_to/from_user(), which expands the same code
163 * here.163 * here.
164 *
165 * Rust code always uses the extern definition.
166 */164 */
167static inline __must_check unsigned long165static inline __must_check unsigned long
168_inline_copy_from_user(void *to, const void __user *from, unsigned long n)166_inline_copy_from_user(void *to, const void __user *from, unsigned long n)
@@ -192,8 +190,10 @@ fail: · 23 unmodified lines
192 memset(to + (n - res), 0, res);190 memset(to + (n - res), 0, res);
193 return res;191 return res;
194}192}
193#ifndef INLINE_COPY_FROM_USER
195extern __must_check unsigned long194extern __must_check unsigned long
196_copy_from_user(void *, const void __user *, unsigned long);195_copy_from_user(void *, const void __user *, unsigned long);
196#endif
197 197
198static inline __must_check unsigned long198static inline __must_check unsigned long
199_inline_copy_to_user(void __user *to, const void *from, unsigned long n)199_inline_copy_to_user(void __user *to, const void *from, unsigned long n)
@@ -207,8 +207,10 @@ _inline_copy_to_user(void __user *to, const void *from, unsigned long n) · 7 unmodified lines
207 }207 }
208 return n;208 return n;
209}209}
210#ifndef INLINE_COPY_TO_USER
210extern __must_check unsigned long211extern __must_check unsigned long
211_copy_to_user(void __user *, const void *, unsigned long);212_copy_to_user(void __user *, const void *, unsigned long);
213#endif
212 214
213static __always_inline unsigned long __must_check215static __always_inline unsigned long __must_check
214copy_from_user(void *to, const void __user *from, unsigned long n)216copy_from_user(void *to, const void __user *from, unsigned long n)
include/linux/util_macros.h+2−2
@@ -136,10 +136,10 @@ · 135 unmodified lines
136#define PTR_IF(cond, ptr) ((cond) ? (ptr) : NULL)136#define PTR_IF(cond, ptr) ((cond) ? (ptr) : NULL)
137 137
138/**138/**
139 * to_user_ptr - cast a pointer passed as u64 from user space to void __user *139 * u64_to_user_ptr - cast a pointer passed as u64 from user space to void __user *
140 * @x: The u64 value from user space, usually via IOCTL140 * @x: The u64 value from user space, usually via IOCTL
141 *141 *
142 * to_user_ptr() simply casts a pointer passed as u64 from user space to void142 * u64_to_user_ptr() simply casts a pointer passed as u64 from user space to void
143 * __user * correctly. Using this lets us get rid of all the tiresome casts.143 * __user * correctly. Using this lets us get rid of all the tiresome casts.
144 */144 */
145#define u64_to_user_ptr(x) \145#define u64_to_user_ptr(x) \
include/linux/vmcore_info.h+8−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#include <linux/linkage.h>5#include <linux/linkage.h>
6#include <linux/elfcore.h>6#include <linux/elfcore.h>
7#include <linux/elf.h>7#include <linux/elf.h>
8#include <uapi/linux/vmcore.h>
8 9
9#define CRASH_CORE_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)10#define CRASH_CORE_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)
10#define CRASH_CORE_NOTE_NAME_BYTES ALIGN(sizeof(NN_PRSTATUS), 4)11#define CRASH_CORE_NOTE_NAME_BYTES ALIGN(sizeof(NN_PRSTATUS), 4)
@@ -77,4 +78,11 @@ extern u32 *vmcoreinfo_note; · 66 unmodified lines
77Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,78Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
78 void *data, size_t data_len);79 void *data, size_t data_len);
79void final_note(Elf_Word *buf);80void final_note(Elf_Word *buf);
81
82#ifdef CONFIG_VMCORE_INFO
83void hwerr_log_error_type(enum hwerr_error_type src);
84#else
85static inline void hwerr_log_error_type(enum hwerr_error_type src) {};
86#endif
87
80#endif /* LINUX_VMCORE_INFO_H */88#endif /* LINUX_VMCORE_INFO_H */
include/linux/xxhash.h+1−45
@@ -141,21 +141,7 @@ static inline unsigned long xxhash(const void *input, size_t length, · 140 unmodified lines
141 */141 */
142 142
143/**143/**
144 * struct xxh32_state - private xxh32 state, do not use members directly144 * struct xxh64_state - private xxh64 state, do not use members directly
145 */
146struct xxh32_state {
147 uint32_t total_len_32;
148 uint32_t large_len;
149 uint32_t v1;
150 uint32_t v2;
151 uint32_t v3;
152 uint32_t v4;
153 uint32_t mem32[4];
154 uint32_t memsize;
155};
156
157/**
158 * struct xxh32_state - private xxh64 state, do not use members directly
159 */145 */
160struct xxh64_state {146struct xxh64_state {
161 uint64_t total_len;147 uint64_t total_len;
@@ -167,16 +153,6 @@ struct xxh64_state { · 5 unmodified lines
167 uint32_t memsize;153 uint32_t memsize;
168};154};
169 155
170/**
171 * xxh32_reset() - reset the xxh32 state to start a new hashing operation
172 *
173 * @state: The xxh32 state to reset.
174 * @seed: Initialize the hash state with this seed.
175 *
176 * Call this function on any xxh32_state to prepare for a new hashing operation.
177 */
178void xxh32_reset(struct xxh32_state *state, uint32_t seed);
179
180/**156/**
181 * xxh64_reset() - reset the xxh64 state to start a new hashing operation157 * xxh64_reset() - reset the xxh64 state to start a new hashing operation
182 *158 *
@@ -210,24 +186,4 @@ int xxh64_update(struct xxh64_state *state, const void *input, size_t length); · 27 unmodified lines
210 */186 */
211uint64_t xxh64_digest(const struct xxh64_state *state);187uint64_t xxh64_digest(const struct xxh64_state *state);
212 188
213/*-**************************
214 * Utils
215 ***************************/
216
217/**
218 * xxh32_copy_state() - copy the source state into the destination state
219 *
220 * @src: The source xxh32 state.
221 * @dst: The destination xxh32 state.
222 */
223void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
224
225/**
226 * xxh64_copy_state() - copy the source state into the destination state
227 *
228 * @src: The source xxh64 state.
229 * @dst: The destination xxh64 state.
230 */
231void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
232
233#endif /* XXHASH_H */189#endif /* XXHASH_H */
include/uapi/linux/liveupdate.h+216−0
@@ -0,0 +1,216 @@
1/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2
3/*
4 * Userspace interface for /dev/liveupdate
5 * Live Update Orchestrator
6 *
7 * Copyright (c) 2025, Google LLC.
8 * Pasha Tatashin <pasha.tatashin@soleen.com>
9 */
10
11#ifndef _UAPI_LIVEUPDATE_H
12#define _UAPI_LIVEUPDATE_H
13
14#include <linux/ioctl.h>
15#include <linux/types.h>
16
17/**
18 * DOC: General ioctl format
19 *
20 * The ioctl interface follows a general format to allow for extensibility. Each
21 * ioctl is passed in a structure pointer as the argument providing the size of
22 * the structure in the first u32. The kernel checks that any structure space
23 * beyond what it understands is 0. This allows userspace to use the backward
24 * compatible portion while consistently using the newer, larger, structures.
25 *
26 * ioctls use a standard meaning for common errnos:
27 *
28 * - ENOTTY: The IOCTL number itself is not supported at all
29 * - E2BIG: The IOCTL number is supported, but the provided structure has
30 * non-zero in a part the kernel does not understand.
31 * - EOPNOTSUPP: The IOCTL number is supported, and the structure is
32 * understood, however a known field has a value the kernel does not
33 * understand or support.
34 * - EINVAL: Everything about the IOCTL was understood, but a field is not
35 * correct.
36 * - ENOENT: A provided token does not exist.
37 * - ENOMEM: Out of memory.
38 * - EOVERFLOW: Mathematics overflowed.
39 *
40 * As well as additional errnos, within specific ioctls.
41 */
42
43/* The ioctl type, documented in ioctl-number.rst */
44#define LIVEUPDATE_IOCTL_TYPE 0xBA
45
46/* The maximum length of session name including null termination */
47#define LIVEUPDATE_SESSION_NAME_LENGTH 64
48
49/* The /dev/liveupdate ioctl commands */
50enum {
51 LIVEUPDATE_CMD_BASE = 0x00,
52 LIVEUPDATE_CMD_CREATE_SESSION = LIVEUPDATE_CMD_BASE,
53 LIVEUPDATE_CMD_RETRIEVE_SESSION = 0x01,
54};
55
56/* ioctl commands for session file descriptors */
57enum {
58 LIVEUPDATE_CMD_SESSION_BASE = 0x40,
59 LIVEUPDATE_CMD_SESSION_PRESERVE_FD = LIVEUPDATE_CMD_SESSION_BASE,
60 LIVEUPDATE_CMD_SESSION_RETRIEVE_FD = 0x41,
61 LIVEUPDATE_CMD_SESSION_FINISH = 0x42,
62};
63
64/**
65 * struct liveupdate_ioctl_create_session - ioctl(LIVEUPDATE_IOCTL_CREATE_SESSION)
66 * @size: Input; sizeof(struct liveupdate_ioctl_create_session)
67 * @fd: Output; The new file descriptor for the created session.
68 * @name: Input; A null-terminated string for the session name, max
69 * length %LIVEUPDATE_SESSION_NAME_LENGTH including termination
70 * character.
71 *
72 * Creates a new live update session for managing preserved resources.
73 * This ioctl can only be called on the main /dev/liveupdate device.
74 *
75 * Return: 0 on success, negative error code on failure.
76 */
77struct liveupdate_ioctl_create_session {
78 __u32 size;
79 __s32 fd;
80 __u8 name[LIVEUPDATE_SESSION_NAME_LENGTH];
81};
82
83#define LIVEUPDATE_IOCTL_CREATE_SESSION \
84 _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_CREATE_SESSION)
85
86/**
87 * struct liveupdate_ioctl_retrieve_session - ioctl(LIVEUPDATE_IOCTL_RETRIEVE_SESSION)
88 * @size: Input; sizeof(struct liveupdate_ioctl_retrieve_session)
89 * @fd: Output; The new file descriptor for the retrieved session.
90 * @name: Input; A null-terminated string identifying the session to retrieve.
91 * The name must exactly match the name used when the session was
92 * created in the previous kernel.
93 *
94 * Retrieves a handle (a new file descriptor) for a preserved session by its
95 * name. This is the primary mechanism for a userspace agent to regain control
96 * of its preserved resources after a live update.
97 *
98 * The userspace application provides the null-terminated `name` of a session
99 * it created before the live update. If a preserved session with a matching
100 * name is found, the kernel instantiates it and returns a new file descriptor
101 * in the `fd` field. This new session FD can then be used for all file-specific
102 * operations, such as restoring individual file descriptors with
103 * LIVEUPDATE_SESSION_RETRIEVE_FD.
104 *
105 * It is the responsibility of the userspace application to know the names of
106 * the sessions it needs to retrieve. If no session with the given name is
107 * found, the ioctl will fail with -ENOENT.
108 *
109 * This ioctl can only be called on the main /dev/liveupdate device when the
110 * system is in the LIVEUPDATE_STATE_UPDATED state.
111 */
112struct liveupdate_ioctl_retrieve_session {
113 __u32 size;
114 __s32 fd;
115 __u8 name[LIVEUPDATE_SESSION_NAME_LENGTH];
116};
117
118#define LIVEUPDATE_IOCTL_RETRIEVE_SESSION \
119 _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_RETRIEVE_SESSION)
120
121/* Session specific IOCTLs */
122
123/**
124 * struct liveupdate_session_preserve_fd - ioctl(LIVEUPDATE_SESSION_PRESERVE_FD)
125 * @size: Input; sizeof(struct liveupdate_session_preserve_fd)
126 * @fd: Input; The user-space file descriptor to be preserved.
127 * @token: Input; An opaque, unique token for preserved resource.
128 *
129 * Holds parameters for preserving a file descriptor.
130 *
131 * User sets the @fd field identifying the file descriptor to preserve
132 * (e.g., memfd, kvm, iommufd, VFIO). The kernel validates if this FD type
133 * and its dependencies are supported for preservation. If validation passes,
134 * the kernel marks the FD internally and *initiates the process* of preparing
135 * its state for saving. The actual snapshotting of the state typically occurs
136 * during the subsequent %LIVEUPDATE_IOCTL_PREPARE execution phase, though
137 * some finalization might occur during freeze.
138 * On successful validation and initiation, the kernel uses the @token
139 * field with an opaque identifier representing the resource being preserved.
140 * This token confirms the FD is targeted for preservation and is required for
141 * the subsequent %LIVEUPDATE_SESSION_RETRIEVE_FD call after the live update.
142 *
143 * Return: 0 on success (validation passed, preservation initiated), negative
144 * error code on failure (e.g., unsupported FD type, dependency issue,
145 * validation failed).
146 */
147struct liveupdate_session_preserve_fd {
148 __u32 size;
149 __s32 fd;
150 __aligned_u64 token;
151};
152
153#define LIVEUPDATE_SESSION_PRESERVE_FD \
154 _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_PRESERVE_FD)
155
156/**
157 * struct liveupdate_session_retrieve_fd - ioctl(LIVEUPDATE_SESSION_RETRIEVE_FD)
158 * @size: Input; sizeof(struct liveupdate_session_retrieve_fd)
159 * @fd: Output; The new file descriptor representing the fully restored
160 * kernel resource.
161 * @token: Input; An opaque, token that was used to preserve the resource.
162 *
163 * Retrieve a previously preserved file descriptor.
164 *
165 * User sets the @token field to the value obtained from a successful
166 * %LIVEUPDATE_IOCTL_FD_PRESERVE call before the live update. On success,
167 * the kernel restores the state (saved during the PREPARE/FREEZE phases)
168 * associated with the token and populates the @fd field with a new file
169 * descriptor referencing the restored resource in the current (new) kernel.
170 * This operation must be performed *before* signaling completion via
171 * %LIVEUPDATE_IOCTL_FINISH.
172 *
173 * Return: 0 on success, negative error code on failure (e.g., invalid token).
174 */
175struct liveupdate_session_retrieve_fd {
176 __u32 size;
177 __s32 fd;
178 __aligned_u64 token;
179};
180
181#define LIVEUPDATE_SESSION_RETRIEVE_FD \
182 _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_RETRIEVE_FD)
183
184/**
185 * struct liveupdate_session_finish - ioctl(LIVEUPDATE_SESSION_FINISH)
186 * @size: Input; sizeof(struct liveupdate_session_finish)
187 * @reserved: Input; Must be zero. Reserved for future use.
188 *
189 * Signals the completion of the restoration process for a retrieved session.
190 * This is the final operation that should be performed on a session file
191 * descriptor after a live update.
192 *
193 * This ioctl must be called once all required file descriptors for the session
194 * have been successfully retrieved (using %LIVEUPDATE_SESSION_RETRIEVE_FD) and
195 * are fully restored from the userspace and kernel perspective.
196 *
197 * Upon success, the kernel releases its ownership of the preserved resources
198 * associated with this session. This allows internal resources to be freed,
199 * typically by decrementing reference counts on the underlying preserved
200 * objects.
201 *
202 * If this operation fails, the resources remain preserved in memory. Userspace
203 * may attempt to call finish again. The resources will otherwise be reset
204 * during the next live update cycle.
205 *
206 * Return: 0 on success, negative error code on failure.
207 */
208struct liveupdate_session_finish {
209 __u32 size;
210 __u32 reserved;
211};
212
213#define LIVEUPDATE_SESSION_FINISH \
214 _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_SESSION_FINISH)
215
216#endif /* _UAPI_LIVEUPDATE_H */
include/uapi/linux/vmcore.h+9−0
@@ -15,4 +15,13 @@ struct vmcoredd_header { · 14 unmodified lines
15 __u8 dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Device dump's name */15 __u8 dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Device dump's name */
16};16};
17 17
18enum hwerr_error_type {
19 HWERR_RECOV_CPU,
20 HWERR_RECOV_MEMORY,
21 HWERR_RECOV_PCI,
22 HWERR_RECOV_CXL,
23 HWERR_RECOV_OTHERS,
24 HWERR_RECOV_MAX,
25};
26
18#endif /* _UAPI_VMCORE_H */27#endif /* _UAPI_VMCORE_H */
init/Kconfig+20−0
@@ -1519,6 +1519,24 @@ config BOOT_CONFIG_EMBED_FILE · 1518 unmodified lines
1519 This bootconfig will be used if there is no initrd or no other1519 This bootconfig will be used if there is no initrd or no other
1520 bootconfig in the initrd.1520 bootconfig in the initrd.
1521 1521
1522config CMDLINE_LOG_WRAP_IDEAL_LEN
1523 int "Length to try to wrap the cmdline when logged at boot"
1524 default 1021
1525 range 0 1021
1526 help
1527 At boot time, the kernel command line is logged to the console.
1528 The log message will start with the prefix "Kernel command line: ".
1529 The log message will attempt to be wrapped (split into multiple log
1530 messages) at spaces based on CMDLINE_LOG_WRAP_IDEAL_LEN characters.
1531 If wrapping happens, each log message will start with the prefix and
1532 all but the last message will end with " \". Messages may exceed the
1533 ideal length if a place to wrap isn't found before the specified
1534 number of characters.
1535
1536 A value of 0 disables wrapping, though be warned that the maximum
1537 length of a log message (1021 characters) may cause the cmdline to
1538 be truncated.
1539
1522config INITRAMFS_PRESERVE_MTIME1540config INITRAMFS_PRESERVE_MTIME
1523 bool "Preserve cpio archive mtimes in initramfs"1541 bool "Preserve cpio archive mtimes in initramfs"
1524 depends on BLK_DEV_INITRD1542 depends on BLK_DEV_INITRD
@@ -2171,6 +2189,8 @@ config TRACEPOINTS · 646 unmodified lines
2171 2189
2172source "kernel/Kconfig.kexec"2190source "kernel/Kconfig.kexec"
2173 2191
2192source "kernel/liveupdate/Kconfig"
2193
2174endmenu # General setup2194endmenu # General setup
2175 2195
2176source "arch/Kconfig"2196source "arch/Kconfig"
init/calibrate.c+8−5
@@ -5,19 +5,22 @@ · 4 unmodified lines
5 * Copyright (C) 1991, 1992 Linus Torvalds5 * Copyright (C) 1991, 1992 Linus Torvalds
6 */6 */
7 7
8#include <linux/jiffies.h>
9#include <linux/delay.h>8#include <linux/delay.h>
10#include <linux/init.h>9#include <linux/init.h>
11#include <linux/timex.h>10#include <linux/jiffies.h>
12#include <linux/smp.h>11#include <linux/kstrtox.h>
13#include <linux/percpu.h>12#include <linux/percpu.h>
13#include <linux/printk.h>
14#include <linux/smp.h>
15#include <linux/stddef.h>
16#include <linux/timex.h>
14 17
15unsigned long lpj_fine;18unsigned long lpj_fine;
16unsigned long preset_lpj;19unsigned long preset_lpj;
20
17static int __init lpj_setup(char *str)21static int __init lpj_setup(char *str)
18{22{
19 preset_lpj = simple_strtoul(str,NULL,0);23 return kstrtoul(str, 0, &preset_lpj) == 0;
20 return 1;
21}24}
22 25
23__setup("lpj=", lpj_setup);26__setup("lpj=", lpj_setup);
init/main.c+96−1
@@ -906,6 +906,101 @@ static void __init early_numa_node_init(void) · 905 unmodified lines
906#endif906#endif
907}907}
908 908
909#define KERNEL_CMDLINE_PREFIX "Kernel command line: "
910#define KERNEL_CMDLINE_PREFIX_LEN (sizeof(KERNEL_CMDLINE_PREFIX) - 1)
911#define KERNEL_CMDLINE_CONTINUATION " \\"
912#define KERNEL_CMDLINE_CONTINUATION_LEN (sizeof(KERNEL_CMDLINE_CONTINUATION) - 1)
913
914#define MIN_CMDLINE_LOG_WRAP_IDEAL_LEN (KERNEL_CMDLINE_PREFIX_LEN + \
915 KERNEL_CMDLINE_CONTINUATION_LEN)
916#define CMDLINE_LOG_WRAP_IDEAL_LEN (CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN > \
917 MIN_CMDLINE_LOG_WRAP_IDEAL_LEN ? \
918 CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN : \
919 MIN_CMDLINE_LOG_WRAP_IDEAL_LEN)
920
921#define IDEAL_CMDLINE_LEN (CMDLINE_LOG_WRAP_IDEAL_LEN - KERNEL_CMDLINE_PREFIX_LEN)
922#define IDEAL_CMDLINE_SPLIT_LEN (IDEAL_CMDLINE_LEN - KERNEL_CMDLINE_CONTINUATION_LEN)
923
924/**
925 * print_kernel_cmdline() - Print the kernel cmdline with wrapping.
926 * @cmdline: The cmdline to print.
927 *
928 * Print the kernel command line, trying to wrap based on the Kconfig knob
929 * CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN.
930 *
931 * Wrapping is based on spaces, ignoring quotes. All lines are prefixed
932 * with "Kernel command line: " and lines that are not the last line have
933 * a " \" suffix added to them. The prefix and suffix count towards the
934 * line length for wrapping purposes. The ideal length will be exceeded
935 * if no appropriate place to wrap is found.
936 *
937 * Example output if CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN is 40:
938 * Kernel command line: loglevel=7 \
939 * Kernel command line: init=/sbin/init \
940 * Kernel command line: root=PARTUUID=8c3efc1a-768b-6642-8d0c-89eb782f19f0/PARTNROFF=1 \
941 * Kernel command line: rootwait ro \
942 * Kernel command line: my_quoted_arg="The \
943 * Kernel command line: quick brown fox \
944 * Kernel command line: jumps over the \
945 * Kernel command line: lazy dog."
946 */
947static void __init print_kernel_cmdline(const char *cmdline)
948{
949 size_t len;
950
951 /* Config option of 0 or anything longer than the max disables wrapping */
952 if (CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN == 0 ||
953 IDEAL_CMDLINE_LEN >= COMMAND_LINE_SIZE - 1) {
954 pr_notice("%s%s\n", KERNEL_CMDLINE_PREFIX, cmdline);
955 return;
956 }
957
958 len = strlen(cmdline);
959 while (len > IDEAL_CMDLINE_LEN) {
960 const char *first_space;
961 const char *prev_cutoff;
962 const char *cutoff;
963 int to_print;
964 size_t used;
965
966 /* Find the last ' ' that wouldn't make the line too long */
967 prev_cutoff = NULL;
968 cutoff = cmdline;
969 while (true) {
970 cutoff = strchr(cutoff + 1, ' ');
971 if (!cutoff || cutoff - cmdline > IDEAL_CMDLINE_SPLIT_LEN)
972 break;
973 prev_cutoff = cutoff;
974 }
975 if (prev_cutoff)
976 cutoff = prev_cutoff;
977 else if (!cutoff)
978 break;
979
980 /* Find the beginning and end of the string of spaces */
981 first_space = cutoff;
982 while (first_space > cmdline && first_space[-1] == ' ')
983 first_space--;
984 to_print = first_space - cmdline;
985 while (*cutoff == ' ')
986 cutoff++;
987 used = cutoff - cmdline;
988
989 /* If the whole string is used, break and do the final printout */
990 if (len == used)
991 break;
992
993 if (to_print)
994 pr_notice("%s%.*s%s\n", KERNEL_CMDLINE_PREFIX,
995 to_print, cmdline, KERNEL_CMDLINE_CONTINUATION);
996
997 len -= used;
998 cmdline += used;
999 }
1000 if (len)
1001 pr_notice("%s%s\n", KERNEL_CMDLINE_PREFIX, cmdline);
1002}
1003
909asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector1004asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
910void start_kernel(void)1005void start_kernel(void)
911{1006{
@@ -942,7 +1037,7 @@ void start_kernel(void) · 30 unmodified lines
942 early_numa_node_init();1037 early_numa_node_init();
943 boot_cpu_hotplug_init();1038 boot_cpu_hotplug_init();
944 1039
945 pr_notice("Kernel command line: %s\n", saved_command_line);1040 print_kernel_cmdline(saved_command_line);
946 /* parameters may set static keys */1041 /* parameters may set static keys */
947 parse_early_param();1042 parse_early_param();
948 after_dashes = parse_args("Booting kernel",1043 after_dashes = parse_args("Booting kernel",
ipc/namespace.c+5−4
@@ -76,10 +76,10 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, · 75 unmodified lines
76 76
77 err = -ENOMEM;77 err = -ENOMEM;
78 if (!setup_mq_sysctls(ns))78 if (!setup_mq_sysctls(ns))
79 goto fail_put;79 goto fail_mq_mount;
80 80
81 if (!setup_ipc_sysctls(ns))81 if (!setup_ipc_sysctls(ns))
82 goto fail_mq;82 goto fail_mq_sysctls;
83 83
84 err = msg_init_ns(ns);84 err = msg_init_ns(ns);
85 if (err)85 if (err)
@@ -93,9 +93,10 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, · 7 unmodified lines
93 93
94fail_ipc:94fail_ipc:
95 retire_ipc_sysctls(ns);95 retire_ipc_sysctls(ns);
96fail_mq:96fail_mq_sysctls:
97 retire_mq_sysctls(ns);97 retire_mq_sysctls(ns);
98 98fail_mq_mount:
99 mntput(ns->mq_mnt);
99fail_put:100fail_put:
100 put_user_ns(ns->user_ns);101 put_user_ns(ns->user_ns);
101 ns_common_free(ns);102 ns_common_free(ns);
kernel/Kconfig.kexec+0−24
@@ -94,30 +94,6 @@ config KEXEC_JUMP · 93 unmodified lines
94 Jump between original kernel and kexeced kernel and invoke94 Jump between original kernel and kexeced kernel and invoke
95 code in physical address mode via KEXEC95 code in physical address mode via KEXEC
96 96
97config KEXEC_HANDOVER
98 bool "kexec handover"
99 depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE
100 depends on !DEFERRED_STRUCT_PAGE_INIT
101 select MEMBLOCK_KHO_SCRATCH
102 select KEXEC_FILE
103 select DEBUG_FS
104 select LIBFDT
105 select CMA
106 help
107 Allow kexec to hand over state across kernels by generating and
108 passing additional metadata to the target kernel. This is useful
109 to keep data or state alive across the kexec. For this to work,
110 both source and target kernels need to have this option enabled.
111
112config KEXEC_HANDOVER_DEBUG
113 bool "Enable Kexec Handover debug checks"
114 depends on KEXEC_HANDOVER
115 help
116 This option enables extra sanity checks for the Kexec Handover
117 subsystem. Since, KHO performance is crucial in live update
118 scenarios and the extra code might be adding overhead it is
119 only optionally enabled.
120
121config CRASH_DUMP97config CRASH_DUMP
122 bool "kernel crash dumps"98 bool "kernel crash dumps"
123 default ARCH_DEFAULT_CRASH_DUMP99 default ARCH_DEFAULT_CRASH_DUMP
kernel/Makefile+1−2
@@ -52,6 +52,7 @@ obj-y += printk/ · 51 unmodified lines
52obj-y += irq/52obj-y += irq/
53obj-y += rcu/53obj-y += rcu/
54obj-y += livepatch/54obj-y += livepatch/
55obj-y += liveupdate/
55obj-y += dma/56obj-y += dma/
56obj-y += entry/57obj-y += entry/
57obj-y += unwind/58obj-y += unwind/
@@ -82,8 +83,6 @@ obj-$(CONFIG_CRASH_DUMP_KUNIT_TEST) += crash_core_test.o · 24 unmodified lines
82obj-$(CONFIG_KEXEC) += kexec.o83obj-$(CONFIG_KEXEC) += kexec.o
83obj-$(CONFIG_KEXEC_FILE) += kexec_file.o84obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
84obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o85obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
85obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
86obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
87obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o86obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
88obj-$(CONFIG_COMPAT) += compat.o87obj-$(CONFIG_COMPAT) += compat.o
89obj-$(CONFIG_CGROUPS) += cgroup/88obj-$(CONFIG_CGROUPS) += cgroup/
kernel/configs/debug.config+1−1
@@ -83,7 +83,7 @@ CONFIG_SLUB_DEBUG_ON=y · 82 unmodified lines
83#83#
84# Debug Oops, Lockups and Hangs84# Debug Oops, Lockups and Hangs
85#85#
86# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set86CONFIG_BOOTPARAM_HUNG_TASK_PANIC=0
87# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set87# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
88CONFIG_DEBUG_ATOMIC_SLEEP=y88CONFIG_DEBUG_ATOMIC_SLEEP=y
89CONFIG_DETECT_HUNG_TASK=y89CONFIG_DETECT_HUNG_TASK=y
kernel/crash_reserve.c+3−0
@@ -524,6 +524,9 @@ void __init reserve_crashkernel_cma(unsigned long long cma_size) · 523 unmodified lines
524#ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY524#ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
525static __init int insert_crashkernel_resources(void)525static __init int insert_crashkernel_resources(void)
526{526{
527 if (!arch_add_crash_res_to_iomem())
528 return 0;
529
527 if (crashk_res.start < crashk_res.end)530 if (crashk_res.start < crashk_res.end)
528 insert_resource(&iomem_resource, &crashk_res);531 insert_resource(&iomem_resource, &crashk_res);
529 532
kernel/exit.c+1−3
@@ -251,10 +251,8 @@ repeat: · 250 unmodified lines
251 memset(&post, 0, sizeof(post));251 memset(&post, 0, sizeof(post));
252 252
253 /* don't need to get the RCU readlock here - the process is dead and253 /* don't need to get the RCU readlock here - the process is dead and
254 * can't be modifying its own credentials. But shut RCU-lockdep up */254 * can't be modifying its own credentials. */
255 rcu_read_lock();
256 dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);255 dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
257 rcu_read_unlock();
258 256
259 pidfs_exit(p);257 pidfs_exit(p);
260 cgroup_task_release(p);258 cgroup_task_release(p);
kernel/fork.c+53−10
@@ -208,15 +208,62 @@ struct vm_stack { · 207 unmodified lines
208 struct vm_struct *stack_vm_area;208 struct vm_struct *stack_vm_area;
209};209};
210 210
211static struct vm_struct *alloc_thread_stack_node_from_cache(struct task_struct *tsk, int node)
212{
213 struct vm_struct *vm_area;
214 unsigned int i;
215
216 /*
217 * If the node has memory, we are guaranteed the stacks are backed by local pages.
218 * Otherwise the pages are arbitrary.
219 *
220 * Note that depending on cpuset it is possible we will get migrated to a different
221 * node immediately after allocating here, so this does *not* guarantee locality for
222 * arbitrary callers.
223 */
224 scoped_guard(preempt) {
225 if (node != NUMA_NO_NODE && numa_node_id() != node)
226 return NULL;
227
228 for (i = 0; i < NR_CACHED_STACKS; i++) {
229 vm_area = this_cpu_xchg(cached_stacks[i], NULL);
230 if (vm_area)
231 return vm_area;
232 }
233 }
234
235 return NULL;
236}
237
211static bool try_release_thread_stack_to_cache(struct vm_struct *vm_area)238static bool try_release_thread_stack_to_cache(struct vm_struct *vm_area)
212{239{
213 unsigned int i;240 unsigned int i;
241 int nid;
214 242
215 for (i = 0; i < NR_CACHED_STACKS; i++) {243 /*
216 struct vm_struct *tmp = NULL;244 * Don't cache stacks if any of the pages don't match the local domain, unless
245 * there is no local memory to begin with.
246 *
247 * Note that lack of local memory does not automatically mean it makes no difference
248 * performance-wise which other domain backs the stack. In this case we are merely
249 * trying to avoid constantly going to vmalloc.
250 */
251 scoped_guard(preempt) {
252 nid = numa_node_id();
253 if (node_state(nid, N_MEMORY)) {
254 for (i = 0; i < vm_area->nr_pages; i++) {
255 struct page *page = vm_area->pages[i];
256 if (page_to_nid(page) != nid)
257 return false;
258 }
259 }
260
261 for (i = 0; i < NR_CACHED_STACKS; i++) {
262 struct vm_struct *tmp = NULL;
217 263
218 if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm_area))264 if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm_area))
219 return true;265 return true;
266 }
220 }267 }
221 return false;268 return false;
222}269}
@@ -283,13 +330,9 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node) · 60 unmodified lines
283{330{
284 struct vm_struct *vm_area;331 struct vm_struct *vm_area;
285 void *stack;332 void *stack;
286 int i;
287
288 for (i = 0; i < NR_CACHED_STACKS; i++) {
289 vm_area = this_cpu_xchg(cached_stacks[i], NULL);
290 if (!vm_area)
291 continue;
292 333
334 vm_area = alloc_thread_stack_node_from_cache(tsk, node);
335 if (vm_area) {
293 if (memcg_charge_kernel_stack(vm_area)) {336 if (memcg_charge_kernel_stack(vm_area)) {
294 vfree(vm_area->addr);337 vfree(vm_area->addr);
295 return -ENOMEM;338 return -ENOMEM;
kernel/hung_task.c+38−18
@@ -24,6 +24,7 @@ · 23 unmodified lines
24#include <linux/sched/sysctl.h>24#include <linux/sched/sysctl.h>
25#include <linux/hung_task.h>25#include <linux/hung_task.h>
26#include <linux/rwsem.h>26#include <linux/rwsem.h>
27#include <linux/sys_info.h>
27 28
28#include <trace/events/sched.h>29#include <trace/events/sched.h>
29 30
@@ -50,7 +51,6 @@ static unsigned long __read_mostly sysctl_hung_task_detect_count; · 20 unmodified lines
50 * Zero means infinite timeout - no checking done:51 * Zero means infinite timeout - no checking done:
51 */52 */
52unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;53unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
53EXPORT_SYMBOL_GPL(sysctl_hung_task_timeout_secs);
54 54
55/*55/*
56 * Zero (default value) means use sysctl_hung_task_timeout_secs:56 * Zero (default value) means use sysctl_hung_task_timeout_secs:
@@ -60,12 +60,17 @@ static unsigned long __read_mostly sysctl_hung_task_check_interval_secs; · 3 unmodified lines
60static int __read_mostly sysctl_hung_task_warnings = 10;60static int __read_mostly sysctl_hung_task_warnings = 10;
61 61
62static int __read_mostly did_panic;62static int __read_mostly did_panic;
63static bool hung_task_show_lock;
64static bool hung_task_call_panic;63static bool hung_task_call_panic;
65static bool hung_task_show_all_bt;
66 64
67static struct task_struct *watchdog_task;65static struct task_struct *watchdog_task;
68 66
67/*
68 * A bitmask to control what kinds of system info to be printed when
69 * a hung task is detected, it could be task, memory, lock etc. Refer
70 * include/linux/sys_info.h for detailed bit definition.
71 */
72static unsigned long hung_task_si_mask;
73
69#ifdef CONFIG_SMP74#ifdef CONFIG_SMP
70/*75/*
71 * Should we dump all CPUs backtraces in a hung task event?76 * Should we dump all CPUs backtraces in a hung task event?
@@ -81,7 +86,7 @@ static unsigned int __read_mostly sysctl_hung_task_all_cpu_backtrace; · 9 unmodified lines
81 * hung task is detected:86 * hung task is detected:
82 */87 */
83static unsigned int __read_mostly sysctl_hung_task_panic =88static unsigned int __read_mostly sysctl_hung_task_panic =
84 IS_ENABLED(CONFIG_BOOTPARAM_HUNG_TASK_PANIC);89 CONFIG_BOOTPARAM_HUNG_TASK_PANIC;
85 90
86static int91static int
87hung_task_panic(struct notifier_block *this, unsigned long event, void *ptr)92hung_task_panic(struct notifier_block *this, unsigned long event, void *ptr)
@@ -218,8 +223,11 @@ static inline void debug_show_blocker(struct task_struct *task, unsigned long ti · 130 unmodified lines
218}223}
219#endif224#endif
220 225
221static void check_hung_task(struct task_struct *t, unsigned long timeout)226static void check_hung_task(struct task_struct *t, unsigned long timeout,
227 unsigned long prev_detect_count)
222{228{
229 unsigned long total_hung_task;
230
223 if (!task_is_hung(t, timeout))231 if (!task_is_hung(t, timeout))
224 return;232 return;
225 233
@@ -229,11 +237,11 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) · 3 unmodified lines
229 */237 */
230 sysctl_hung_task_detect_count++;238 sysctl_hung_task_detect_count++;
231 239
240 total_hung_task = sysctl_hung_task_detect_count - prev_detect_count;
232 trace_sched_process_hang(t);241 trace_sched_process_hang(t);
233 242
234 if (sysctl_hung_task_panic) {243 if (sysctl_hung_task_panic && total_hung_task >= sysctl_hung_task_panic) {
235 console_verbose();244 console_verbose();
236 hung_task_show_lock = true;
237 hung_task_call_panic = true;245 hung_task_call_panic = true;
238 }246 }
239 247
@@ -256,10 +264,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) · 16 unmodified lines
256 " disables this message.\n");264 " disables this message.\n");
257 sched_show_task(t);265 sched_show_task(t);
258 debug_show_blocker(t, timeout);266 debug_show_blocker(t, timeout);
259 hung_task_show_lock = true;
260 267
261 if (sysctl_hung_task_all_cpu_backtrace)
262 hung_task_show_all_bt = true;
263 if (!sysctl_hung_task_warnings)268 if (!sysctl_hung_task_warnings)
264 pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");269 pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");
265 }270 }
@@ -300,6 +305,9 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 34 unmodified lines
300 int max_count = sysctl_hung_task_check_count;305 int max_count = sysctl_hung_task_check_count;
301 unsigned long last_break = jiffies;306 unsigned long last_break = jiffies;
302 struct task_struct *g, *t;307 struct task_struct *g, *t;
308 unsigned long prev_detect_count = sysctl_hung_task_detect_count;
309 int need_warning = sysctl_hung_task_warnings;
310 unsigned long si_mask = hung_task_si_mask;
303 311
304 /*312 /*
305 * If the system crashed already then all bets are off,313 * If the system crashed already then all bets are off,
@@ -308,7 +316,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 2 unmodified lines
308 if (test_taint(TAINT_DIE) || did_panic)316 if (test_taint(TAINT_DIE) || did_panic)
309 return;317 return;
310 318
311 hung_task_show_lock = false;319
312 rcu_read_lock();320 rcu_read_lock();
313 for_each_process_thread(g, t) {321 for_each_process_thread(g, t) {
314 322
@@ -320,18 +328,23 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 5 unmodified lines
320 last_break = jiffies;328 last_break = jiffies;
321 }329 }
322 330
323 check_hung_task(t, timeout);331 check_hung_task(t, timeout, prev_detect_count);
324 }332 }
325 unlock:333 unlock:
326 rcu_read_unlock();334 rcu_read_unlock();
327 if (hung_task_show_lock)
328 debug_show_all_locks();
329 335
330 if (hung_task_show_all_bt) {336 if (!(sysctl_hung_task_detect_count - prev_detect_count))
331 hung_task_show_all_bt = false;337 return;
332 trigger_all_cpu_backtrace();338
339 if (need_warning || hung_task_call_panic) {
340 si_mask |= SYS_INFO_LOCKS;
341
342 if (sysctl_hung_task_all_cpu_backtrace)
343 si_mask |= SYS_INFO_ALL_BT;
333 }344 }
334 345
346 sys_info(si_mask);
347
335 if (hung_task_call_panic)348 if (hung_task_call_panic)
336 panic("hung_task: blocked tasks");349 panic("hung_task: blocked tasks");
337}350}
@@ -389,7 +402,7 @@ static const struct ctl_table hung_task_sysctls[] = { · 51 unmodified lines
389 .mode = 0644,402 .mode = 0644,
390 .proc_handler = proc_dointvec_minmax,403 .proc_handler = proc_dointvec_minmax,
391 .extra1 = SYSCTL_ZERO,404 .extra1 = SYSCTL_ZERO,
392 .extra2 = SYSCTL_ONE,405 .extra2 = SYSCTL_INT_MAX,
393 },406 },
394 {407 {
395 .procname = "hung_task_check_count",408 .procname = "hung_task_check_count",
@@ -430,6 +443,13 @@ static const struct ctl_table hung_task_sysctls[] = { · 34 unmodified lines
430 .mode = 0444,443 .mode = 0444,
431 .proc_handler = proc_doulongvec_minmax,444 .proc_handler = proc_doulongvec_minmax,
432 },445 },
446 {
447 .procname = "hung_task_sys_info",
448 .data = &hung_task_si_mask,
449 .maxlen = sizeof(hung_task_si_mask),
450 .mode = 0644,
451 .proc_handler = sysctl_sys_info_handler,
452 },
433};453};
434 454
435static void __init hung_task_sysctl_init(void)455static void __init hung_task_sysctl_init(void)
kernel/kexec_core.c+149−12
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <linux/kexec.h>15#include <linux/kexec.h>
16#include <linux/mutex.h>16#include <linux/mutex.h>
17#include <linux/list.h>17#include <linux/list.h>
18#include <linux/liveupdate.h>
18#include <linux/highmem.h>19#include <linux/highmem.h>
19#include <linux/syscalls.h>20#include <linux/syscalls.h>
20#include <linux/reboot.h>21#include <linux/reboot.h>
@@ -41,6 +42,7 @@ · 20 unmodified lines
41#include <linux/objtool.h>42#include <linux/objtool.h>
42#include <linux/kmsg_dump.h>43#include <linux/kmsg_dump.h>
43#include <linux/dma-map-ops.h>44#include <linux/dma-map-ops.h>
45#include <linux/sysfs.h>
44 46
45#include <asm/page.h>47#include <asm/page.h>
46#include <asm/sections.h>48#include <asm/sections.h>
@@ -742,7 +744,6 @@ static int kimage_load_cma_segment(struct kimage *image, int idx) · 695 unmodified lines
742 struct kexec_segment *segment = &image->segment[idx];744 struct kexec_segment *segment = &image->segment[idx];
743 struct page *cma = image->segment_cma[idx];745 struct page *cma = image->segment_cma[idx];
744 char *ptr = page_address(cma);746 char *ptr = page_address(cma);
745 unsigned long maddr;
746 size_t ubytes, mbytes;747 size_t ubytes, mbytes;
747 int result = 0;748 int result = 0;
748 unsigned char __user *buf = NULL;749 unsigned char __user *buf = NULL;
@@ -754,15 +755,12 @@ static int kimage_load_cma_segment(struct kimage *image, int idx) · 5 unmodified lines
754 buf = segment->buf;755 buf = segment->buf;
755 ubytes = segment->bufsz;756 ubytes = segment->bufsz;
756 mbytes = segment->memsz;757 mbytes = segment->memsz;
757 maddr = segment->mem;
758 758
759 /* Then copy from source buffer to the CMA one */759 /* Then copy from source buffer to the CMA one */
760 while (mbytes) {760 while (mbytes) {
761 size_t uchunk, mchunk;761 size_t uchunk, mchunk;
762 762
763 ptr += maddr & ~PAGE_MASK;763 mchunk = min_t(size_t, mbytes, PAGE_SIZE);
764 mchunk = min_t(size_t, mbytes,
765 PAGE_SIZE - (maddr & ~PAGE_MASK));
766 uchunk = min(ubytes, mchunk);764 uchunk = min(ubytes, mchunk);
767 765
768 if (uchunk) {766 if (uchunk) {
@@ -784,7 +782,6 @@ static int kimage_load_cma_segment(struct kimage *image, int idx) · 15 unmodified lines
784 }782 }
785 783
786 ptr += mchunk;784 ptr += mchunk;
787 maddr += mchunk;
788 mbytes -= mchunk;785 mbytes -= mchunk;
789 786
790 cond_resched();787 cond_resched();
@@ -839,9 +836,7 @@ static int kimage_load_normal_segment(struct kimage *image, int idx) · 48 unmodified lines
839 ptr = kmap_local_page(page);836 ptr = kmap_local_page(page);
840 /* Start with a clear page */837 /* Start with a clear page */
841 clear_page(ptr);838 clear_page(ptr);
842 ptr += maddr & ~PAGE_MASK;839 mchunk = min_t(size_t, mbytes, PAGE_SIZE);
843 mchunk = min_t(size_t, mbytes,
844 PAGE_SIZE - (maddr & ~PAGE_MASK));
845 uchunk = min(ubytes, mchunk);840 uchunk = min(ubytes, mchunk);
846 841
847 if (uchunk) {842 if (uchunk) {
@@ -904,9 +899,7 @@ static int kimage_load_crash_segment(struct kimage *image, int idx) · 56 unmodified lines
904 }899 }
905 arch_kexec_post_alloc_pages(page_address(page), 1, 0);900 arch_kexec_post_alloc_pages(page_address(page), 1, 0);
906 ptr = kmap_local_page(page);901 ptr = kmap_local_page(page);
907 ptr += maddr & ~PAGE_MASK;902 mchunk = min_t(size_t, mbytes, PAGE_SIZE);
908 mchunk = min_t(size_t, mbytes,
909 PAGE_SIZE - (maddr & ~PAGE_MASK));
910 uchunk = min(ubytes, mchunk);903 uchunk = min(ubytes, mchunk);
911 if (mchunk > uchunk) {904 if (mchunk > uchunk) {
912 /* Zero the trailing part of the page */905 /* Zero the trailing part of the page */
@@ -1146,6 +1139,10 @@ int kernel_kexec(void) · 233 unmodified lines
1146 goto Unlock;1139 goto Unlock;
1147 }1140 }
1148 1141
1142 error = liveupdate_reboot();
1143 if (error)
1144 goto Unlock;
1145
1149#ifdef CONFIG_KEXEC_JUMP1146#ifdef CONFIG_KEXEC_JUMP
1150 if (kexec_image->preserve_context) {1147 if (kexec_image->preserve_context) {
1151 /*1148 /*
@@ -1229,3 +1226,143 @@ int kernel_kexec(void) · 77 unmodified lines
1229 kexec_unlock();1226 kexec_unlock();
1230 return error;1227 return error;
1231}1228}
1229
1230static ssize_t loaded_show(struct kobject *kobj,
1231 struct kobj_attribute *attr, char *buf)
1232{
1233 return sysfs_emit(buf, "%d\n", !!kexec_image);
1234}
1235static struct kobj_attribute loaded_attr = __ATTR_RO(loaded);
1236
1237#ifdef CONFIG_CRASH_DUMP
1238static ssize_t crash_loaded_show(struct kobject *kobj,
1239 struct kobj_attribute *attr, char *buf)
1240{
1241 return sysfs_emit(buf, "%d\n", kexec_crash_loaded());
1242}
1243static struct kobj_attribute crash_loaded_attr = __ATTR_RO(crash_loaded);
1244
1245#ifdef CONFIG_CRASH_RESERVE
1246static ssize_t crash_cma_ranges_show(struct kobject *kobj,
1247 struct kobj_attribute *attr, char *buf)
1248{
1249
1250 ssize_t len = 0;
1251 int i;
1252
1253 for (i = 0; i < crashk_cma_cnt; ++i) {
1254 len += sysfs_emit_at(buf, len, "%08llx-%08llx\n",
1255 crashk_cma_ranges[i].start,
1256 crashk_cma_ranges[i].end);
1257 }
1258 return len;
1259}
1260static struct kobj_attribute crash_cma_ranges_attr = __ATTR_RO(crash_cma_ranges);
1261#endif
1262
1263static ssize_t crash_size_show(struct kobject *kobj,
1264 struct kobj_attribute *attr, char *buf)
1265{
1266 ssize_t size = crash_get_memory_size();
1267
1268 if (size < 0)
1269 return size;
1270
1271 return sysfs_emit(buf, "%zd\n", size);
1272}
1273static ssize_t crash_size_store(struct kobject *kobj,
1274 struct kobj_attribute *attr,
1275 const char *buf, size_t count)
1276{
1277 unsigned long cnt;
1278 int ret;
1279
1280 if (kstrtoul(buf, 0, &cnt))
1281 return -EINVAL;
1282
1283 ret = crash_shrink_memory(cnt);
1284 return ret < 0 ? ret : count;
1285}
1286static struct kobj_attribute crash_size_attr = __ATTR_RW(crash_size);
1287
1288#ifdef CONFIG_CRASH_HOTPLUG
1289static ssize_t crash_elfcorehdr_size_show(struct kobject *kobj,
1290 struct kobj_attribute *attr, char *buf)
1291{
1292 unsigned int sz = crash_get_elfcorehdr_size();
1293
1294 return sysfs_emit(buf, "%u\n", sz);
1295}
1296static struct kobj_attribute crash_elfcorehdr_size_attr = __ATTR_RO(crash_elfcorehdr_size);
1297
1298#endif /* CONFIG_CRASH_HOTPLUG */
1299#endif /* CONFIG_CRASH_DUMP */
1300
1301static struct attribute *kexec_attrs[] = {
1302 &loaded_attr.attr,
1303#ifdef CONFIG_CRASH_DUMP
1304 &crash_loaded_attr.attr,
1305 &crash_size_attr.attr,
1306#ifdef CONFIG_CRASH_RESERVE
1307 &crash_cma_ranges_attr.attr,
1308#endif
1309#ifdef CONFIG_CRASH_HOTPLUG
1310 &crash_elfcorehdr_size_attr.attr,
1311#endif
1312#endif
1313 NULL
1314};
1315
1316struct kexec_link_entry {
1317 const char *target;
1318 const char *name;
1319};
1320
1321static struct kexec_link_entry kexec_links[] = {
1322 { "loaded", "kexec_loaded" },
1323#ifdef CONFIG_CRASH_DUMP
1324 { "crash_loaded", "kexec_crash_loaded" },
1325 { "crash_size", "kexec_crash_size" },
1326#ifdef CONFIG_CRASH_RESERVE
1327 {"crash_cma_ranges", "kexec_crash_cma_ranges"},
1328#endif
1329#ifdef CONFIG_CRASH_HOTPLUG
1330 { "crash_elfcorehdr_size", "crash_elfcorehdr_size" },
1331#endif
1332#endif
1333};
1334
1335static struct kobject *kexec_kobj;
1336ATTRIBUTE_GROUPS(kexec);
1337
1338static int __init init_kexec_sysctl(void)
1339{
1340 int error;
1341 int i;
1342
1343 kexec_kobj = kobject_create_and_add("kexec", kernel_kobj);
1344 if (!kexec_kobj) {
1345 pr_err("failed to create kexec kobject\n");
1346 return -ENOMEM;
1347 }
1348
1349 error = sysfs_create_groups(kexec_kobj, kexec_groups);
1350 if (error)
1351 goto kset_exit;
1352
1353 for (i = 0; i < ARRAY_SIZE(kexec_links); i++) {
1354 error = compat_only_sysfs_link_entry_to_kobj(kernel_kobj, kexec_kobj,
1355 kexec_links[i].target,
1356 kexec_links[i].name);
1357 if (error)
1358 pr_err("Unable to create %s symlink (%d)", kexec_links[i].name, error);
1359 }
1360
1361 return 0;
1362
1363kset_exit:
1364 kobject_put(kexec_kobj);
1365 return error;
1366}
1367
1368subsys_initcall(init_kexec_sysctl);
kernel/kexec_handover_internal.h+0−20
@@ -1,20 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef LINUX_KEXEC_HANDOVER_INTERNAL_H
3#define LINUX_KEXEC_HANDOVER_INTERNAL_H
4
5#include <linux/kexec_handover.h>
6#include <linux/types.h>
7
8extern struct kho_scratch *kho_scratch;
9extern unsigned int kho_scratch_cnt;
10
11#ifdef CONFIG_KEXEC_HANDOVER_DEBUG
12bool kho_scratch_overlap(phys_addr_t phys, size_t size);
13#else
14static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
15{
16 return false;
17}
18#endif /* CONFIG_KEXEC_HANDOVER_DEBUG */
19
20#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */
kernel/ksysfs.c+1−67
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <linux/sysfs.h>12#include <linux/sysfs.h>
13#include <linux/export.h>13#include <linux/export.h>
14#include <linux/init.h>14#include <linux/init.h>
15#include <linux/kexec.h>15#include <linux/vmcore_info.h>
16#include <linux/profile.h>16#include <linux/profile.h>
17#include <linux/stat.h>17#include <linux/stat.h>
18#include <linux/sched.h>18#include <linux/sched.h>
@@ -119,50 +119,6 @@ static ssize_t profiling_store(struct kobject *kobj, · 100 unmodified lines
119KERNEL_ATTR_RW(profiling);119KERNEL_ATTR_RW(profiling);
120#endif120#endif
121 121
122#ifdef CONFIG_KEXEC_CORE
123static ssize_t kexec_loaded_show(struct kobject *kobj,
124 struct kobj_attribute *attr, char *buf)
125{
126 return sysfs_emit(buf, "%d\n", !!kexec_image);
127}
128KERNEL_ATTR_RO(kexec_loaded);
129
130#ifdef CONFIG_CRASH_DUMP
131static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
132 struct kobj_attribute *attr, char *buf)
133{
134 return sysfs_emit(buf, "%d\n", kexec_crash_loaded());
135}
136KERNEL_ATTR_RO(kexec_crash_loaded);
137
138static ssize_t kexec_crash_size_show(struct kobject *kobj,
139 struct kobj_attribute *attr, char *buf)
140{
141 ssize_t size = crash_get_memory_size();
142
143 if (size < 0)
144 return size;
145
146 return sysfs_emit(buf, "%zd\n", size);
147}
148static ssize_t kexec_crash_size_store(struct kobject *kobj,
149 struct kobj_attribute *attr,
150 const char *buf, size_t count)
151{
152 unsigned long cnt;
153 int ret;
154
155 if (kstrtoul(buf, 0, &cnt))
156 return -EINVAL;
157
158 ret = crash_shrink_memory(cnt);
159 return ret < 0 ? ret : count;
160}
161KERNEL_ATTR_RW(kexec_crash_size);
162
163#endif /* CONFIG_CRASH_DUMP*/
164#endif /* CONFIG_KEXEC_CORE */
165
166#ifdef CONFIG_VMCORE_INFO122#ifdef CONFIG_VMCORE_INFO
167 123
168static ssize_t vmcoreinfo_show(struct kobject *kobj,124static ssize_t vmcoreinfo_show(struct kobject *kobj,
@@ -174,18 +130,6 @@ static ssize_t vmcoreinfo_show(struct kobject *kobj, · 5 unmodified lines
174}130}
175KERNEL_ATTR_RO(vmcoreinfo);131KERNEL_ATTR_RO(vmcoreinfo);
176 132
177#ifdef CONFIG_CRASH_HOTPLUG
178static ssize_t crash_elfcorehdr_size_show(struct kobject *kobj,
179 struct kobj_attribute *attr, char *buf)
180{
181 unsigned int sz = crash_get_elfcorehdr_size();
182
183 return sysfs_emit(buf, "%u\n", sz);
184}
185KERNEL_ATTR_RO(crash_elfcorehdr_size);
186
187#endif
188
189#endif /* CONFIG_VMCORE_INFO */133#endif /* CONFIG_VMCORE_INFO */
190 134
191/* whether file capabilities are enabled */135/* whether file capabilities are enabled */
@@ -255,18 +199,8 @@ static struct attribute * kernel_attrs[] = { · 63 unmodified lines
255#ifdef CONFIG_PROFILING199#ifdef CONFIG_PROFILING
256 &profiling_attr.attr,200 &profiling_attr.attr,
257#endif201#endif
258#ifdef CONFIG_KEXEC_CORE
259 &kexec_loaded_attr.attr,
260#ifdef CONFIG_CRASH_DUMP
261 &kexec_crash_loaded_attr.attr,
262 &kexec_crash_size_attr.attr,
263#endif
264#endif
265#ifdef CONFIG_VMCORE_INFO202#ifdef CONFIG_VMCORE_INFO
266 &vmcoreinfo_attr.attr,203 &vmcoreinfo_attr.attr,
267#ifdef CONFIG_CRASH_HOTPLUG
268 &crash_elfcorehdr_size_attr.attr,
269#endif
270#endif204#endif
271#ifndef CONFIG_TINY_RCU205#ifndef CONFIG_TINY_RCU
272 &rcu_expedited_attr.attr,206 &rcu_expedited_attr.attr,
kernel/liveupdate/Kconfig+75−0
@@ -0,0 +1,75 @@
1# SPDX-License-Identifier: GPL-2.0-only
2
3menu "Live Update and Kexec HandOver"
4 depends on !DEFERRED_STRUCT_PAGE_INIT
5
6config KEXEC_HANDOVER
7 bool "kexec handover"
8 depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE
9 depends on !DEFERRED_STRUCT_PAGE_INIT
10 select MEMBLOCK_KHO_SCRATCH
11 select KEXEC_FILE
12 select LIBFDT
13 select CMA
14 help
15 Allow kexec to hand over state across kernels by generating and
16 passing additional metadata to the target kernel. This is useful
17 to keep data or state alive across the kexec. For this to work,
18 both source and target kernels need to have this option enabled.
19
20config KEXEC_HANDOVER_DEBUG
21 bool "Enable Kexec Handover debug checks"
22 depends on KEXEC_HANDOVER
23 help
24 This option enables extra sanity checks for the Kexec Handover
25 subsystem. Since, KHO performance is crucial in live update
26 scenarios and the extra code might be adding overhead it is
27 only optionally enabled.
28
29config KEXEC_HANDOVER_DEBUGFS
30 bool "kexec handover debugfs interface"
31 default KEXEC_HANDOVER
32 depends on KEXEC_HANDOVER
33 select DEBUG_FS
34 help
35 Allow to control kexec handover device tree via debugfs
36 interface, i.e. finalize the state or aborting the finalization.
37 Also, enables inspecting the KHO fdt trees with the debugfs binary
38 blobs.
39
40config KEXEC_HANDOVER_ENABLE_DEFAULT
41 bool "Enable kexec handover by default"
42 depends on KEXEC_HANDOVER
43 help
44 Enable Kexec Handover by default. This avoids the need to
45 explicitly pass 'kho=on' on the kernel command line.
46
47 This is useful for systems where KHO is a prerequisite for other
48 features, such as Live Update, ensuring the mechanism is always
49 active.
50
51 The default behavior can still be overridden at boot time by
52 passing 'kho=off'.
53
54config LIVEUPDATE
55 bool "Live Update Orchestrator"
56 depends on KEXEC_HANDOVER
57 help
58 Enable the Live Update Orchestrator. Live Update is a mechanism,
59 typically based on kexec, that allows the kernel to be updated
60 while keeping selected devices operational across the transition.
61 These devices are intended to be reclaimed by the new kernel and
62 re-attached to their original workload without requiring a device
63 reset.
64
65 Ability to handover a device from current to the next kernel depends
66 on specific support within device drivers and related kernel
67 subsystems.
68
69 This feature primarily targets virtual machine hosts to quickly update
70 the kernel hypervisor with minimal disruption to the running virtual
71 machines.
72
73 If unsure, say N.
74
75endmenu
kernel/liveupdate/Makefile+12−0
@@ -0,0 +1,12 @@
1# SPDX-License-Identifier: GPL-2.0
2
3luo-y := \
4 luo_core.o \
5 luo_file.o \
6 luo_session.o
7
8obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
9obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
10obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o
11
12obj-$(CONFIG_LIVEUPDATE) += luo.o
kernel/liveupdate/kexec_handover.crenamed from kernel/kexec_handover.c+333−383
@@ -4,21 +4,22 @@ · 3 unmodified lines
4 * Copyright (C) 2023 Alexander Graf <graf@amazon.com>4 * Copyright (C) 2023 Alexander Graf <graf@amazon.com>
5 * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org>5 * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org>
6 * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com>6 * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com>
7 * Copyright (C) 2025 Pasha Tatashin <pasha.tatashin@soleen.com>
7 */8 */
8 9
9#define pr_fmt(fmt) "KHO: " fmt10#define pr_fmt(fmt) "KHO: " fmt
10 11
11#include <linux/cleanup.h>12#include <linux/cleanup.h>
12#include <linux/cma.h>13#include <linux/cma.h>
14#include <linux/kmemleak.h>
13#include <linux/count_zeros.h>15#include <linux/count_zeros.h>
14#include <linux/debugfs.h>
15#include <linux/kexec.h>16#include <linux/kexec.h>
16#include <linux/kexec_handover.h>17#include <linux/kexec_handover.h>
17#include <linux/libfdt.h>18#include <linux/libfdt.h>
18#include <linux/list.h>19#include <linux/list.h>
19#include <linux/memblock.h>20#include <linux/memblock.h>
20#include <linux/notifier.h>
21#include <linux/page-isolation.h>21#include <linux/page-isolation.h>
22#include <linux/unaligned.h>
22#include <linux/vmalloc.h>23#include <linux/vmalloc.h>
23 24
24#include <asm/early_ioremap.h>25#include <asm/early_ioremap.h>
@@ -28,8 +29,9 @@ · 3 unmodified lines
28 * KHO is tightly coupled with mm init and needs access to some of mm29 * KHO is tightly coupled with mm init and needs access to some of mm
29 * internal APIs.30 * internal APIs.
30 */31 */
31#include "../mm/internal.h"32#include "../../mm/internal.h"
32#include "kexec_internal.h"33#include "../kexec_internal.h"
34#include "kexec_handover_internal.h"
33 35
34#define KHO_FDT_COMPATIBLE "kho-v1"36#define KHO_FDT_COMPATIBLE "kho-v1"
35#define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"37#define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map"
@@ -51,7 +53,7 @@ union kho_page_info { · 15 unmodified lines
51 53
52static_assert(sizeof(union kho_page_info) == sizeof(((struct page *)0)->private));54static_assert(sizeof(union kho_page_info) == sizeof(((struct page *)0)->private));
53 55
54static bool kho_enable __ro_after_init;56static bool kho_enable __ro_after_init = IS_ENABLED(CONFIG_KEXEC_HANDOVER_ENABLE_DEFAULT);
55 57
56bool kho_is_enabled(void)58bool kho_is_enabled(void)
57{59{
@@ -103,34 +105,19 @@ struct kho_mem_track { · 45 unmodified lines
103 105
104struct khoser_mem_chunk;106struct khoser_mem_chunk;
105 107
106struct kho_serialization {
107 struct page *fdt;
108 struct list_head fdt_list;
109 struct dentry *sub_fdt_dir;
110 struct kho_mem_track track;
111 /* First chunk of serialized preserved memory map */
112 struct khoser_mem_chunk *preserved_mem_map;
113};
114
115struct kho_out {108struct kho_out {
116 struct blocking_notifier_head chain_head;109 void *fdt;
117 110 bool finalized;
118 struct dentry *dir;
119
120 struct mutex lock; /* protects KHO FDT finalization */111 struct mutex lock; /* protects KHO FDT finalization */
121 112
122 struct kho_serialization ser;113 struct kho_mem_track track;
123 bool finalized;114 struct kho_debugfs dbg;
124};115};
125 116
126static struct kho_out kho_out = {117static struct kho_out kho_out = {
127 .chain_head = BLOCKING_NOTIFIER_INIT(kho_out.chain_head),
128 .lock = __MUTEX_INITIALIZER(kho_out.lock),118 .lock = __MUTEX_INITIALIZER(kho_out.lock),
129 .ser = {119 .track = {
130 .fdt_list = LIST_HEAD_INIT(kho_out.ser.fdt_list),120 .orders = XARRAY_INIT(kho_out.track.orders, 0),
131 .track = {
132 .orders = XARRAY_INIT(kho_out.ser.track.orders, 0),
133 },
134 },121 },
135 .finalized = false,122 .finalized = false,
136};123};
@@ -159,26 +146,33 @@ static void *xa_load_or_alloc(struct xarray *xa, unsigned long index) · 22 unmodified lines
159 return no_free_ptr(elm);146 return no_free_ptr(elm);
160}147}
161 148
162static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn,149static void __kho_unpreserve_order(struct kho_mem_track *track, unsigned long pfn,
163 unsigned long end_pfn)150 unsigned int order)
164{151{
165 struct kho_mem_phys_bits *bits;152 struct kho_mem_phys_bits *bits;
166 struct kho_mem_phys *physxa;153 struct kho_mem_phys *physxa;
154 const unsigned long pfn_high = pfn >> order;
167 155
168 while (pfn < end_pfn) {156 physxa = xa_load(&track->orders, order);
169 const unsigned int order =157 if (WARN_ON_ONCE(!physxa))
170 min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));158 return;
171 const unsigned long pfn_high = pfn >> order;
172 159
173 physxa = xa_load(&track->orders, order);160 bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS);
174 if (WARN_ON_ONCE(!physxa))161 if (WARN_ON_ONCE(!bits))
175 return;162 return;
176 163
177 bits = xa_load(&physxa->phys_bits, pfn_high / PRESERVE_BITS);164 clear_bit(pfn_high % PRESERVE_BITS, bits->preserve);
178 if (WARN_ON_ONCE(!bits))165}
179 return;
180 166
181 clear_bit(pfn_high % PRESERVE_BITS, bits->preserve);167static void __kho_unpreserve(struct kho_mem_track *track, unsigned long pfn,
168 unsigned long end_pfn)
169{
170 unsigned int order;
171
172 while (pfn < end_pfn) {
173 order = min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
174
175 __kho_unpreserve_order(track, pfn, order);
182 176
183 pfn += 1 << order;177 pfn += 1 << order;
184 }178 }
@@ -192,10 +186,6 @@ static int __kho_preserve_order(struct kho_mem_track *track, unsigned long pfn, · 7 unmodified lines
192 const unsigned long pfn_high = pfn >> order;186 const unsigned long pfn_high = pfn >> order;
193 187
194 might_sleep();188 might_sleep();
195
196 if (kho_out.finalized)
197 return -EBUSY;
198
199 physxa = xa_load(&track->orders, order);189 physxa = xa_load(&track->orders, order);
200 if (!physxa) {190 if (!physxa) {
201 int err;191 int err;
@@ -229,11 +219,11 @@ static int __kho_preserve_order(struct kho_mem_track *track, unsigned long pfn, · 27 unmodified lines
229 return 0;219 return 0;
230}220}
231 221
232static struct page *kho_restore_page(phys_addr_t phys)222static struct page *kho_restore_page(phys_addr_t phys, bool is_folio)
233{223{
234 struct page *page = pfn_to_online_page(PHYS_PFN(phys));224 struct page *page = pfn_to_online_page(PHYS_PFN(phys));
225 unsigned int nr_pages, ref_cnt;
235 union kho_page_info info;226 union kho_page_info info;
236 unsigned int nr_pages;
237 227
238 if (!page)228 if (!page)
239 return NULL;229 return NULL;
@@ -253,11 +243,16 @@ static struct page *kho_restore_page(phys_addr_t phys) · 13 unmodified lines
253 /* Head page gets refcount of 1. */243 /* Head page gets refcount of 1. */
254 set_page_count(page, 1);244 set_page_count(page, 1);
255 245
256 /* For higher order folios, tail pages get a page count of zero. */246 /*
247 * For higher order folios, tail pages get a page count of zero.
248 * For physically contiguous order-0 pages every pages gets a page
249 * count of 1
250 */
251 ref_cnt = is_folio ? 0 : 1;
257 for (unsigned int i = 1; i < nr_pages; i++)252 for (unsigned int i = 1; i < nr_pages; i++)
258 set_page_count(page + i, 0);253 set_page_count(page + i, ref_cnt);
259 254
260 if (info.order > 0)255 if (is_folio && info.order)
261 prep_compound_page(page, info.order);256 prep_compound_page(page, info.order);
262 257
263 adjust_managed_page_count(page, nr_pages);258 adjust_managed_page_count(page, nr_pages);
@@ -272,7 +267,7 @@ static struct page *kho_restore_page(phys_addr_t phys) · 8 unmodified lines
272 */267 */
273struct folio *kho_restore_folio(phys_addr_t phys)268struct folio *kho_restore_folio(phys_addr_t phys)
274{269{
275 struct page *page = kho_restore_page(phys);270 struct page *page = kho_restore_page(phys, true);
276 271
277 return page ? page_folio(page) : NULL;272 return page ? page_folio(page) : NULL;
278}273}
@@ -297,11 +292,10 @@ struct page *kho_restore_pages(phys_addr_t phys, unsigned int nr_pages) · 18 unmodified lines
297 while (pfn < end_pfn) {292 while (pfn < end_pfn) {
298 const unsigned int order =293 const unsigned int order =
299 min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));294 min(count_trailing_zeros(pfn), ilog2(end_pfn - pfn));
300 struct page *page = kho_restore_page(PFN_PHYS(pfn));295 struct page *page = kho_restore_page(PFN_PHYS(pfn), false);
301 296
302 if (!page)297 if (!page)
303 return NULL;298 return NULL;
304 split_page(page, order);
305 pfn += 1 << order;299 pfn += 1 << order;
306 }300 }
307 301
@@ -371,11 +365,32 @@ static void kho_mem_ser_free(struct khoser_mem_chunk *first_chunk) · 63 unmodified lines
371 struct khoser_mem_chunk *tmp = chunk;365 struct khoser_mem_chunk *tmp = chunk;
372 366
373 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);367 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
374 kfree(tmp);368 free_page((unsigned long)tmp);
375 }369 }
376}370}
377 371
378static int kho_mem_serialize(struct kho_serialization *ser)372/*
373 * Update memory map property, if old one is found discard it via
374 * kho_mem_ser_free().
375 */
376static void kho_update_memory_map(struct khoser_mem_chunk *first_chunk)
377{
378 void *ptr;
379 u64 phys;
380
381 ptr = fdt_getprop_w(kho_out.fdt, 0, PROP_PRESERVED_MEMORY_MAP, NULL);
382
383 /* Check and discard previous memory map */
384 phys = get_unaligned((u64 *)ptr);
385 if (phys)
386 kho_mem_ser_free((struct khoser_mem_chunk *)phys_to_virt(phys));
387
388 /* Update with the new value */
389 phys = first_chunk ? (u64)virt_to_phys(first_chunk) : 0;
390 put_unaligned(phys, (u64 *)ptr);
391}
392
393static int kho_mem_serialize(struct kho_out *kho_out)
379{394{
380 struct khoser_mem_chunk *first_chunk = NULL;395 struct khoser_mem_chunk *first_chunk = NULL;
381 struct khoser_mem_chunk *chunk = NULL;396 struct khoser_mem_chunk *chunk = NULL;
@@ -383,7 +398,7 @@ static int kho_mem_serialize(struct kho_serialization *ser) · 1 unmodified line
383 unsigned long order;398 unsigned long order;
384 int err = -ENOMEM;399 int err = -ENOMEM;
385 400
386 xa_for_each(&ser->track.orders, order, physxa) {401 xa_for_each(&kho_out->track.orders, order, physxa) {
387 struct kho_mem_phys_bits *bits;402 struct kho_mem_phys_bits *bits;
388 unsigned long phys;403 unsigned long phys;
389 404
@@ -415,7 +430,7 @@ static int kho_mem_serialize(struct kho_serialization *ser) · 25 unmodified lines
415 }430 }
416 }431 }
417 432
418 ser->preserved_mem_map = first_chunk;433 kho_update_memory_map(first_chunk);
419 434
420 return 0;435 return 0;
421 436
@@ -445,20 +460,27 @@ static void __init deserialize_bitmap(unsigned int order, · 23 unmodified lines
445 }460 }
446}461}
447 462
448static void __init kho_mem_deserialize(const void *fdt)463/* Return true if memory was deserizlied */
464static bool __init kho_mem_deserialize(const void *fdt)
449{465{
450 struct khoser_mem_chunk *chunk;466 struct khoser_mem_chunk *chunk;
451 const phys_addr_t *mem;467 const void *mem_ptr;
468 u64 mem;
452 int len;469 int len;
453 470
454 mem = fdt_getprop(fdt, 0, PROP_PRESERVED_MEMORY_MAP, &len);471 mem_ptr = fdt_getprop(fdt, 0, PROP_PRESERVED_MEMORY_MAP, &len);
455 472 if (!mem_ptr || len != sizeof(u64)) {
456 if (!mem || len != sizeof(*mem)) {
457 pr_err("failed to get preserved memory bitmaps\n");473 pr_err("failed to get preserved memory bitmaps\n");
458 return;474 return false;
459 }475 }
460 476
461 chunk = *mem ? phys_to_virt(*mem) : NULL;477 mem = get_unaligned((const u64 *)mem_ptr);
478 chunk = mem ? phys_to_virt(mem) : NULL;
479
480 /* No preserved physical pages were passed, no deserialization */
481 if (!chunk)
482 return false;
483
462 while (chunk) {484 while (chunk) {
463 unsigned int i;485 unsigned int i;
464 486
@@ -467,6 +489,8 @@ static void __init kho_mem_deserialize(const void *fdt) · 2 unmodified lines
467 &chunk->bitmaps[i]);489 &chunk->bitmaps[i]);
468 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);490 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
469 }491 }
492
493 return true;
470}494}
471 495
472/*496/*
@@ -674,40 +698,8 @@ err_disable_kho: · 201 unmodified lines
674 kho_enable = false;698 kho_enable = false;
675}699}
676 700
677struct fdt_debugfs {
678 struct list_head list;
679 struct debugfs_blob_wrapper wrapper;
680 struct dentry *file;
681};
682
683static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
684 const char *name, const void *fdt)
685{
686 struct fdt_debugfs *f;
687 struct dentry *file;
688
689 f = kmalloc(sizeof(*f), GFP_KERNEL);
690 if (!f)
691 return -ENOMEM;
692
693 f->wrapper.data = (void *)fdt;
694 f->wrapper.size = fdt_totalsize(fdt);
695
696 file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
697 if (IS_ERR(file)) {
698 kfree(f);
699 return PTR_ERR(file);
700 }
701
702 f->file = file;
703 list_add(&f->list, list);
704
705 return 0;
706}
707
708/**701/**
709 * kho_add_subtree - record the physical address of a sub FDT in KHO root tree.702 * kho_add_subtree - record the physical address of a sub FDT in KHO root tree.
710 * @ser: serialization control object passed by KHO notifiers.
711 * @name: name of the sub tree.703 * @name: name of the sub tree.
712 * @fdt: the sub tree blob.704 * @fdt: the sub tree blob.
713 *705 *
@@ -716,38 +708,76 @@ static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir, · 2 unmodified lines
716 * by KHO for the new kernel to retrieve it after kexec.708 * by KHO for the new kernel to retrieve it after kexec.
717 *709 *
718 * A debugfs blob entry is also created at710 * A debugfs blob entry is also created at
719 * ``/sys/kernel/debug/kho/out/sub_fdts/@name``.711 * ``/sys/kernel/debug/kho/out/sub_fdts/@name`` when kernel is configured with
712 * CONFIG_KEXEC_HANDOVER_DEBUGFS
720 *713 *
721 * Return: 0 on success, error code on failure714 * Return: 0 on success, error code on failure
722 */715 */
723int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt)716int kho_add_subtree(const char *name, void *fdt)
724{717{
725 int err = 0;718 phys_addr_t phys = virt_to_phys(fdt);
726 u64 phys = (u64)virt_to_phys(fdt);719 void *root_fdt = kho_out.fdt;
727 void *root = page_to_virt(ser->fdt);720 int err = -ENOMEM;
721 int off, fdt_err;
728 722
729 err |= fdt_begin_node(root, name);723 guard(mutex)(&kho_out.lock);
730 err |= fdt_property(root, PROP_SUB_FDT, &phys, sizeof(phys));
731 err |= fdt_end_node(root);
732 724
733 if (err)725 fdt_err = fdt_open_into(root_fdt, root_fdt, PAGE_SIZE);
726 if (fdt_err < 0)
734 return err;727 return err;
735 728
736 return kho_debugfs_fdt_add(&ser->fdt_list, ser->sub_fdt_dir, name, fdt);729 off = fdt_add_subnode(root_fdt, 0, name);
730 if (off < 0) {
731 if (off == -FDT_ERR_EXISTS)
732 err = -EEXIST;
733 goto out_pack;
734 }
735
736 err = fdt_setprop(root_fdt, off, PROP_SUB_FDT, &phys, sizeof(phys));
737 if (err < 0)
738 goto out_pack;
739
740 WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false));
741
742out_pack:
743 fdt_pack(root_fdt);
744
745 return err;
737}746}
738EXPORT_SYMBOL_GPL(kho_add_subtree);747EXPORT_SYMBOL_GPL(kho_add_subtree);
739 748
740int register_kho_notifier(struct notifier_block *nb)749void kho_remove_subtree(void *fdt)
741{750{
742 return blocking_notifier_chain_register(&kho_out.chain_head, nb);751 phys_addr_t target_phys = virt_to_phys(fdt);
743}752 void *root_fdt = kho_out.fdt;
744EXPORT_SYMBOL_GPL(register_kho_notifier);753 int off;
754 int err;
745 755
746int unregister_kho_notifier(struct notifier_block *nb)756 guard(mutex)(&kho_out.lock);
747{757
748 return blocking_notifier_chain_unregister(&kho_out.chain_head, nb);758 err = fdt_open_into(root_fdt, root_fdt, PAGE_SIZE);
759 if (err < 0)
760 return;
761
762 for (off = fdt_first_subnode(root_fdt, 0); off >= 0;
763 off = fdt_next_subnode(root_fdt, off)) {
764 const u64 *val;
765 int len;
766
767 val = fdt_getprop(root_fdt, off, PROP_SUB_FDT, &len);
768 if (!val || len != sizeof(phys_addr_t))
769 continue;
770
771 if ((phys_addr_t)*val == target_phys) {
772 fdt_del_node(root_fdt, off);
773 kho_debugfs_fdt_remove(&kho_out.dbg, fdt);
774 break;
775 }
776 }
777
778 fdt_pack(root_fdt);
749}779}
750EXPORT_SYMBOL_GPL(unregister_kho_notifier);780EXPORT_SYMBOL_GPL(kho_remove_subtree);
751 781
752/**782/**
753 * kho_preserve_folio - preserve a folio across kexec.783 * kho_preserve_folio - preserve a folio across kexec.
@@ -762,7 +792,7 @@ int kho_preserve_folio(struct folio *folio) · 8 unmodified lines
762{792{
763 const unsigned long pfn = folio_pfn(folio);793 const unsigned long pfn = folio_pfn(folio);
764 const unsigned int order = folio_order(folio);794 const unsigned int order = folio_order(folio);
765 struct kho_mem_track *track = &kho_out.ser.track;795 struct kho_mem_track *track = &kho_out.track;
766 796
767 if (WARN_ON(kho_scratch_overlap(pfn << PAGE_SHIFT, PAGE_SIZE << order)))797 if (WARN_ON(kho_scratch_overlap(pfn << PAGE_SHIFT, PAGE_SIZE << order)))
768 return -EINVAL;798 return -EINVAL;
@@ -771,6 +801,24 @@ int kho_preserve_folio(struct folio *folio) · 2 unmodified lines
771}801}
772EXPORT_SYMBOL_GPL(kho_preserve_folio);802EXPORT_SYMBOL_GPL(kho_preserve_folio);
773 803
804/**
805 * kho_unpreserve_folio - unpreserve a folio.
806 * @folio: folio to unpreserve.
807 *
808 * Instructs KHO to unpreserve a folio that was preserved by
809 * kho_preserve_folio() before. The provided @folio (pfn and order)
810 * must exactly match a previously preserved folio.
811 */
812void kho_unpreserve_folio(struct folio *folio)
813{
814 const unsigned long pfn = folio_pfn(folio);
815 const unsigned int order = folio_order(folio);
816 struct kho_mem_track *track = &kho_out.track;
817
818 __kho_unpreserve_order(track, pfn, order);
819}
820EXPORT_SYMBOL_GPL(kho_unpreserve_folio);
821
774/**822/**
775 * kho_preserve_pages - preserve contiguous pages across kexec823 * kho_preserve_pages - preserve contiguous pages across kexec
776 * @page: first page in the list.824 * @page: first page in the list.
@@ -783,7 +831,7 @@ EXPORT_SYMBOL_GPL(kho_preserve_folio); · 6 unmodified lines
783 */831 */
784int kho_preserve_pages(struct page *page, unsigned int nr_pages)832int kho_preserve_pages(struct page *page, unsigned int nr_pages)
785{833{
786 struct kho_mem_track *track = &kho_out.ser.track;834 struct kho_mem_track *track = &kho_out.track;
787 const unsigned long start_pfn = page_to_pfn(page);835 const unsigned long start_pfn = page_to_pfn(page);
788 const unsigned long end_pfn = start_pfn + nr_pages;836 const unsigned long end_pfn = start_pfn + nr_pages;
789 unsigned long pfn = start_pfn;837 unsigned long pfn = start_pfn;
@@ -815,6 +863,26 @@ int kho_preserve_pages(struct page *page, unsigned int nr_pages) · 25 unmodified lines
815}863}
816EXPORT_SYMBOL_GPL(kho_preserve_pages);864EXPORT_SYMBOL_GPL(kho_preserve_pages);
817 865
866/**
867 * kho_unpreserve_pages - unpreserve contiguous pages.
868 * @page: first page in the list.
869 * @nr_pages: number of pages.
870 *
871 * Instructs KHO to unpreserve @nr_pages contiguous pages starting from @page.
872 * This must be called with the same @page and @nr_pages as the corresponding
873 * kho_preserve_pages() call. Unpreserving arbitrary sub-ranges of larger
874 * preserved blocks is not supported.
875 */
876void kho_unpreserve_pages(struct page *page, unsigned int nr_pages)
877{
878 struct kho_mem_track *track = &kho_out.track;
879 const unsigned long start_pfn = page_to_pfn(page);
880 const unsigned long end_pfn = start_pfn + nr_pages;
881
882 __kho_unpreserve(track, start_pfn, end_pfn);
883}
884EXPORT_SYMBOL_GPL(kho_unpreserve_pages);
885
818struct kho_vmalloc_hdr {886struct kho_vmalloc_hdr {
819 DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);887 DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);
820};888};
@@ -885,7 +953,7 @@ err_free: · 64 unmodified lines
885static void kho_vmalloc_unpreserve_chunk(struct kho_vmalloc_chunk *chunk,953static void kho_vmalloc_unpreserve_chunk(struct kho_vmalloc_chunk *chunk,
886 unsigned short order)954 unsigned short order)
887{955{
888 struct kho_mem_track *track = &kho_out.ser.track;956 struct kho_mem_track *track = &kho_out.track;
889 unsigned long pfn = PHYS_PFN(virt_to_phys(chunk));957 unsigned long pfn = PHYS_PFN(virt_to_phys(chunk));
890 958
891 __kho_unpreserve(track, pfn, pfn + 1);959 __kho_unpreserve(track, pfn, pfn + 1);
@@ -896,20 +964,6 @@ static void kho_vmalloc_unpreserve_chunk(struct kho_vmalloc_chunk *chunk, · 4 unmodified lines
896 }964 }
897}965}
898 966
899static void kho_vmalloc_free_chunks(struct kho_vmalloc *kho_vmalloc)
900{
901 struct kho_vmalloc_chunk *chunk = KHOSER_LOAD_PTR(kho_vmalloc->first);
902
903 while (chunk) {
904 struct kho_vmalloc_chunk *tmp = chunk;
905
906 kho_vmalloc_unpreserve_chunk(chunk, kho_vmalloc->order);
907
908 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
909 free_page((unsigned long)tmp);
910 }
911}
912
913/**967/**
914 * kho_preserve_vmalloc - preserve memory allocated with vmalloc() across kexec968 * kho_preserve_vmalloc - preserve memory allocated with vmalloc() across kexec
915 * @ptr: pointer to the area in vmalloc address space969 * @ptr: pointer to the area in vmalloc address space
@@ -971,11 +1025,33 @@ int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) · 55 unmodified lines
971 return 0;1025 return 0;
972 1026
973err_free:1027err_free:
974 kho_vmalloc_free_chunks(preservation);1028 kho_unpreserve_vmalloc(preservation);
975 return err;1029 return err;
976}1030}
977EXPORT_SYMBOL_GPL(kho_preserve_vmalloc);1031EXPORT_SYMBOL_GPL(kho_preserve_vmalloc);
978 1032
1033/**
1034 * kho_unpreserve_vmalloc - unpreserve memory allocated with vmalloc()
1035 * @preservation: preservation metadata returned by kho_preserve_vmalloc()
1036 *
1037 * Instructs KHO to unpreserve the area in vmalloc address space that was
1038 * previously preserved with kho_preserve_vmalloc().
1039 */
1040void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation)
1041{
1042 struct kho_vmalloc_chunk *chunk = KHOSER_LOAD_PTR(preservation->first);
1043
1044 while (chunk) {
1045 struct kho_vmalloc_chunk *tmp = chunk;
1046
1047 kho_vmalloc_unpreserve_chunk(chunk, preservation->order);
1048
1049 chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
1050 free_page((unsigned long)tmp);
1051 }
1052}
1053EXPORT_SYMBOL_GPL(kho_unpreserve_vmalloc);
1054
979/**1055/**
980 * kho_restore_vmalloc - recreates and populates an area in vmalloc address1056 * kho_restore_vmalloc - recreates and populates an area in vmalloc address
981 * space from the preserved memory.1057 * space from the preserved memory.
@@ -1024,7 +1100,7 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) · 42 unmodified lines
1024 goto err_free_pages_array;1100 goto err_free_pages_array;
1025 1101
1026 for (int j = 0; j < contig_pages; j++)1102 for (int j = 0; j < contig_pages; j++)
1027 pages[idx++] = page;1103 pages[idx++] = page + j;
1028 1104
1029 phys += contig_pages * PAGE_SIZE;1105 phys += contig_pages * PAGE_SIZE;
1030 }1106 }
@@ -1065,217 +1141,122 @@ err_free_pages_array: · 34 unmodified lines
1065}1141}
1066EXPORT_SYMBOL_GPL(kho_restore_vmalloc);1142EXPORT_SYMBOL_GPL(kho_restore_vmalloc);
1067 1143
1068/* Handling for debug/kho/out */1144/**
1069 1145 * kho_alloc_preserve - Allocate, zero, and preserve memory.
1070static struct dentry *debugfs_root;1146 * @size: The number of bytes to allocate.
1071 1147 *
1072static int kho_out_update_debugfs_fdt(void)1148 * Allocates a physically contiguous block of zeroed pages that is large
1073{1149 * enough to hold @size bytes. The allocated memory is then registered with
1074 int err = 0;1150 * KHO for preservation across a kexec.
1075 struct fdt_debugfs *ff, *tmp;1151 *
1076 1152 * Note: The actual allocated size will be rounded up to the nearest
1077 if (kho_out.finalized) {1153 * power-of-two page boundary.
1078 err = kho_debugfs_fdt_add(&kho_out.ser.fdt_list, kho_out.dir,1154 *
1079 "fdt", page_to_virt(kho_out.ser.fdt));1155 * @return A virtual pointer to the allocated and preserved memory on success,
1080 } else {1156 * or an ERR_PTR() encoded error on failure.
1081 list_for_each_entry_safe(ff, tmp, &kho_out.ser.fdt_list, list) {1157 */
1082 debugfs_remove(ff->file);1158void *kho_alloc_preserve(size_t size)
1083 list_del(&ff->list);
1084 kfree(ff);
1085 }
1086 }
1087
1088 return err;
1089}
1090
1091static int kho_abort(void)
1092{1159{
1093 int err;1160 struct folio *folio;
1094 unsigned long order;1161 int order, ret;
1095 struct kho_mem_phys *physxa;
1096 1162
1097 xa_for_each(&kho_out.ser.track.orders, order, physxa) {1163 if (!size)
1098 struct kho_mem_phys_bits *bits;1164 return ERR_PTR(-EINVAL);
1099 unsigned long phys;
1100 1165
1101 xa_for_each(&physxa->phys_bits, phys, bits)1166 order = get_order(size);
1102 kfree(bits);1167 if (order > MAX_PAGE_ORDER)
1168 return ERR_PTR(-E2BIG);
1103 1169
1104 xa_destroy(&physxa->phys_bits);1170 folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, order);
1105 kfree(physxa);1171 if (!folio)
1106 }1172 return ERR_PTR(-ENOMEM);
1107 xa_destroy(&kho_out.ser.track.orders);
1108 1173
1109 if (kho_out.ser.preserved_mem_map) {1174 ret = kho_preserve_folio(folio);
1110 kho_mem_ser_free(kho_out.ser.preserved_mem_map);1175 if (ret) {
1111 kho_out.ser.preserved_mem_map = NULL;1176 folio_put(folio);
1177 return ERR_PTR(ret);
1112 }1178 }
1113 1179
1114 err = blocking_notifier_call_chain(&kho_out.chain_head, KEXEC_KHO_ABORT,1180 return folio_address(folio);
1115 NULL);
1116 err = notifier_to_errno(err);
1117
1118 if (err)
1119 pr_err("Failed to abort KHO finalization: %d\n", err);
1120
1121 return err;
1122}1181}
1182EXPORT_SYMBOL_GPL(kho_alloc_preserve);
1123 1183
1124static int kho_finalize(void)1184/**
1185 * kho_unpreserve_free - Unpreserve and free memory.
1186 * @mem: Pointer to the memory allocated by kho_alloc_preserve().
1187 *
1188 * Unregisters the memory from KHO preservation and frees the underlying
1189 * pages back to the system. This function should be called to clean up
1190 * memory allocated with kho_alloc_preserve().
1191 */
1192void kho_unpreserve_free(void *mem)
1125{1193{
1126 int err = 0;1194 struct folio *folio;
1127 u64 *preserved_mem_map;
1128 void *fdt = page_to_virt(kho_out.ser.fdt);
1129
1130 err |= fdt_create(fdt, PAGE_SIZE);
1131 err |= fdt_finish_reservemap(fdt);
1132 err |= fdt_begin_node(fdt, "");
1133 err |= fdt_property_string(fdt, "compatible", KHO_FDT_COMPATIBLE);
1134 /**
1135 * Reserve the preserved-memory-map property in the root FDT, so
1136 * that all property definitions will precede subnodes created by
1137 * KHO callers.
1138 */
1139 err |= fdt_property_placeholder(fdt, PROP_PRESERVED_MEMORY_MAP,
1140 sizeof(*preserved_mem_map),
1141 (void **)&preserved_mem_map);
1142 if (err)
1143 goto abort;
1144
1145 err = kho_preserve_folio(page_folio(kho_out.ser.fdt));
1146 if (err)
1147 goto abort;
1148
1149 err = blocking_notifier_call_chain(&kho_out.chain_head,
1150 KEXEC_KHO_FINALIZE, &kho_out.ser);
1151 err = notifier_to_errno(err);
1152 if (err)
1153 goto abort;
1154
1155 err = kho_mem_serialize(&kho_out.ser);
1156 if (err)
1157 goto abort;
1158
1159 *preserved_mem_map = (u64)virt_to_phys(kho_out.ser.preserved_mem_map);
1160
1161 err |= fdt_end_node(fdt);
1162 err |= fdt_finish(fdt);
1163 1195
1164abort:1196 if (!mem)
1165 if (err) {1197 return;
1166 pr_err("Failed to convert KHO state tree: %d\n", err);
1167 kho_abort();
1168 }
1169 1198
1170 return err;1199 folio = virt_to_folio(mem);
1200 kho_unpreserve_folio(folio);
1201 folio_put(folio);
1171}1202}
1203EXPORT_SYMBOL_GPL(kho_unpreserve_free);
1172 1204
1173static int kho_out_finalize_get(void *data, u64 *val)1205/**
1206 * kho_restore_free - Restore and free memory after kexec.
1207 * @mem: Pointer to the memory (in the new kernel's address space)
1208 * that was allocated by the old kernel.
1209 *
1210 * This function is intended to be called in the new kernel (post-kexec)
1211 * to take ownership of and free a memory region that was preserved by the
1212 * old kernel using kho_alloc_preserve().
1213 *
1214 * It first restores the pages from KHO (using their physical address)
1215 * and then frees the pages back to the new kernel's page allocator.
1216 */
1217void kho_restore_free(void *mem)
1174{1218{
1175 mutex_lock(&kho_out.lock);1219 struct folio *folio;
1176 *val = kho_out.finalized;
1177 mutex_unlock(&kho_out.lock);
1178 1220
1179 return 0;1221 if (!mem)
1222 return;
1223
1224 folio = kho_restore_folio(__pa(mem));
1225 if (!WARN_ON(!folio))
1226 folio_put(folio);
1180}1227}
1228EXPORT_SYMBOL_GPL(kho_restore_free);
1181 1229
1182static int kho_out_finalize_set(void *data, u64 _val)1230int kho_finalize(void)
1183{1231{
1184 int ret = 0;1232 int ret;
1185 bool val = !!_val;
1186
1187 mutex_lock(&kho_out.lock);
1188
1189 if (val == kho_out.finalized) {
1190 if (kho_out.finalized)
1191 ret = -EEXIST;
1192 else
1193 ret = -ENOENT;
1194 goto unlock;
1195 }
1196 1233
1197 if (val)1234 if (!kho_enable)
1198 ret = kho_finalize();1235 return -EOPNOTSUPP;
1199 else
1200 ret = kho_abort();
1201 1236
1237 guard(mutex)(&kho_out.lock);
1238 ret = kho_mem_serialize(&kho_out);
1202 if (ret)1239 if (ret)
1203 goto unlock;1240 return ret;
1204
1205 kho_out.finalized = val;
1206 ret = kho_out_update_debugfs_fdt();
1207
1208unlock:
1209 mutex_unlock(&kho_out.lock);
1210 return ret;
1211}
1212
1213DEFINE_DEBUGFS_ATTRIBUTE(fops_kho_out_finalize, kho_out_finalize_get,
1214 kho_out_finalize_set, "%llu\n");
1215 1241
1216static int scratch_phys_show(struct seq_file *m, void *v)1242 kho_out.finalized = true;
1217{
1218 for (int i = 0; i < kho_scratch_cnt; i++)
1219 seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
1220 1243
1221 return 0;1244 return 0;
1222}1245}
1223DEFINE_SHOW_ATTRIBUTE(scratch_phys);
1224 1246
1225static int scratch_len_show(struct seq_file *m, void *v)1247bool kho_finalized(void)
1226{1248{
1227 for (int i = 0; i < kho_scratch_cnt; i++)1249 guard(mutex)(&kho_out.lock);
1228 seq_printf(m, "0x%llx\n", kho_scratch[i].size);1250 return kho_out.finalized;
1229
1230 return 0;
1231}
1232DEFINE_SHOW_ATTRIBUTE(scratch_len);
1233
1234static __init int kho_out_debugfs_init(void)
1235{
1236 struct dentry *dir, *f, *sub_fdt_dir;
1237
1238 dir = debugfs_create_dir("out", debugfs_root);
1239 if (IS_ERR(dir))
1240 return -ENOMEM;
1241
1242 sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
1243 if (IS_ERR(sub_fdt_dir))
1244 goto err_rmdir;
1245
1246 f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
1247 &scratch_phys_fops);
1248 if (IS_ERR(f))
1249 goto err_rmdir;
1250
1251 f = debugfs_create_file("scratch_len", 0400, dir, NULL,
1252 &scratch_len_fops);
1253 if (IS_ERR(f))
1254 goto err_rmdir;
1255
1256 f = debugfs_create_file("finalize", 0600, dir, NULL,
1257 &fops_kho_out_finalize);
1258 if (IS_ERR(f))
1259 goto err_rmdir;
1260
1261 kho_out.dir = dir;
1262 kho_out.ser.sub_fdt_dir = sub_fdt_dir;
1263 return 0;
1264
1265err_rmdir:
1266 debugfs_remove_recursive(dir);
1267 return -ENOENT;
1268}1251}
1269 1252
1270struct kho_in {1253struct kho_in {
1271 struct dentry *dir;
1272 phys_addr_t fdt_phys;1254 phys_addr_t fdt_phys;
1273 phys_addr_t scratch_phys;1255 phys_addr_t scratch_phys;
1274 struct list_head fdt_list;1256 struct kho_debugfs dbg;
1275};1257};
1276 1258
1277static struct kho_in kho_in = {1259static struct kho_in kho_in = {
1278 .fdt_list = LIST_HEAD_INIT(kho_in.fdt_list),
1279};1260};
1280 1261
1281static const void *kho_get_fdt(void)1262static const void *kho_get_fdt(void)
@@ -1339,91 +1320,52 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys) · 57 unmodified lines
1339}1320}
1340EXPORT_SYMBOL_GPL(kho_retrieve_subtree);1321EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
1341 1322
1342/* Handling for debugfs/kho/in */1323static __init int kho_out_fdt_setup(void)
1343
1344static __init int kho_in_debugfs_init(const void *fdt)
1345{1324{
1346 struct dentry *sub_fdt_dir;1325 void *root = kho_out.fdt;
1347 int err, child;1326 u64 empty_mem_map = 0;
1348 1327 int err;
1349 kho_in.dir = debugfs_create_dir("in", debugfs_root);
1350 if (IS_ERR(kho_in.dir))
1351 return PTR_ERR(kho_in.dir);
1352
1353 sub_fdt_dir = debugfs_create_dir("sub_fdts", kho_in.dir);
1354 if (IS_ERR(sub_fdt_dir)) {
1355 err = PTR_ERR(sub_fdt_dir);
1356 goto err_rmdir;
1357 }
1358
1359 err = kho_debugfs_fdt_add(&kho_in.fdt_list, kho_in.dir, "fdt", fdt);
1360 if (err)
1361 goto err_rmdir;
1362
1363 fdt_for_each_subnode(child, fdt, 0) {
1364 int len = 0;
1365 const char *name = fdt_get_name(fdt, child, NULL);
1366 const u64 *fdt_phys;
1367
1368 fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
1369 if (!fdt_phys)
1370 continue;
1371 if (len != sizeof(*fdt_phys)) {
1372 pr_warn("node `%s`'s prop `fdt` has invalid length: %d\n",
1373 name, len);
1374 continue;
1375 }
1376 err = kho_debugfs_fdt_add(&kho_in.fdt_list, sub_fdt_dir, name,
1377 phys_to_virt(*fdt_phys));
1378 if (err) {
1379 pr_warn("failed to add fdt `%s` to debugfs: %d\n", name,
1380 err);
1381 continue;
1382 }
1383 }
1384 1328
1385 return 0;1329 err = fdt_create(root, PAGE_SIZE);
1330 err |= fdt_finish_reservemap(root);
1331 err |= fdt_begin_node(root, "");
1332 err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE);
1333 err |= fdt_property(root, PROP_PRESERVED_MEMORY_MAP, &empty_mem_map,
1334 sizeof(empty_mem_map));
1335 err |= fdt_end_node(root);
1336 err |= fdt_finish(root);
1386 1337
1387err_rmdir:
1388 debugfs_remove_recursive(kho_in.dir);
1389 return err;1338 return err;
1390}1339}
1391 1340
1392static __init int kho_init(void)1341static __init int kho_init(void)
1393{1342{
1394 int err = 0;
1395 const void *fdt = kho_get_fdt();1343 const void *fdt = kho_get_fdt();
1344 int err = 0;
1396 1345
1397 if (!kho_enable)1346 if (!kho_enable)
1398 return 0;1347 return 0;
1399 1348
1400 kho_out.ser.fdt = alloc_page(GFP_KERNEL);1349 kho_out.fdt = kho_alloc_preserve(PAGE_SIZE);
1401 if (!kho_out.ser.fdt) {1350 if (IS_ERR(kho_out.fdt)) {
1402 err = -ENOMEM;1351 err = PTR_ERR(kho_out.fdt);
1403 goto err_free_scratch;1352 goto err_free_scratch;
1404 }1353 }
1405 1354
1406 debugfs_root = debugfs_create_dir("kho", NULL);1355 err = kho_debugfs_init();
1407 if (IS_ERR(debugfs_root)) {1356 if (err)
1408 err = -ENOENT;
1409 goto err_free_fdt;1357 goto err_free_fdt;
1410 }
1411 1358
1412 err = kho_out_debugfs_init();1359 err = kho_out_debugfs_init(&kho_out.dbg);
1413 if (err)1360 if (err)
1414 goto err_free_fdt;1361 goto err_free_fdt;
1415 1362
1416 if (fdt) {1363 err = kho_out_fdt_setup();
1417 err = kho_in_debugfs_init(fdt);1364 if (err)
1418 /*1365 goto err_free_fdt;
1419 * Failure to create /sys/kernel/debug/kho/in does not prevent
1420 * reviving state from KHO and setting up KHO for the next
1421 * kexec.
1422 */
1423 if (err)
1424 pr_err("failed exposing handover FDT in debugfs: %d\n",
1425 err);
1426 1366
1367 if (fdt) {
1368 kho_in_debugfs_init(&kho_in.dbg, fdt);
1427 return 0;1369 return 0;
1428 }1370 }
1429 1371
@@ -1432,17 +1374,29 @@ static __init int kho_init(void) · 2 unmodified lines
1432 unsigned long count = kho_scratch[i].size >> PAGE_SHIFT;1374 unsigned long count = kho_scratch[i].size >> PAGE_SHIFT;
1433 unsigned long pfn;1375 unsigned long pfn;
1434 1376
1377 /*
1378 * When debug_pagealloc is enabled, __free_pages() clears the
1379 * corresponding PRESENT bit in the kernel page table.
1380 * Subsequent kmemleak scans of these pages cause the
1381 * non-PRESENT page faults.
1382 * Mark scratch areas with kmemleak_ignore_phys() to exclude
1383 * them from kmemleak scanning.
1384 */
1385 kmemleak_ignore_phys(kho_scratch[i].addr);
1435 for (pfn = base_pfn; pfn < base_pfn + count;1386 for (pfn = base_pfn; pfn < base_pfn + count;
1436 pfn += pageblock_nr_pages)1387 pfn += pageblock_nr_pages)
1437 init_cma_reserved_pageblock(pfn_to_page(pfn));1388 init_cma_reserved_pageblock(pfn_to_page(pfn));
1438 }1389 }
1439 1390
1391 WARN_ON_ONCE(kho_debugfs_fdt_add(&kho_out.dbg, "fdt",
1392 kho_out.fdt, true));
1393
1440 return 0;1394 return 0;
1441 1395
1442err_free_fdt:1396err_free_fdt:
1443 put_page(kho_out.ser.fdt);1397 kho_unpreserve_free(kho_out.fdt);
1444 kho_out.ser.fdt = NULL;
1445err_free_scratch:1398err_free_scratch:
1399 kho_out.fdt = NULL;
1446 for (int i = 0; i < kho_scratch_cnt; i++) {1400 for (int i = 0; i < kho_scratch_cnt; i++) {
1447 void *start = __va(kho_scratch[i].addr);1401 void *start = __va(kho_scratch[i].addr);
1448 void *end = start + kho_scratch[i].size;1402 void *end = start + kho_scratch[i].size;
@@ -1452,7 +1406,7 @@ err_free_scratch: · 3 unmodified lines
1452 kho_enable = false;1406 kho_enable = false;
1453 return err;1407 return err;
1454}1408}
1455late_initcall(kho_init);1409fs_initcall(kho_init);
1456 1410
1457static void __init kho_release_scratch(void)1411static void __init kho_release_scratch(void)
1458{1412{
@@ -1480,16 +1434,12 @@ static void __init kho_release_scratch(void) · 21 unmodified lines
1480 1434
1481void __init kho_memory_init(void)1435void __init kho_memory_init(void)
1482{1436{
1483 struct folio *folio;
1484
1485 if (kho_in.scratch_phys) {1437 if (kho_in.scratch_phys) {
1486 kho_scratch = phys_to_virt(kho_in.scratch_phys);1438 kho_scratch = phys_to_virt(kho_in.scratch_phys);
1487 kho_release_scratch();1439 kho_release_scratch();
1488 1440
1489 kho_mem_deserialize(kho_get_fdt());1441 if (!kho_mem_deserialize(kho_get_fdt()))
1490 folio = kho_restore_folio(kho_in.fdt_phys);1442 kho_in.fdt_phys = 0;
1491 if (!folio)
1492 pr_warn("failed to restore folio for KHO fdt\n");
1493 } else {1443 } else {
1494 kho_reserve_scratch();1444 kho_reserve_scratch();
1495 }1445 }
@@ -1545,8 +1495,8 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, · 49 unmodified lines
1545 memblock_add(area->addr, size);1495 memblock_add(area->addr, size);
1546 err = memblock_mark_kho_scratch(area->addr, size);1496 err = memblock_mark_kho_scratch(area->addr, size);
1547 if (WARN_ON(err)) {1497 if (WARN_ON(err)) {
1548 pr_warn("failed to mark the scratch region 0x%pa+0x%pa: %d",1498 pr_warn("failed to mark the scratch region 0x%pa+0x%pa: %pe",
1549 &area->addr, &size, err);1499 &area->addr, &size, ERR_PTR(err));
1550 goto out;1500 goto out;
1551 }1501 }
1552 pr_debug("Marked 0x%pa+0x%pa as scratch", &area->addr, &size);1502 pr_debug("Marked 0x%pa+0x%pa as scratch", &area->addr, &size);
@@ -1566,7 +1516,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, · 13 unmodified lines
1566 kho_in.fdt_phys = fdt_phys;1516 kho_in.fdt_phys = fdt_phys;
1567 kho_in.scratch_phys = scratch_phys;1517 kho_in.scratch_phys = scratch_phys;
1568 kho_scratch_cnt = scratch_cnt;1518 kho_scratch_cnt = scratch_cnt;
1569 pr_info("found kexec handover data. Will skip init for some devices\n");1519 pr_info("found kexec handover data.\n");
1570 1520
1571out:1521out:
1572 if (fdt)1522 if (fdt)
@@ -1585,10 +1535,10 @@ int kho_fill_kimage(struct kimage *image) · 12 unmodified lines
1585 int err = 0;1535 int err = 0;
1586 struct kexec_buf scratch;1536 struct kexec_buf scratch;
1587 1537
1588 if (!kho_out.finalized)1538 if (!kho_enable)
1589 return 0;1539 return 0;
1590 1540
1591 image->kho.fdt = page_to_phys(kho_out.ser.fdt);1541 image->kho.fdt = virt_to_phys(kho_out.fdt);
1592 1542
1593 scratch_size = sizeof(*kho_scratch) * kho_scratch_cnt;1543 scratch_size = sizeof(*kho_scratch) * kho_scratch_cnt;
1594 scratch = (struct kexec_buf){1544 scratch = (struct kexec_buf){
kernel/liveupdate/kexec_handover_debug.crenamed from kernel/kexec_handover_debug.c+0−0

File renamed without changes.

kernel/liveupdate/kexec_handover_debugfs.c+221−0
@@ -0,0 +1,221 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * kexec_handover_debugfs.c - kexec handover debugfs interfaces
4 * Copyright (C) 2023 Alexander Graf <graf@amazon.com>
5 * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport <rppt@kernel.org>
6 * Copyright (C) 2025 Google LLC, Changyuan Lyu <changyuanl@google.com>
7 * Copyright (C) 2025 Google LLC, Pasha Tatashin <pasha.tatashin@soleen.com>
8 */
9
10#define pr_fmt(fmt) "KHO: " fmt
11
12#include <linux/init.h>
13#include <linux/io.h>
14#include <linux/libfdt.h>
15#include <linux/mm.h>
16#include "kexec_handover_internal.h"
17
18static struct dentry *debugfs_root;
19
20struct fdt_debugfs {
21 struct list_head list;
22 struct debugfs_blob_wrapper wrapper;
23 struct dentry *file;
24};
25
26static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir,
27 const char *name, const void *fdt)
28{
29 struct fdt_debugfs *f;
30 struct dentry *file;
31
32 f = kmalloc(sizeof(*f), GFP_KERNEL);
33 if (!f)
34 return -ENOMEM;
35
36 f->wrapper.data = (void *)fdt;
37 f->wrapper.size = fdt_totalsize(fdt);
38
39 file = debugfs_create_blob(name, 0400, dir, &f->wrapper);
40 if (IS_ERR(file)) {
41 kfree(f);
42 return PTR_ERR(file);
43 }
44
45 f->file = file;
46 list_add(&f->list, list);
47
48 return 0;
49}
50
51int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
52 const void *fdt, bool root)
53{
54 struct dentry *dir;
55
56 if (root)
57 dir = dbg->dir;
58 else
59 dir = dbg->sub_fdt_dir;
60
61 return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt);
62}
63
64void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt)
65{
66 struct fdt_debugfs *ff;
67
68 list_for_each_entry(ff, &dbg->fdt_list, list) {
69 if (ff->wrapper.data == fdt) {
70 debugfs_remove(ff->file);
71 list_del(&ff->list);
72 kfree(ff);
73 break;
74 }
75 }
76}
77
78static int kho_out_finalize_get(void *data, u64 *val)
79{
80 *val = kho_finalized();
81
82 return 0;
83}
84
85static int kho_out_finalize_set(void *data, u64 val)
86{
87 if (val)
88 return kho_finalize();
89 else
90 return -EINVAL;
91}
92
93DEFINE_DEBUGFS_ATTRIBUTE(kho_out_finalize_fops, kho_out_finalize_get,
94 kho_out_finalize_set, "%llu\n");
95
96static int scratch_phys_show(struct seq_file *m, void *v)
97{
98 for (int i = 0; i < kho_scratch_cnt; i++)
99 seq_printf(m, "0x%llx\n", kho_scratch[i].addr);
100
101 return 0;
102}
103DEFINE_SHOW_ATTRIBUTE(scratch_phys);
104
105static int scratch_len_show(struct seq_file *m, void *v)
106{
107 for (int i = 0; i < kho_scratch_cnt; i++)
108 seq_printf(m, "0x%llx\n", kho_scratch[i].size);
109
110 return 0;
111}
112DEFINE_SHOW_ATTRIBUTE(scratch_len);
113
114__init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt)
115{
116 struct dentry *dir, *sub_fdt_dir;
117 int err, child;
118
119 INIT_LIST_HEAD(&dbg->fdt_list);
120
121 dir = debugfs_create_dir("in", debugfs_root);
122 if (IS_ERR(dir)) {
123 err = PTR_ERR(dir);
124 goto err_out;
125 }
126
127 sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
128 if (IS_ERR(sub_fdt_dir)) {
129 err = PTR_ERR(sub_fdt_dir);
130 goto err_rmdir;
131 }
132
133 err = __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt);
134 if (err)
135 goto err_rmdir;
136
137 fdt_for_each_subnode(child, fdt, 0) {
138 int len = 0;
139 const char *name = fdt_get_name(fdt, child, NULL);
140 const u64 *fdt_phys;
141
142 fdt_phys = fdt_getprop(fdt, child, "fdt", &len);
143 if (!fdt_phys)
144 continue;
145 if (len != sizeof(*fdt_phys)) {
146 pr_warn("node %s prop fdt has invalid length: %d\n",
147 name, len);
148 continue;
149 }
150 err = __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name,
151 phys_to_virt(*fdt_phys));
152 if (err) {
153 pr_warn("failed to add fdt %s to debugfs: %pe\n", name,
154 ERR_PTR(err));
155 continue;
156 }
157 }
158
159 dbg->dir = dir;
160 dbg->sub_fdt_dir = sub_fdt_dir;
161
162 return;
163err_rmdir:
164 debugfs_remove_recursive(dir);
165err_out:
166 /*
167 * Failure to create /sys/kernel/debug/kho/in does not prevent
168 * reviving state from KHO and setting up KHO for the next
169 * kexec.
170 */
171 if (err) {
172 pr_err("failed exposing handover FDT in debugfs: %pe\n",
173 ERR_PTR(err));
174 }
175}
176
177__init int kho_out_debugfs_init(struct kho_debugfs *dbg)
178{
179 struct dentry *dir, *f, *sub_fdt_dir;
180
181 INIT_LIST_HEAD(&dbg->fdt_list);
182
183 dir = debugfs_create_dir("out", debugfs_root);
184 if (IS_ERR(dir))
185 return -ENOMEM;
186
187 sub_fdt_dir = debugfs_create_dir("sub_fdts", dir);
188 if (IS_ERR(sub_fdt_dir))
189 goto err_rmdir;
190
191 f = debugfs_create_file("scratch_phys", 0400, dir, NULL,
192 &scratch_phys_fops);
193 if (IS_ERR(f))
194 goto err_rmdir;
195
196 f = debugfs_create_file("scratch_len", 0400, dir, NULL,
197 &scratch_len_fops);
198 if (IS_ERR(f))
199 goto err_rmdir;
200
201 f = debugfs_create_file("finalize", 0600, dir, NULL,
202 &kho_out_finalize_fops);
203 if (IS_ERR(f))
204 goto err_rmdir;
205
206 dbg->dir = dir;
207 dbg->sub_fdt_dir = sub_fdt_dir;
208 return 0;
209
210err_rmdir:
211 debugfs_remove_recursive(dir);
212 return -ENOENT;
213}
214
215__init int kho_debugfs_init(void)
216{
217 debugfs_root = debugfs_create_dir("kho", NULL);
218 if (IS_ERR(debugfs_root))
219 return -ENOENT;
220 return 0;
221}
kernel/liveupdate/kexec_handover_internal.h+55−0
@@ -0,0 +1,55 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef LINUX_KEXEC_HANDOVER_INTERNAL_H
3#define LINUX_KEXEC_HANDOVER_INTERNAL_H
4
5#include <linux/kexec_handover.h>
6#include <linux/list.h>
7#include <linux/types.h>
8
9#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
10#include <linux/debugfs.h>
11
12struct kho_debugfs {
13 struct dentry *dir;
14 struct dentry *sub_fdt_dir;
15 struct list_head fdt_list;
16};
17
18#else
19struct kho_debugfs {};
20#endif
21
22extern struct kho_scratch *kho_scratch;
23extern unsigned int kho_scratch_cnt;
24
25bool kho_finalized(void);
26int kho_finalize(void);
27
28#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS
29int kho_debugfs_init(void);
30void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt);
31int kho_out_debugfs_init(struct kho_debugfs *dbg);
32int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
33 const void *fdt, bool root);
34void kho_debugfs_fdt_remove(struct kho_debugfs *dbg, void *fdt);
35#else
36static inline int kho_debugfs_init(void) { return 0; }
37static inline void kho_in_debugfs_init(struct kho_debugfs *dbg,
38 const void *fdt) { }
39static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0; }
40static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name,
41 const void *fdt, bool root) { return 0; }
42static inline void kho_debugfs_fdt_remove(struct kho_debugfs *dbg,
43 void *fdt) { }
44#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */
45
46#ifdef CONFIG_KEXEC_HANDOVER_DEBUG
47bool kho_scratch_overlap(phys_addr_t phys, size_t size);
48#else
49static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
50{
51 return false;
52}
53#endif /* CONFIG_KEXEC_HANDOVER_DEBUG */
54
55#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */
kernel/liveupdate/luo_core.c+450−0
@@ -0,0 +1,450 @@
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8/**
9 * DOC: Live Update Orchestrator (LUO)
10 *
11 * Live Update is a specialized, kexec-based reboot process that allows a
12 * running kernel to be updated from one version to another while preserving
13 * the state of selected resources and keeping designated hardware devices
14 * operational. For these devices, DMA activity may continue throughout the
15 * kernel transition.
16 *
17 * While the primary use case driving this work is supporting live updates of
18 * the Linux kernel when it is used as a hypervisor in cloud environments, the
19 * LUO framework itself is designed to be workload-agnostic. Live Update
20 * facilitates a full kernel version upgrade for any type of system.
21 *
22 * For example, a non-hypervisor system running an in-memory cache like
23 * memcached with many gigabytes of data can use LUO. The userspace service
24 * can place its cache into a memfd, have its state preserved by LUO, and
25 * restore it immediately after the kernel kexec.
26 *
27 * Whether the system is running virtual machines, containers, a
28 * high-performance database, or networking services, LUO's primary goal is to
29 * enable a full kernel update by preserving critical userspace state and
30 * keeping essential devices operational.
31 *
32 * The core of LUO is a mechanism that tracks the progress of a live update,
33 * along with a callback API that allows other kernel subsystems to participate
34 * in the process. Example subsystems that can hook into LUO include: kvm,
35 * iommu, interrupts, vfio, participating filesystems, and memory management.
36 *
37 * LUO uses Kexec Handover to transfer memory state from the current kernel to
38 * the next kernel. For more details see
39 * Documentation/core-api/kho/concepts.rst.
40 */
41
42#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
43
44#include <linux/atomic.h>
45#include <linux/errno.h>
46#include <linux/file.h>
47#include <linux/fs.h>
48#include <linux/init.h>
49#include <linux/io.h>
50#include <linux/kernel.h>
51#include <linux/kexec_handover.h>
52#include <linux/kho/abi/luo.h>
53#include <linux/kobject.h>
54#include <linux/libfdt.h>
55#include <linux/liveupdate.h>
56#include <linux/miscdevice.h>
57#include <linux/mm.h>
58#include <linux/sizes.h>
59#include <linux/string.h>
60#include <linux/unaligned.h>
61
62#include "kexec_handover_internal.h"
63#include "luo_internal.h"
64
65static struct {
66 bool enabled;
67 void *fdt_out;
68 void *fdt_in;
69 u64 liveupdate_num;
70} luo_global;
71
72static int __init early_liveupdate_param(char *buf)
73{
74 return kstrtobool(buf, &luo_global.enabled);
75}
76early_param("liveupdate", early_liveupdate_param);
77
78static int __init luo_early_startup(void)
79{
80 phys_addr_t fdt_phys;
81 int err, ln_size;
82 const void *ptr;
83
84 if (!kho_is_enabled()) {
85 if (liveupdate_enabled())
86 pr_warn("Disabling liveupdate because KHO is disabled\n");
87 luo_global.enabled = false;
88 return 0;
89 }
90
91 /* Retrieve LUO subtree, and verify its format. */
92 err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys);
93 if (err) {
94 if (err != -ENOENT) {
95 pr_err("failed to retrieve FDT '%s' from KHO: %pe\n",
96 LUO_FDT_KHO_ENTRY_NAME, ERR_PTR(err));
97 return err;
98 }
99
100 return 0;
101 }
102
103 luo_global.fdt_in = phys_to_virt(fdt_phys);
104 err = fdt_node_check_compatible(luo_global.fdt_in, 0,
105 LUO_FDT_COMPATIBLE);
106 if (err) {
107 pr_err("FDT '%s' is incompatible with '%s' [%d]\n",
108 LUO_FDT_KHO_ENTRY_NAME, LUO_FDT_COMPATIBLE, err);
109
110 return -EINVAL;
111 }
112
113 ln_size = 0;
114 ptr = fdt_getprop(luo_global.fdt_in, 0, LUO_FDT_LIVEUPDATE_NUM,
115 &ln_size);
116 if (!ptr || ln_size != sizeof(luo_global.liveupdate_num)) {
117 pr_err("Unable to get live update number '%s' [%d]\n",
118 LUO_FDT_LIVEUPDATE_NUM, ln_size);
119
120 return -EINVAL;
121 }
122
123 luo_global.liveupdate_num = get_unaligned((u64 *)ptr);
124 pr_info("Retrieved live update data, liveupdate number: %lld\n",
125 luo_global.liveupdate_num);
126
127 err = luo_session_setup_incoming(luo_global.fdt_in);
128 if (err)
129 return err;
130
131 return 0;
132}
133
134static int __init liveupdate_early_init(void)
135{
136 int err;
137
138 err = luo_early_startup();
139 if (err) {
140 luo_global.enabled = false;
141 luo_restore_fail("The incoming tree failed to initialize properly [%pe], disabling live update\n",
142 ERR_PTR(err));
143 }
144
145 return err;
146}
147early_initcall(liveupdate_early_init);
148
149/* Called during boot to create outgoing LUO fdt tree */
150static int __init luo_fdt_setup(void)
151{
152 const u64 ln = luo_global.liveupdate_num + 1;
153 void *fdt_out;
154 int err;
155
156 fdt_out = kho_alloc_preserve(LUO_FDT_SIZE);
157 if (IS_ERR(fdt_out)) {
158 pr_err("failed to allocate/preserve FDT memory\n");
159 return PTR_ERR(fdt_out);
160 }
161
162 err = fdt_create(fdt_out, LUO_FDT_SIZE);
163 err |= fdt_finish_reservemap(fdt_out);
164 err |= fdt_begin_node(fdt_out, "");
165 err |= fdt_property_string(fdt_out, "compatible", LUO_FDT_COMPATIBLE);
166 err |= fdt_property(fdt_out, LUO_FDT_LIVEUPDATE_NUM, &ln, sizeof(ln));
167 err |= luo_session_setup_outgoing(fdt_out);
168 err |= fdt_end_node(fdt_out);
169 err |= fdt_finish(fdt_out);
170 if (err)
171 goto exit_free;
172
173 err = kho_add_subtree(LUO_FDT_KHO_ENTRY_NAME, fdt_out);
174 if (err)
175 goto exit_free;
176 luo_global.fdt_out = fdt_out;
177
178 return 0;
179
180exit_free:
181 kho_unpreserve_free(fdt_out);
182 pr_err("failed to prepare LUO FDT: %d\n", err);
183
184 return err;
185}
186
187/*
188 * late initcall because it initializes the outgoing tree that is needed only
189 * once userspace starts using /dev/liveupdate.
190 */
191static int __init luo_late_startup(void)
192{
193 int err;
194
195 if (!liveupdate_enabled())
196 return 0;
197
198 err = luo_fdt_setup();
199 if (err)
200 luo_global.enabled = false;
201
202 return err;
203}
204late_initcall(luo_late_startup);
205
206/* Public Functions */
207
208/**
209 * liveupdate_reboot() - Kernel reboot notifier for live update final
210 * serialization.
211 *
212 * This function is invoked directly from the reboot() syscall pathway
213 * if kexec is in progress.
214 *
215 * If any callback fails, this function aborts KHO, undoes the freeze()
216 * callbacks, and returns an error.
217 */
218int liveupdate_reboot(void)
219{
220 int err;
221
222 if (!liveupdate_enabled())
223 return 0;
224
225 err = luo_session_serialize();
226 if (err)
227 return err;
228
229 err = kho_finalize();
230 if (err) {
231 pr_err("kho_finalize failed %d\n", err);
232 /*
233 * kho_finalize() may return libfdt errors, to aboid passing to
234 * userspace unknown errors, change this to EAGAIN.
235 */
236 err = -EAGAIN;
237 }
238
239 return err;
240}
241
242/**
243 * liveupdate_enabled - Check if the live update feature is enabled.
244 *
245 * This function returns the state of the live update feature flag, which
246 * can be controlled via the ``liveupdate`` kernel command-line parameter.
247 *
248 * @return true if live update is enabled, false otherwise.
249 */
250bool liveupdate_enabled(void)
251{
252 return luo_global.enabled;
253}
254
255/**
256 * DOC: LUO ioctl Interface
257 *
258 * The IOCTL user-space control interface for the LUO subsystem.
259 * It registers a character device, typically found at ``/dev/liveupdate``,
260 * which allows a userspace agent to manage the LUO state machine and its
261 * associated resources, such as preservable file descriptors.
262 *
263 * To ensure that the state machine is controlled by a single entity, access
264 * to this device is exclusive: only one process is permitted to have
265 * ``/dev/liveupdate`` open at any given time. Subsequent open attempts will
266 * fail with -EBUSY until the first process closes its file descriptor.
267 * This singleton model simplifies state management by preventing conflicting
268 * commands from multiple userspace agents.
269 */
270
271struct luo_device_state {
272 struct miscdevice miscdev;
273 atomic_t in_use;
274};
275
276static int luo_ioctl_create_session(struct luo_ucmd *ucmd)
277{
278 struct liveupdate_ioctl_create_session *argp = ucmd->cmd;
279 struct file *file;
280 int err;
281
282 argp->fd = get_unused_fd_flags(O_CLOEXEC);
283 if (argp->fd < 0)
284 return argp->fd;
285
286 err = luo_session_create(argp->name, &file);
287 if (err)
288 goto err_put_fd;
289
290 err = luo_ucmd_respond(ucmd, sizeof(*argp));
291 if (err)
292 goto err_put_file;
293
294 fd_install(argp->fd, file);
295
296 return 0;
297
298err_put_file:
299 fput(file);
300err_put_fd:
301 put_unused_fd(argp->fd);
302
303 return err;
304}
305
306static int luo_ioctl_retrieve_session(struct luo_ucmd *ucmd)
307{
308 struct liveupdate_ioctl_retrieve_session *argp = ucmd->cmd;
309 struct file *file;
310 int err;
311
312 argp->fd = get_unused_fd_flags(O_CLOEXEC);
313 if (argp->fd < 0)
314 return argp->fd;
315
316 err = luo_session_retrieve(argp->name, &file);
317 if (err < 0)
318 goto err_put_fd;
319
320 err = luo_ucmd_respond(ucmd, sizeof(*argp));
321 if (err)
322 goto err_put_file;
323
324 fd_install(argp->fd, file);
325
326 return 0;
327
328err_put_file:
329 fput(file);
330err_put_fd:
331 put_unused_fd(argp->fd);
332
333 return err;
334}
335
336static int luo_open(struct inode *inodep, struct file *filep)
337{
338 struct luo_device_state *ldev = container_of(filep->private_data,
339 struct luo_device_state,
340 miscdev);
341
342 if (atomic_cmpxchg(&ldev->in_use, 0, 1))
343 return -EBUSY;
344
345 /* Always return -EIO to user if deserialization fail */
346 if (luo_session_deserialize()) {
347 atomic_set(&ldev->in_use, 0);
348 return -EIO;
349 }
350
351 return 0;
352}
353
354static int luo_release(struct inode *inodep, struct file *filep)
355{
356 struct luo_device_state *ldev = container_of(filep->private_data,
357 struct luo_device_state,
358 miscdev);
359 atomic_set(&ldev->in_use, 0);
360
361 return 0;
362}
363
364union ucmd_buffer {
365 struct liveupdate_ioctl_create_session create;
366 struct liveupdate_ioctl_retrieve_session retrieve;
367};
368
369struct luo_ioctl_op {
370 unsigned int size;
371 unsigned int min_size;
372 unsigned int ioctl_num;
373 int (*execute)(struct luo_ucmd *ucmd);
374};
375
376#define IOCTL_OP(_ioctl, _fn, _struct, _last) \
377 [_IOC_NR(_ioctl) - LIVEUPDATE_CMD_BASE] = { \
378 .size = sizeof(_struct) + \
379 BUILD_BUG_ON_ZERO(sizeof(union ucmd_buffer) < \
380 sizeof(_struct)), \
381 .min_size = offsetofend(_struct, _last), \
382 .ioctl_num = _ioctl, \
383 .execute = _fn, \
384 }
385
386static const struct luo_ioctl_op luo_ioctl_ops[] = {
387 IOCTL_OP(LIVEUPDATE_IOCTL_CREATE_SESSION, luo_ioctl_create_session,
388 struct liveupdate_ioctl_create_session, name),
389 IOCTL_OP(LIVEUPDATE_IOCTL_RETRIEVE_SESSION, luo_ioctl_retrieve_session,
390 struct liveupdate_ioctl_retrieve_session, name),
391};
392
393static long luo_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
394{
395 const struct luo_ioctl_op *op;
396 struct luo_ucmd ucmd = {};
397 union ucmd_buffer buf;
398 unsigned int nr;
399 int err;
400
401 nr = _IOC_NR(cmd);
402 if (nr < LIVEUPDATE_CMD_BASE ||
403 (nr - LIVEUPDATE_CMD_BASE) >= ARRAY_SIZE(luo_ioctl_ops)) {
404 return -EINVAL;
405 }
406
407 ucmd.ubuffer = (void __user *)arg;
408 err = get_user(ucmd.user_size, (u32 __user *)ucmd.ubuffer);
409 if (err)
410 return err;
411
412 op = &luo_ioctl_ops[nr - LIVEUPDATE_CMD_BASE];
413 if (op->ioctl_num != cmd)
414 return -ENOIOCTLCMD;
415 if (ucmd.user_size < op->min_size)
416 return -EINVAL;
417
418 ucmd.cmd = &buf;
419 err = copy_struct_from_user(ucmd.cmd, op->size, ucmd.ubuffer,
420 ucmd.user_size);
421 if (err)
422 return err;
423
424 return op->execute(&ucmd);
425}
426
427static const struct file_operations luo_fops = {
428 .owner = THIS_MODULE,
429 .open = luo_open,
430 .release = luo_release,
431 .unlocked_ioctl = luo_ioctl,
432};
433
434static struct luo_device_state luo_dev = {
435 .miscdev = {
436 .minor = MISC_DYNAMIC_MINOR,
437 .name = "liveupdate",
438 .fops = &luo_fops,
439 },
440 .in_use = ATOMIC_INIT(0),
441};
442
443static int __init liveupdate_ioctl_init(void)
444{
445 if (!liveupdate_enabled())
446 return 0;
447
448 return misc_register(&luo_dev.miscdev);
449}
450late_initcall(liveupdate_ioctl_init);
kernel/liveupdate/luo_file.c+889−0
@@ -0,0 +1,889 @@
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8/**
9 * DOC: LUO File Descriptors
10 *
11 * LUO provides the infrastructure to preserve specific, stateful file
12 * descriptors across a kexec-based live update. The primary goal is to allow
13 * workloads, such as virtual machines using vfio, memfd, or iommufd, to
14 * retain access to their essential resources without interruption.
15 *
16 * The framework is built around a callback-based handler model and a well-
17 * defined lifecycle for each preserved file.
18 *
19 * Handler Registration:
20 * Kernel modules responsible for a specific file type (e.g., memfd, vfio)
21 * register a &struct liveupdate_file_handler. This handler provides a set of
22 * callbacks that LUO invokes at different stages of the update process, most
23 * notably:
24 *
25 * - can_preserve(): A lightweight check to determine if the handler is
26 * compatible with a given 'struct file'.
27 * - preserve(): The heavyweight operation that saves the file's state and
28 * returns an opaque u64 handle. This is typically performed while the
29 * workload is still active to minimize the downtime during the
30 * actual reboot transition.
31 * - unpreserve(): Cleans up any resources allocated by .preserve(), called
32 * if the preservation process is aborted before the reboot (i.e. session is
33 * closed).
34 * - freeze(): A final pre-reboot opportunity to prepare the state for kexec.
35 * We are already in reboot syscall, and therefore userspace cannot mutate
36 * the file anymore.
37 * - unfreeze(): Undoes the actions of .freeze(), called if the live update
38 * is aborted after the freeze phase.
39 * - retrieve(): Reconstructs the file in the new kernel from the preserved
40 * handle.
41 * - finish(): Performs final check and cleanup in the new kernel. After
42 * succesul finish call, LUO gives up ownership to this file.
43 *
44 * File Preservation Lifecycle happy path:
45 *
46 * 1. Preserve (Normal Operation): A userspace agent preserves files one by one
47 * via an ioctl. For each file, luo_preserve_file() finds a compatible
48 * handler, calls its .preserve() operation, and creates an internal &struct
49 * luo_file to track the live state.
50 *
51 * 2. Freeze (Pre-Reboot): Just before the kexec, luo_file_freeze() is called.
52 * It iterates through all preserved files, calls their respective .freeze()
53 * operation, and serializes their final metadata (compatible string, token,
54 * and data handle) into a contiguous memory block for KHO.
55 *
56 * 3. Deserialize: After kexec, luo_file_deserialize() runs when session gets
57 * deserialized (which is when /dev/liveupdate is first opened). It reads the
58 * serialized data from the KHO memory region and reconstructs the in-memory
59 * list of &struct luo_file instances for the new kernel, linking them to
60 * their corresponding handlers.
61 *
62 * 4. Retrieve (New Kernel - Userspace Ready): The userspace agent can now
63 * restore file descriptors by providing a token. luo_retrieve_file()
64 * searches for the matching token, calls the handler's .retrieve() op to
65 * re-create the 'struct file', and returns a new FD. Files can be
66 * retrieved in ANY order.
67 *
68 * 5. Finish (New Kernel - Cleanup): Once a session retrival is complete,
69 * luo_file_finish() is called. It iterates through all files, invokes their
70 * .finish() operations for final cleanup, and releases all associated kernel
71 * resources.
72 *
73 * File Preservation Lifecycle unhappy paths:
74 *
75 * 1. Abort Before Reboot: If the userspace agent aborts the live update
76 * process before calling reboot (e.g., by closing the session file
77 * descriptor), the session's release handler calls
78 * luo_file_unpreserve_files(). This invokes the .unpreserve() callback on
79 * all preserved files, ensuring all allocated resources are cleaned up and
80 * returning the system to a clean state.
81 *
82 * 2. Freeze Failure: During the reboot() syscall, if any handler's .freeze()
83 * op fails, the .unfreeze() op is invoked on all previously *successful*
84 * freezes to roll back their state. The reboot() syscall then returns an
85 * error to userspace, canceling the live update.
86 *
87 * 3. Finish Failure: In the new kernel, if a handler's .finish() op fails,
88 * the luo_file_finish() operation is aborted. LUO retains ownership of
89 * all files within that session, including those that were not yet
90 * processed. The userspace agent can attempt to call the finish operation
91 * again later. If the issue cannot be resolved, these resources will be held
92 * by LUO until the next live update cycle, at which point they will be
93 * discarded.
94 */
95
96#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
97
98#include <linux/cleanup.h>
99#include <linux/compiler.h>
100#include <linux/err.h>
101#include <linux/errno.h>
102#include <linux/file.h>
103#include <linux/fs.h>
104#include <linux/io.h>
105#include <linux/kexec_handover.h>
106#include <linux/kho/abi/luo.h>
107#include <linux/liveupdate.h>
108#include <linux/module.h>
109#include <linux/sizes.h>
110#include <linux/slab.h>
111#include <linux/string.h>
112#include "luo_internal.h"
113
114static LIST_HEAD(luo_file_handler_list);
115
116/* 2 4K pages, give space for 128 files per file_set */
117#define LUO_FILE_PGCNT 2ul
118#define LUO_FILE_MAX \
119 ((LUO_FILE_PGCNT << PAGE_SHIFT) / sizeof(struct luo_file_ser))
120
121/**
122 * struct luo_file - Represents a single preserved file instance.
123 * @fh: Pointer to the &struct liveupdate_file_handler that manages
124 * this type of file.
125 * @file: Pointer to the kernel's &struct file that is being preserved.
126 * This is NULL in the new kernel until the file is successfully
127 * retrieved.
128 * @serialized_data: The opaque u64 handle to the serialized state of the file.
129 * This handle is passed back to the handler's .freeze(),
130 * .retrieve(), and .finish() callbacks, allowing it to track
131 * and update its serialized state across phases.
132 * @private_data: Pointer to the private data for the file used to hold runtime
133 * state that is not preserved. Set by the handler's .preserve()
134 * callback, and must be freed in the handler's .unpreserve()
135 * callback.
136 * @retrieved: A flag indicating whether a user/kernel in the new kernel has
137 * successfully called retrieve() on this file. This prevents
138 * multiple retrieval attempts.
139 * @mutex: A mutex that protects the fields of this specific instance
140 * (e.g., @retrieved, @file), ensuring that operations like
141 * retrieving or finishing a file are atomic.
142 * @list: The list_head linking this instance into its parent
143 * file_set's list of preserved files.
144 * @token: The user-provided unique token used to identify this file.
145 *
146 * This structure is the core in-kernel representation of a single file being
147 * managed through a live update. An instance is created by luo_preserve_file()
148 * to link a 'struct file' to its corresponding handler, a user-provided token,
149 * and the serialized state handle returned by the handler's .preserve()
150 * operation.
151 *
152 * These instances are tracked in a per-file_set list. The @serialized_data
153 * field, which holds a handle to the file's serialized state, may be updated
154 * during the .freeze() callback before being serialized for the next kernel.
155 * After reboot, these structures are recreated by luo_file_deserialize() and
156 * are finally cleaned up by luo_file_finish().
157 */
158struct luo_file {
159 struct liveupdate_file_handler *fh;
160 struct file *file;
161 u64 serialized_data;
162 void *private_data;
163 bool retrieved;
164 struct mutex mutex;
165 struct list_head list;
166 u64 token;
167};
168
169static int luo_alloc_files_mem(struct luo_file_set *file_set)
170{
171 size_t size;
172 void *mem;
173
174 if (file_set->files)
175 return 0;
176
177 WARN_ON_ONCE(file_set->count);
178
179 size = LUO_FILE_PGCNT << PAGE_SHIFT;
180 mem = kho_alloc_preserve(size);
181 if (IS_ERR(mem))
182 return PTR_ERR(mem);
183
184 file_set->files = mem;
185
186 return 0;
187}
188
189static void luo_free_files_mem(struct luo_file_set *file_set)
190{
191 /* If file_set has files, no need to free preservation memory */
192 if (file_set->count)
193 return;
194
195 if (!file_set->files)
196 return;
197
198 kho_unpreserve_free(file_set->files);
199 file_set->files = NULL;
200}
201
202static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
203{
204 struct luo_file *iter;
205
206 list_for_each_entry(iter, &file_set->files_list, list) {
207 if (iter->token == token)
208 return true;
209 }
210
211 return false;
212}
213
214/**
215 * luo_preserve_file - Initiate the preservation of a file descriptor.
216 * @file_set: The file_set to which the preserved file will be added.
217 * @token: A unique, user-provided identifier for the file.
218 * @fd: The file descriptor to be preserved.
219 *
220 * This function orchestrates the first phase of preserving a file. Upon entry,
221 * it takes a reference to the 'struct file' via fget(), effectively making LUO
222 * a co-owner of the file. This reference is held until the file is either
223 * unpreserved or successfully finished in the next kernel, preventing the file
224 * from being prematurely destroyed.
225 *
226 * This function orchestrates the first phase of preserving a file. It performs
227 * the following steps:
228 *
229 * 1. Validates that the @token is not already in use within the file_set.
230 * 2. Ensures the file_set's memory for files serialization is allocated
231 * (allocates if needed).
232 * 3. Iterates through registered handlers, calling can_preserve() to find one
233 * compatible with the given @fd.
234 * 4. Calls the handler's .preserve() operation, which saves the file's state
235 * and returns an opaque private data handle.
236 * 5. Adds the new instance to the file_set's internal list.
237 *
238 * On success, LUO takes a reference to the 'struct file' and considers it
239 * under its management until it is unpreserved or finished.
240 *
241 * In case of any failure, all intermediate allocations (file reference, memory
242 * for the 'luo_file' struct, etc.) are cleaned up before returning an error.
243 *
244 * Context: Can be called from an ioctl handler during normal system operation.
245 * Return: 0 on success. Returns a negative errno on failure:
246 * -EEXIST if the token is already used.
247 * -EBADF if the file descriptor is invalid.
248 * -ENOSPC if the file_set is full.
249 * -ENOENT if no compatible handler is found.
250 * -ENOMEM on memory allocation failure.
251 * Other erros might be returned by .preserve().
252 */
253int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
254{
255 struct liveupdate_file_op_args args = {0};
256 struct liveupdate_file_handler *fh;
257 struct luo_file *luo_file;
258 struct file *file;
259 int err;
260
261 if (luo_token_is_used(file_set, token))
262 return -EEXIST;
263
264 if (file_set->count == LUO_FILE_MAX)
265 return -ENOSPC;
266
267 file = fget(fd);
268 if (!file)
269 return -EBADF;
270
271 err = luo_alloc_files_mem(file_set);
272 if (err)
273 goto err_fput;
274
275 err = -ENOENT;
276 luo_list_for_each_private(fh, &luo_file_handler_list, list) {
277 if (fh->ops->can_preserve(fh, file)) {
278 err = 0;
279 break;
280 }
281 }
282
283 /* err is still -ENOENT if no handler was found */
284 if (err)
285 goto err_free_files_mem;
286
287 luo_file = kzalloc(sizeof(*luo_file), GFP_KERNEL);
288 if (!luo_file) {
289 err = -ENOMEM;
290 goto err_free_files_mem;
291 }
292
293 luo_file->file = file;
294 luo_file->fh = fh;
295 luo_file->token = token;
296 luo_file->retrieved = false;
297 mutex_init(&luo_file->mutex);
298
299 args.handler = fh;
300 args.file = file;
301 err = fh->ops->preserve(&args);
302 if (err)
303 goto err_kfree;
304
305 luo_file->serialized_data = args.serialized_data;
306 luo_file->private_data = args.private_data;
307 list_add_tail(&luo_file->list, &file_set->files_list);
308 file_set->count++;
309
310 return 0;
311
312err_kfree:
313 kfree(luo_file);
314err_free_files_mem:
315 luo_free_files_mem(file_set);
316err_fput:
317 fput(file);
318
319 return err;
320}
321
322/**
323 * luo_file_unpreserve_files - Unpreserves all files from a file_set.
324 * @file_set: The files to be cleaned up.
325 *
326 * This function serves as the primary cleanup path for a file_set. It is
327 * invoked when the userspace agent closes the file_set's file descriptor.
328 *
329 * For each file, it performs the following cleanup actions:
330 * 1. Calls the handler's .unpreserve() callback to allow the handler to
331 * release any resources it allocated.
332 * 2. Removes the file from the file_set's internal tracking list.
333 * 3. Releases the reference to the 'struct file' that was taken by
334 * luo_preserve_file() via fput(), returning ownership.
335 * 4. Frees the memory associated with the internal 'struct luo_file'.
336 *
337 * After all individual files are unpreserved, it frees the contiguous memory
338 * block that was allocated to hold their serialization data.
339 */
340void luo_file_unpreserve_files(struct luo_file_set *file_set)
341{
342 struct luo_file *luo_file;
343
344 while (!list_empty(&file_set->files_list)) {
345 struct liveupdate_file_op_args args = {0};
346
347 luo_file = list_last_entry(&file_set->files_list,
348 struct luo_file, list);
349
350 args.handler = luo_file->fh;
351 args.file = luo_file->file;
352 args.serialized_data = luo_file->serialized_data;
353 args.private_data = luo_file->private_data;
354 luo_file->fh->ops->unpreserve(&args);
355
356 list_del(&luo_file->list);
357 file_set->count--;
358
359 fput(luo_file->file);
360 mutex_destroy(&luo_file->mutex);
361 kfree(luo_file);
362 }
363
364 luo_free_files_mem(file_set);
365}
366
367static int luo_file_freeze_one(struct luo_file_set *file_set,
368 struct luo_file *luo_file)
369{
370 int err = 0;
371
372 guard(mutex)(&luo_file->mutex);
373
374 if (luo_file->fh->ops->freeze) {
375 struct liveupdate_file_op_args args = {0};
376
377 args.handler = luo_file->fh;
378 args.file = luo_file->file;
379 args.serialized_data = luo_file->serialized_data;
380 args.private_data = luo_file->private_data;
381
382 err = luo_file->fh->ops->freeze(&args);
383 if (!err)
384 luo_file->serialized_data = args.serialized_data;
385 }
386
387 return err;
388}
389
390static void luo_file_unfreeze_one(struct luo_file_set *file_set,
391 struct luo_file *luo_file)
392{
393 guard(mutex)(&luo_file->mutex);
394
395 if (luo_file->fh->ops->unfreeze) {
396 struct liveupdate_file_op_args args = {0};
397
398 args.handler = luo_file->fh;
399 args.file = luo_file->file;
400 args.serialized_data = luo_file->serialized_data;
401 args.private_data = luo_file->private_data;
402
403 luo_file->fh->ops->unfreeze(&args);
404 }
405
406 luo_file->serialized_data = 0;
407}
408
409static void __luo_file_unfreeze(struct luo_file_set *file_set,
410 struct luo_file *failed_entry)
411{
412 struct list_head *files_list = &file_set->files_list;
413 struct luo_file *luo_file;
414
415 list_for_each_entry(luo_file, files_list, list) {
416 if (luo_file == failed_entry)
417 break;
418
419 luo_file_unfreeze_one(file_set, luo_file);
420 }
421
422 memset(file_set->files, 0, LUO_FILE_PGCNT << PAGE_SHIFT);
423}
424
425/**
426 * luo_file_freeze - Freezes all preserved files and serializes their metadata.
427 * @file_set: The file_set whose files are to be frozen.
428 * @file_set_ser: Where to put the serialized file_set.
429 *
430 * This function is called from the reboot() syscall path, just before the
431 * kernel transitions to the new image via kexec. Its purpose is to perform the
432 * final preparation and serialization of all preserved files in the file_set.
433 *
434 * It iterates through each preserved file in FIFO order (the order of
435 * preservation) and performs two main actions:
436 *
437 * 1. Freezes the File: It calls the handler's .freeze() callback for each
438 * file. This gives the handler a final opportunity to quiesce the device or
439 * prepare its state for the upcoming reboot. The handler may update its
440 * private data handle during this step.
441 *
442 * 2. Serializes Metadata: After a successful freeze, it copies the final file
443 * metadata—the handler's compatible string, the user token, and the final
444 * private data handle—into the pre-allocated contiguous memory buffer
445 * (file_set->files) that will be handed over to the next kernel via KHO.
446 *
447 * Error Handling (Rollback):
448 * This function is atomic. If any handler's .freeze() operation fails, the
449 * entire live update is aborted. The __luo_file_unfreeze() helper is
450 * immediately called to invoke the .unfreeze() op on all files that were
451 * successfully frozen before the point of failure, rolling them back to a
452 * running state. The function then returns an error, causing the reboot()
453 * syscall to fail.
454 *
455 * Context: Called only from the liveupdate_reboot() path.
456 * Return: 0 on success, or a negative errno on failure.
457 */
458int luo_file_freeze(struct luo_file_set *file_set,
459 struct luo_file_set_ser *file_set_ser)
460{
461 struct luo_file_ser *file_ser = file_set->files;
462 struct luo_file *luo_file;
463 int err;
464 int i;
465
466 if (!file_set->count)
467 return 0;
468
469 if (WARN_ON(!file_ser))
470 return -EINVAL;
471
472 i = 0;
473 list_for_each_entry(luo_file, &file_set->files_list, list) {
474 err = luo_file_freeze_one(file_set, luo_file);
475 if (err < 0) {
476 pr_warn("Freeze failed for token[%#0llx] handler[%s] err[%pe]\n",
477 luo_file->token, luo_file->fh->compatible,
478 ERR_PTR(err));
479 goto err_unfreeze;
480 }
481
482 strscpy(file_ser[i].compatible, luo_file->fh->compatible,
483 sizeof(file_ser[i].compatible));
484 file_ser[i].data = luo_file->serialized_data;
485 file_ser[i].token = luo_file->token;
486 i++;
487 }
488
489 file_set_ser->count = file_set->count;
490 if (file_set->files)
491 file_set_ser->files = virt_to_phys(file_set->files);
492
493 return 0;
494
495err_unfreeze:
496 __luo_file_unfreeze(file_set, luo_file);
497
498 return err;
499}
500
501/**
502 * luo_file_unfreeze - Unfreezes all files in a file_set and clear serialization
503 * @file_set: The file_set whose files are to be unfrozen.
504 * @file_set_ser: Serialized file_set.
505 *
506 * This function rolls back the state of all files in a file_set after the
507 * freeze phase has begun but must be aborted. It is the counterpart to
508 * luo_file_freeze().
509 *
510 * It invokes the __luo_file_unfreeze() helper with a NULL argument, which
511 * signals the helper to iterate through all files in the file_set and call
512 * their respective .unfreeze() handler callbacks.
513 *
514 * Context: This is called when the live update is aborted during
515 * the reboot() syscall, after luo_file_freeze() has been called.
516 */
517void luo_file_unfreeze(struct luo_file_set *file_set,
518 struct luo_file_set_ser *file_set_ser)
519{
520 if (!file_set->count)
521 return;
522
523 __luo_file_unfreeze(file_set, NULL);
524 memset(file_set_ser, 0, sizeof(*file_set_ser));
525}
526
527/**
528 * luo_retrieve_file - Restores a preserved file from a file_set by its token.
529 * @file_set: The file_set from which to retrieve the file.
530 * @token: The unique token identifying the file to be restored.
531 * @filep: Output parameter; on success, this is populated with a pointer
532 * to the newly retrieved 'struct file'.
533 *
534 * This function is the primary mechanism for recreating a file in the new
535 * kernel after a live update. It searches the file_set's list of deserialized
536 * files for an entry matching the provided @token.
537 *
538 * The operation is idempotent: if a file has already been successfully
539 * retrieved, this function will simply return a pointer to the existing
540 * 'struct file' and report success without re-executing the retrieve
541 * operation. This is handled by checking the 'retrieved' flag under a lock.
542 *
543 * File retrieval can happen in any order; it is not bound by the order of
544 * preservation.
545 *
546 * Context: Can be called from an ioctl or other in-kernel code in the new
547 * kernel.
548 * Return: 0 on success. Returns a negative errno on failure:
549 * -ENOENT if no file with the matching token is found.
550 * Any error code returned by the handler's .retrieve() op.
551 */
552int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
553 struct file **filep)
554{
555 struct liveupdate_file_op_args args = {0};
556 struct luo_file *luo_file;
557 int err;
558
559 if (list_empty(&file_set->files_list))
560 return -ENOENT;
561
562 list_for_each_entry(luo_file, &file_set->files_list, list) {
563 if (luo_file->token == token)
564 break;
565 }
566
567 if (luo_file->token != token)
568 return -ENOENT;
569
570 guard(mutex)(&luo_file->mutex);
571 if (luo_file->retrieved) {
572 /*
573 * Someone is asking for this file again, so get a reference
574 * for them.
575 */
576 get_file(luo_file->file);
577 *filep = luo_file->file;
578 return 0;
579 }
580
581 args.handler = luo_file->fh;
582 args.serialized_data = luo_file->serialized_data;
583 err = luo_file->fh->ops->retrieve(&args);
584 if (!err) {
585 luo_file->file = args.file;
586
587 /* Get reference so we can keep this file in LUO until finish */
588 get_file(luo_file->file);
589 *filep = luo_file->file;
590 luo_file->retrieved = true;
591 }
592
593 return err;
594}
595
596static int luo_file_can_finish_one(struct luo_file_set *file_set,
597 struct luo_file *luo_file)
598{
599 bool can_finish = true;
600
601 guard(mutex)(&luo_file->mutex);
602
603 if (luo_file->fh->ops->can_finish) {
604 struct liveupdate_file_op_args args = {0};
605
606 args.handler = luo_file->fh;
607 args.file = luo_file->file;
608 args.serialized_data = luo_file->serialized_data;
609 args.retrieved = luo_file->retrieved;
610 can_finish = luo_file->fh->ops->can_finish(&args);
611 }
612
613 return can_finish ? 0 : -EBUSY;
614}
615
616static void luo_file_finish_one(struct luo_file_set *file_set,
617 struct luo_file *luo_file)
618{
619 struct liveupdate_file_op_args args = {0};
620
621 guard(mutex)(&luo_file->mutex);
622
623 args.handler = luo_file->fh;
624 args.file = luo_file->file;
625 args.serialized_data = luo_file->serialized_data;
626 args.retrieved = luo_file->retrieved;
627
628 luo_file->fh->ops->finish(&args);
629}
630
631/**
632 * luo_file_finish - Completes the lifecycle for all files in a file_set.
633 * @file_set: The file_set to be finalized.
634 *
635 * This function orchestrates the final teardown of a live update file_set in
636 * the new kernel. It should be called after all necessary files have been
637 * retrieved and the userspace agent is ready to release the preserved state.
638 *
639 * The function iterates through all tracked files. For each file, it performs
640 * the following sequence of cleanup actions:
641 *
642 * 1. If file is not yet retrieved, retrieves it, and calls can_finish() on
643 * every file in the file_set. If all can_finish return true, continue to
644 * finish.
645 * 2. Calls the handler's .finish() callback (via luo_file_finish_one) to
646 * allow for final resource cleanup within the handler.
647 * 3. Releases LUO's ownership reference on the 'struct file' via fput(). This
648 * is the counterpart to the get_file() call in luo_retrieve_file().
649 * 4. Removes the 'struct luo_file' from the file_set's internal list.
650 * 5. Frees the memory for the 'struct luo_file' instance itself.
651 *
652 * After successfully finishing all individual files, it frees the
653 * contiguous memory block that was used to transfer the serialized metadata
654 * from the previous kernel.
655 *
656 * Error Handling (Atomic Failure):
657 * This operation is atomic. If any handler's .can_finish() op fails, the entire
658 * function aborts immediately and returns an error.
659 *
660 * Context: Can be called from an ioctl handler in the new kernel.
661 * Return: 0 on success, or a negative errno on failure.
662 */
663int luo_file_finish(struct luo_file_set *file_set)
664{
665 struct list_head *files_list = &file_set->files_list;
666 struct luo_file *luo_file;
667 int err;
668
669 if (!file_set->count)
670 return 0;
671
672 list_for_each_entry(luo_file, files_list, list) {
673 err = luo_file_can_finish_one(file_set, luo_file);
674 if (err)
675 return err;
676 }
677
678 while (!list_empty(&file_set->files_list)) {
679 luo_file = list_last_entry(&file_set->files_list,
680 struct luo_file, list);
681
682 luo_file_finish_one(file_set, luo_file);
683
684 if (luo_file->file)
685 fput(luo_file->file);
686 list_del(&luo_file->list);
687 file_set->count--;
688 mutex_destroy(&luo_file->mutex);
689 kfree(luo_file);
690 }
691
692 if (file_set->files) {
693 kho_restore_free(file_set->files);
694 file_set->files = NULL;
695 }
696
697 return 0;
698}
699
700/**
701 * luo_file_deserialize - Reconstructs the list of preserved files in the new kernel.
702 * @file_set: The incoming file_set to fill with deserialized data.
703 * @file_set_ser: Serialized KHO file_set data from the previous kernel.
704 *
705 * This function is called during the early boot process of the new kernel. It
706 * takes the raw, contiguous memory block of 'struct luo_file_ser' entries,
707 * provided by the previous kernel, and transforms it back into a live,
708 * in-memory linked list of 'struct luo_file' instances.
709 *
710 * For each serialized entry, it performs the following steps:
711 * 1. Reads the 'compatible' string.
712 * 2. Searches the global list of registered file handlers for one that
713 * matches the compatible string.
714 * 3. Allocates a new 'struct luo_file'.
715 * 4. Populates the new structure with the deserialized data (token, private
716 * data handle) and links it to the found handler. The 'file' pointer is
717 * initialized to NULL, as the file has not been retrieved yet.
718 * 5. Adds the new 'struct luo_file' to the file_set's files_list.
719 *
720 * This prepares the file_set for userspace, which can later call
721 * luo_retrieve_file() to restore the actual file descriptors.
722 *
723 * Context: Called from session deserialization.
724 */
725int luo_file_deserialize(struct luo_file_set *file_set,
726 struct luo_file_set_ser *file_set_ser)
727{
728 struct luo_file_ser *file_ser;
729 u64 i;
730
731 if (!file_set_ser->files) {
732 WARN_ON(file_set_ser->count);
733 return 0;
734 }
735
736 file_set->count = file_set_ser->count;
737 file_set->files = phys_to_virt(file_set_ser->files);
738
739 /*
740 * Note on error handling:
741 *
742 * If deserialization fails (e.g., allocation failure or corrupt data),
743 * we intentionally skip cleanup of files that were already restored.
744 *
745 * A partial failure leaves the preserved state inconsistent.
746 * Implementing a safe "undo" to unwind complex dependencies (sessions,
747 * files, hardware state) is error-prone and provides little value, as
748 * the system is effectively in a broken state.
749 *
750 * We treat these resources as leaked. The expected recovery path is for
751 * userspace to detect the failure and trigger a reboot, which will
752 * reliably reset devices and reclaim memory.
753 */
754 file_ser = file_set->files;
755 for (i = 0; i < file_set->count; i++) {
756 struct liveupdate_file_handler *fh;
757 bool handler_found = false;
758 struct luo_file *luo_file;
759
760 luo_list_for_each_private(fh, &luo_file_handler_list, list) {
761 if (!strcmp(fh->compatible, file_ser[i].compatible)) {
762 handler_found = true;
763 break;
764 }
765 }
766
767 if (!handler_found) {
768 pr_warn("No registered handler for compatible '%s'\n",
769 file_ser[i].compatible);
770 return -ENOENT;
771 }
772
773 luo_file = kzalloc(sizeof(*luo_file), GFP_KERNEL);
774 if (!luo_file)
775 return -ENOMEM;
776
777 luo_file->fh = fh;
778 luo_file->file = NULL;
779 luo_file->serialized_data = file_ser[i].data;
780 luo_file->token = file_ser[i].token;
781 luo_file->retrieved = false;
782 mutex_init(&luo_file->mutex);
783 list_add_tail(&luo_file->list, &file_set->files_list);
784 }
785
786 return 0;
787}
788
789void luo_file_set_init(struct luo_file_set *file_set)
790{
791 INIT_LIST_HEAD(&file_set->files_list);
792}
793
794void luo_file_set_destroy(struct luo_file_set *file_set)
795{
796 WARN_ON(file_set->count);
797 WARN_ON(!list_empty(&file_set->files_list));
798}
799
800/**
801 * liveupdate_register_file_handler - Register a file handler with LUO.
802 * @fh: Pointer to a caller-allocated &struct liveupdate_file_handler.
803 * The caller must initialize this structure, including a unique
804 * 'compatible' string and a valid 'fh' callbacks. This function adds the
805 * handler to the global list of supported file handlers.
806 *
807 * Context: Typically called during module initialization for file types that
808 * support live update preservation.
809 *
810 * Return: 0 on success. Negative errno on failure.
811 */
812int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
813{
814 struct liveupdate_file_handler *fh_iter;
815 int err;
816
817 if (!liveupdate_enabled())
818 return -EOPNOTSUPP;
819
820 /* Sanity check that all required callbacks are set */
821 if (!fh->ops->preserve || !fh->ops->unpreserve || !fh->ops->retrieve ||
822 !fh->ops->finish || !fh->ops->can_preserve) {
823 return -EINVAL;
824 }
825
826 /*
827 * Ensure the system is quiescent (no active sessions).
828 * This prevents registering new handlers while sessions are active or
829 * while deserialization is in progress.
830 */
831 if (!luo_session_quiesce())
832 return -EBUSY;
833
834 /* Check for duplicate compatible strings */
835 luo_list_for_each_private(fh_iter, &luo_file_handler_list, list) {
836 if (!strcmp(fh_iter->compatible, fh->compatible)) {
837 pr_err("File handler registration failed: Compatible string '%s' already registered.\n",
838 fh->compatible);
839 err = -EEXIST;
840 goto err_resume;
841 }
842 }
843
844 /* Pin the module implementing the handler */
845 if (!try_module_get(fh->ops->owner)) {
846 err = -EAGAIN;
847 goto err_resume;
848 }
849
850 INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, list));
851 list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list);
852 luo_session_resume();
853
854 return 0;
855
856err_resume:
857 luo_session_resume();
858 return err;
859}
860
861/**
862 * liveupdate_unregister_file_handler - Unregister a liveupdate file handler
863 * @fh: The file handler to unregister
864 *
865 * Unregisters the file handler from the liveupdate core. This function
866 * reverses the operations of liveupdate_register_file_handler().
867 *
868 * It ensures safe removal by checking that:
869 * No live update session is currently in progress.
870 *
871 * If the unregistration fails, the internal test state is reverted.
872 *
873 * Return: 0 Success. -EOPNOTSUPP when live update is not enabled. -EBUSY A live
874 * update is in progress, can't quiesce live update.
875 */
876int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
877{
878 if (!liveupdate_enabled())
879 return -EOPNOTSUPP;
880
881 if (!luo_session_quiesce())
882 return -EBUSY;
883
884 list_del(&ACCESS_PRIVATE(fh, list));
885 module_put(fh->ops->owner);
886 luo_session_resume();
887
888 return 0;
889}
kernel/liveupdate/luo_internal.h+110−0
@@ -0,0 +1,110 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8#ifndef _LINUX_LUO_INTERNAL_H
9#define _LINUX_LUO_INTERNAL_H
10
11#include <linux/liveupdate.h>
12#include <linux/uaccess.h>
13
14struct luo_ucmd {
15 void __user *ubuffer;
16 u32 user_size;
17 void *cmd;
18};
19
20static inline int luo_ucmd_respond(struct luo_ucmd *ucmd,
21 size_t kernel_cmd_size)
22{
23 /*
24 * Copy the minimum of what the user provided and what we actually
25 * have.
26 */
27 if (copy_to_user(ucmd->ubuffer, ucmd->cmd,
28 min_t(size_t, ucmd->user_size, kernel_cmd_size))) {
29 return -EFAULT;
30 }
31 return 0;
32}
33
34/*
35 * Handles a deserialization failure: devices and memory is in unpredictable
36 * state.
37 *
38 * Continuing the boot process after a failure is dangerous because it could
39 * lead to leaks of private data.
40 */
41#define luo_restore_fail(__fmt, ...) panic(__fmt, ##__VA_ARGS__)
42
43/* Mimics list_for_each_entry() but for private list head entries */
44#define luo_list_for_each_private(pos, head, member) \
45 for (struct list_head *__iter = (head)->next; \
46 __iter != (head) && \
47 ({ pos = container_of(__iter, typeof(*(pos)), member); 1; }); \
48 __iter = __iter->next)
49
50/**
51 * struct luo_file_set - A set of files that belong to the same sessions.
52 * @files_list: An ordered list of files associated with this session, it is
53 * ordered by preservation time.
54 * @files: The physically contiguous memory block that holds the serialized
55 * state of files.
56 * @count: A counter tracking the number of files currently stored in the
57 * @files_list for this session.
58 */
59struct luo_file_set {
60 struct list_head files_list;
61 struct luo_file_ser *files;
62 long count;
63};
64
65/**
66 * struct luo_session - Represents an active or incoming Live Update session.
67 * @name: A unique name for this session, used for identification and
68 * retrieval.
69 * @ser: Pointer to the serialized data for this session.
70 * @list: A list_head member used to link this session into a global list
71 * of either outgoing (to be preserved) or incoming (restored from
72 * previous kernel) sessions.
73 * @retrieved: A boolean flag indicating whether this session has been
74 * retrieved by a consumer in the new kernel.
75 * @file_set: A set of files that belong to this session.
76 * @mutex: protects fields in the luo_session.
77 */
78struct luo_session {
79 char name[LIVEUPDATE_SESSION_NAME_LENGTH];
80 struct luo_session_ser *ser;
81 struct list_head list;
82 bool retrieved;
83 struct luo_file_set file_set;
84 struct mutex mutex;
85};
86
87int luo_session_create(const char *name, struct file **filep);
88int luo_session_retrieve(const char *name, struct file **filep);
89int __init luo_session_setup_outgoing(void *fdt);
90int __init luo_session_setup_incoming(void *fdt);
91int luo_session_serialize(void);
92int luo_session_deserialize(void);
93bool luo_session_quiesce(void);
94void luo_session_resume(void);
95
96int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd);
97void luo_file_unpreserve_files(struct luo_file_set *file_set);
98int luo_file_freeze(struct luo_file_set *file_set,
99 struct luo_file_set_ser *file_set_ser);
100void luo_file_unfreeze(struct luo_file_set *file_set,
101 struct luo_file_set_ser *file_set_ser);
102int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
103 struct file **filep);
104int luo_file_finish(struct luo_file_set *file_set);
105int luo_file_deserialize(struct luo_file_set *file_set,
106 struct luo_file_set_ser *file_set_ser);
107void luo_file_set_init(struct luo_file_set *file_set);
108void luo_file_set_destroy(struct luo_file_set *file_set);
109
110#endif /* _LINUX_LUO_INTERNAL_H */
kernel/liveupdate/luo_session.c+646−0
@@ -0,0 +1,646 @@
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8/**
9 * DOC: LUO Sessions
10 *
11 * LUO Sessions provide the core mechanism for grouping and managing `struct
12 * file *` instances that need to be preserved across a kexec-based live
13 * update. Each session acts as a named container for a set of file objects,
14 * allowing a userspace agent to manage the lifecycle of resources critical to a
15 * workload.
16 *
17 * Core Concepts:
18 *
19 * - Named Containers: Sessions are identified by a unique, user-provided name,
20 * which is used for both creation in the current kernel and retrieval in the
21 * next kernel.
22 *
23 * - Userspace Interface: Session management is driven from userspace via
24 * ioctls on /dev/liveupdate.
25 *
26 * - Serialization: Session metadata is preserved using the KHO framework. When
27 * a live update is triggered via kexec, an array of `struct luo_session_ser`
28 * is populated and placed in a preserved memory region. An FDT node is also
29 * created, containing the count of sessions and the physical address of this
30 * array.
31 *
32 * Session Lifecycle:
33 *
34 * 1. Creation: A userspace agent calls `luo_session_create()` to create a
35 * new, empty session and receives a file descriptor for it.
36 *
37 * 2. Serialization: When the `reboot(LINUX_REBOOT_CMD_KEXEC)` syscall is
38 * made, `luo_session_serialize()` is called. It iterates through all
39 * active sessions and writes their metadata into a memory area preserved
40 * by KHO.
41 *
42 * 3. Deserialization (in new kernel): After kexec, `luo_session_deserialize()`
43 * runs, reading the serialized data and creating a list of `struct
44 * luo_session` objects representing the preserved sessions.
45 *
46 * 4. Retrieval: A userspace agent in the new kernel can then call
47 * `luo_session_retrieve()` with a session name to get a new file
48 * descriptor and access the preserved state.
49 */
50
51#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
52
53#include <linux/anon_inodes.h>
54#include <linux/cleanup.h>
55#include <linux/err.h>
56#include <linux/errno.h>
57#include <linux/file.h>
58#include <linux/fs.h>
59#include <linux/io.h>
60#include <linux/kexec_handover.h>
61#include <linux/kho/abi/luo.h>
62#include <linux/libfdt.h>
63#include <linux/list.h>
64#include <linux/liveupdate.h>
65#include <linux/mutex.h>
66#include <linux/rwsem.h>
67#include <linux/slab.h>
68#include <linux/unaligned.h>
69#include <uapi/linux/liveupdate.h>
70#include "luo_internal.h"
71
72/* 16 4K pages, give space for 744 sessions */
73#define LUO_SESSION_PGCNT 16ul
74#define LUO_SESSION_MAX (((LUO_SESSION_PGCNT << PAGE_SHIFT) - \
75 sizeof(struct luo_session_header_ser)) / \
76 sizeof(struct luo_session_ser))
77
78/**
79 * struct luo_session_header - Header struct for managing LUO sessions.
80 * @count: The number of sessions currently tracked in the @list.
81 * @list: The head of the linked list of `struct luo_session` instances.
82 * @rwsem: A read-write semaphore providing synchronized access to the
83 * session list and other fields in this structure.
84 * @header_ser: The header data of serialization array.
85 * @ser: The serialized session data (an array of
86 * `struct luo_session_ser`).
87 * @active: Set to true when first initialized. If previous kernel did not
88 * send session data, active stays false for incoming.
89 */
90struct luo_session_header {
91 long count;
92 struct list_head list;
93 struct rw_semaphore rwsem;
94 struct luo_session_header_ser *header_ser;
95 struct luo_session_ser *ser;
96 bool active;
97};
98
99/**
100 * struct luo_session_global - Global container for managing LUO sessions.
101 * @incoming: The sessions passed from the previous kernel.
102 * @outgoing: The sessions that are going to be passed to the next kernel.
103 */
104struct luo_session_global {
105 struct luo_session_header incoming;
106 struct luo_session_header outgoing;
107};
108
109static struct luo_session_global luo_session_global = {
110 .incoming = {
111 .list = LIST_HEAD_INIT(luo_session_global.incoming.list),
112 .rwsem = __RWSEM_INITIALIZER(luo_session_global.incoming.rwsem),
113 },
114 .outgoing = {
115 .list = LIST_HEAD_INIT(luo_session_global.outgoing.list),
116 .rwsem = __RWSEM_INITIALIZER(luo_session_global.outgoing.rwsem),
117 },
118};
119
120static struct luo_session *luo_session_alloc(const char *name)
121{
122 struct luo_session *session = kzalloc(sizeof(*session), GFP_KERNEL);
123
124 if (!session)
125 return ERR_PTR(-ENOMEM);
126
127 strscpy(session->name, name, sizeof(session->name));
128 INIT_LIST_HEAD(&session->file_set.files_list);
129 luo_file_set_init(&session->file_set);
130 INIT_LIST_HEAD(&session->list);
131 mutex_init(&session->mutex);
132
133 return session;
134}
135
136static void luo_session_free(struct luo_session *session)
137{
138 luo_file_set_destroy(&session->file_set);
139 mutex_destroy(&session->mutex);
140 kfree(session);
141}
142
143static int luo_session_insert(struct luo_session_header *sh,
144 struct luo_session *session)
145{
146 struct luo_session *it;
147
148 guard(rwsem_write)(&sh->rwsem);
149
150 /*
151 * For outgoing we should make sure there is room in serialization array
152 * for new session.
153 */
154 if (sh == &luo_session_global.outgoing) {
155 if (sh->count == LUO_SESSION_MAX)
156 return -ENOMEM;
157 }
158
159 /*
160 * For small number of sessions this loop won't hurt performance
161 * but if we ever start using a lot of sessions, this might
162 * become a bottle neck during deserialization time, as it would
163 * cause O(n*n) complexity.
164 */
165 list_for_each_entry(it, &sh->list, list) {
166 if (!strncmp(it->name, session->name, sizeof(it->name)))
167 return -EEXIST;
168 }
169 list_add_tail(&session->list, &sh->list);
170 sh->count++;
171
172 return 0;
173}
174
175static void luo_session_remove(struct luo_session_header *sh,
176 struct luo_session *session)
177{
178 guard(rwsem_write)(&sh->rwsem);
179 list_del(&session->list);
180 sh->count--;
181}
182
183static int luo_session_finish_one(struct luo_session *session)
184{
185 guard(mutex)(&session->mutex);
186 return luo_file_finish(&session->file_set);
187}
188
189static void luo_session_unfreeze_one(struct luo_session *session,
190 struct luo_session_ser *ser)
191{
192 guard(mutex)(&session->mutex);
193 luo_file_unfreeze(&session->file_set, &ser->file_set_ser);
194}
195
196static int luo_session_freeze_one(struct luo_session *session,
197 struct luo_session_ser *ser)
198{
199 guard(mutex)(&session->mutex);
200 return luo_file_freeze(&session->file_set, &ser->file_set_ser);
201}
202
203static int luo_session_release(struct inode *inodep, struct file *filep)
204{
205 struct luo_session *session = filep->private_data;
206 struct luo_session_header *sh;
207
208 /* If retrieved is set, it means this session is from incoming list */
209 if (session->retrieved) {
210 int err = luo_session_finish_one(session);
211
212 if (err) {
213 pr_warn("Unable to finish session [%s] on release\n",
214 session->name);
215 return err;
216 }
217 sh = &luo_session_global.incoming;
218 } else {
219 scoped_guard(mutex, &session->mutex)
220 luo_file_unpreserve_files(&session->file_set);
221 sh = &luo_session_global.outgoing;
222 }
223
224 luo_session_remove(sh, session);
225 luo_session_free(session);
226
227 return 0;
228}
229
230static int luo_session_preserve_fd(struct luo_session *session,
231 struct luo_ucmd *ucmd)
232{
233 struct liveupdate_session_preserve_fd *argp = ucmd->cmd;
234 int err;
235
236 guard(mutex)(&session->mutex);
237 err = luo_preserve_file(&session->file_set, argp->token, argp->fd);
238 if (err)
239 return err;
240
241 err = luo_ucmd_respond(ucmd, sizeof(*argp));
242 if (err)
243 pr_warn("The file was successfully preserved, but response to user failed\n");
244
245 return err;
246}
247
248static int luo_session_retrieve_fd(struct luo_session *session,
249 struct luo_ucmd *ucmd)
250{
251 struct liveupdate_session_retrieve_fd *argp = ucmd->cmd;
252 struct file *file;
253 int err;
254
255 argp->fd = get_unused_fd_flags(O_CLOEXEC);
256 if (argp->fd < 0)
257 return argp->fd;
258
259 guard(mutex)(&session->mutex);
260 err = luo_retrieve_file(&session->file_set, argp->token, &file);
261 if (err < 0)
262 goto err_put_fd;
263
264 err = luo_ucmd_respond(ucmd, sizeof(*argp));
265 if (err)
266 goto err_put_file;
267
268 fd_install(argp->fd, file);
269
270 return 0;
271
272err_put_file:
273 fput(file);
274err_put_fd:
275 put_unused_fd(argp->fd);
276
277 return err;
278}
279
280static int luo_session_finish(struct luo_session *session,
281 struct luo_ucmd *ucmd)
282{
283 struct liveupdate_session_finish *argp = ucmd->cmd;
284 int err = luo_session_finish_one(session);
285
286 if (err)
287 return err;
288
289 return luo_ucmd_respond(ucmd, sizeof(*argp));
290}
291
292union ucmd_buffer {
293 struct liveupdate_session_finish finish;
294 struct liveupdate_session_preserve_fd preserve;
295 struct liveupdate_session_retrieve_fd retrieve;
296};
297
298struct luo_ioctl_op {
299 unsigned int size;
300 unsigned int min_size;
301 unsigned int ioctl_num;
302 int (*execute)(struct luo_session *session, struct luo_ucmd *ucmd);
303};
304
305#define IOCTL_OP(_ioctl, _fn, _struct, _last) \
306 [_IOC_NR(_ioctl) - LIVEUPDATE_CMD_SESSION_BASE] = { \
307 .size = sizeof(_struct) + \
308 BUILD_BUG_ON_ZERO(sizeof(union ucmd_buffer) < \
309 sizeof(_struct)), \
310 .min_size = offsetofend(_struct, _last), \
311 .ioctl_num = _ioctl, \
312 .execute = _fn, \
313 }
314
315static const struct luo_ioctl_op luo_session_ioctl_ops[] = {
316 IOCTL_OP(LIVEUPDATE_SESSION_FINISH, luo_session_finish,
317 struct liveupdate_session_finish, reserved),
318 IOCTL_OP(LIVEUPDATE_SESSION_PRESERVE_FD, luo_session_preserve_fd,
319 struct liveupdate_session_preserve_fd, token),
320 IOCTL_OP(LIVEUPDATE_SESSION_RETRIEVE_FD, luo_session_retrieve_fd,
321 struct liveupdate_session_retrieve_fd, token),
322};
323
324static long luo_session_ioctl(struct file *filep, unsigned int cmd,
325 unsigned long arg)
326{
327 struct luo_session *session = filep->private_data;
328 const struct luo_ioctl_op *op;
329 struct luo_ucmd ucmd = {};
330 union ucmd_buffer buf;
331 unsigned int nr;
332 int ret;
333
334 nr = _IOC_NR(cmd);
335 if (nr < LIVEUPDATE_CMD_SESSION_BASE || (nr - LIVEUPDATE_CMD_SESSION_BASE) >=
336 ARRAY_SIZE(luo_session_ioctl_ops)) {
337 return -EINVAL;
338 }
339
340 ucmd.ubuffer = (void __user *)arg;
341 ret = get_user(ucmd.user_size, (u32 __user *)ucmd.ubuffer);
342 if (ret)
343 return ret;
344
345 op = &luo_session_ioctl_ops[nr - LIVEUPDATE_CMD_SESSION_BASE];
346 if (op->ioctl_num != cmd)
347 return -ENOIOCTLCMD;
348 if (ucmd.user_size < op->min_size)
349 return -EINVAL;
350
351 ucmd.cmd = &buf;
352 ret = copy_struct_from_user(ucmd.cmd, op->size, ucmd.ubuffer,
353 ucmd.user_size);
354 if (ret)
355 return ret;
356
357 return op->execute(session, &ucmd);
358}
359
360static const struct file_operations luo_session_fops = {
361 .owner = THIS_MODULE,
362 .release = luo_session_release,
363 .unlocked_ioctl = luo_session_ioctl,
364};
365
366/* Create a "struct file" for session */
367static int luo_session_getfile(struct luo_session *session, struct file **filep)
368{
369 char name_buf[128];
370 struct file *file;
371
372 lockdep_assert_held(&session->mutex);
373 snprintf(name_buf, sizeof(name_buf), "[luo_session] %s", session->name);
374 file = anon_inode_getfile(name_buf, &luo_session_fops, session, O_RDWR);
375 if (IS_ERR(file))
376 return PTR_ERR(file);
377
378 *filep = file;
379
380 return 0;
381}
382
383int luo_session_create(const char *name, struct file **filep)
384{
385 struct luo_session *session;
386 int err;
387
388 session = luo_session_alloc(name);
389 if (IS_ERR(session))
390 return PTR_ERR(session);
391
392 err = luo_session_insert(&luo_session_global.outgoing, session);
393 if (err)
394 goto err_free;
395
396 scoped_guard(mutex, &session->mutex)
397 err = luo_session_getfile(session, filep);
398 if (err)
399 goto err_remove;
400
401 return 0;
402
403err_remove:
404 luo_session_remove(&luo_session_global.outgoing, session);
405err_free:
406 luo_session_free(session);
407
408 return err;
409}
410
411int luo_session_retrieve(const char *name, struct file **filep)
412{
413 struct luo_session_header *sh = &luo_session_global.incoming;
414 struct luo_session *session = NULL;
415 struct luo_session *it;
416 int err;
417
418 scoped_guard(rwsem_read, &sh->rwsem) {
419 list_for_each_entry(it, &sh->list, list) {
420 if (!strncmp(it->name, name, sizeof(it->name))) {
421 session = it;
422 break;
423 }
424 }
425 }
426
427 if (!session)
428 return -ENOENT;
429
430 guard(mutex)(&session->mutex);
431 if (session->retrieved)
432 return -EINVAL;
433
434 err = luo_session_getfile(session, filep);
435 if (!err)
436 session->retrieved = true;
437
438 return err;
439}
440
441int __init luo_session_setup_outgoing(void *fdt_out)
442{
443 struct luo_session_header_ser *header_ser;
444 u64 header_ser_pa;
445 int err;
446
447 header_ser = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT);
448 if (IS_ERR(header_ser))
449 return PTR_ERR(header_ser);
450 header_ser_pa = virt_to_phys(header_ser);
451
452 err = fdt_begin_node(fdt_out, LUO_FDT_SESSION_NODE_NAME);
453 err |= fdt_property_string(fdt_out, "compatible",
454 LUO_FDT_SESSION_COMPATIBLE);
455 err |= fdt_property(fdt_out, LUO_FDT_SESSION_HEADER, &header_ser_pa,
456 sizeof(header_ser_pa));
457 err |= fdt_end_node(fdt_out);
458
459 if (err)
460 goto err_unpreserve;
461
462 luo_session_global.outgoing.header_ser = header_ser;
463 luo_session_global.outgoing.ser = (void *)(header_ser + 1);
464 luo_session_global.outgoing.active = true;
465
466 return 0;
467
468err_unpreserve:
469 kho_unpreserve_free(header_ser);
470 return err;
471}
472
473int __init luo_session_setup_incoming(void *fdt_in)
474{
475 struct luo_session_header_ser *header_ser;
476 int err, header_size, offset;
477 u64 header_ser_pa;
478 const void *ptr;
479
480 offset = fdt_subnode_offset(fdt_in, 0, LUO_FDT_SESSION_NODE_NAME);
481 if (offset < 0) {
482 pr_err("Unable to get session node: [%s]\n",
483 LUO_FDT_SESSION_NODE_NAME);
484 return -EINVAL;
485 }
486
487 err = fdt_node_check_compatible(fdt_in, offset,
488 LUO_FDT_SESSION_COMPATIBLE);
489 if (err) {
490 pr_err("Session node incompatible [%s]\n",
491 LUO_FDT_SESSION_COMPATIBLE);
492 return -EINVAL;
493 }
494
495 header_size = 0;
496 ptr = fdt_getprop(fdt_in, offset, LUO_FDT_SESSION_HEADER, &header_size);
497 if (!ptr || header_size != sizeof(u64)) {
498 pr_err("Unable to get session header '%s' [%d]\n",
499 LUO_FDT_SESSION_HEADER, header_size);
500 return -EINVAL;
501 }
502
503 header_ser_pa = get_unaligned((u64 *)ptr);
504 header_ser = phys_to_virt(header_ser_pa);
505
506 luo_session_global.incoming.header_ser = header_ser;
507 luo_session_global.incoming.ser = (void *)(header_ser + 1);
508 luo_session_global.incoming.active = true;
509
510 return 0;
511}
512
513int luo_session_deserialize(void)
514{
515 struct luo_session_header *sh = &luo_session_global.incoming;
516 static bool is_deserialized;
517 static int err;
518
519 /* If has been deserialized, always return the same error code */
520 if (is_deserialized)
521 return err;
522
523 is_deserialized = true;
524 if (!sh->active)
525 return 0;
526
527 /*
528 * Note on error handling:
529 *
530 * If deserialization fails (e.g., allocation failure or corrupt data),
531 * we intentionally skip cleanup of sessions that were already restored.
532 *
533 * A partial failure leaves the preserved state inconsistent.
534 * Implementing a safe "undo" to unwind complex dependencies (sessions,
535 * files, hardware state) is error-prone and provides little value, as
536 * the system is effectively in a broken state.
537 *
538 * We treat these resources as leaked. The expected recovery path is for
539 * userspace to detect the failure and trigger a reboot, which will
540 * reliably reset devices and reclaim memory.
541 */
542 for (int i = 0; i < sh->header_ser->count; i++) {
543 struct luo_session *session;
544
545 session = luo_session_alloc(sh->ser[i].name);
546 if (IS_ERR(session)) {
547 pr_warn("Failed to allocate session [%s] during deserialization %pe\n",
548 sh->ser[i].name, session);
549 return PTR_ERR(session);
550 }
551
552 err = luo_session_insert(sh, session);
553 if (err) {
554 pr_warn("Failed to insert session [%s] %pe\n",
555 session->name, ERR_PTR(err));
556 luo_session_free(session);
557 return err;
558 }
559
560 scoped_guard(mutex, &session->mutex) {
561 luo_file_deserialize(&session->file_set,
562 &sh->ser[i].file_set_ser);
563 }
564 }
565
566 kho_restore_free(sh->header_ser);
567 sh->header_ser = NULL;
568 sh->ser = NULL;
569
570 return 0;
571}
572
573int luo_session_serialize(void)
574{
575 struct luo_session_header *sh = &luo_session_global.outgoing;
576 struct luo_session *session;
577 int i = 0;
578 int err;
579
580 guard(rwsem_write)(&sh->rwsem);
581 list_for_each_entry(session, &sh->list, list) {
582 err = luo_session_freeze_one(session, &sh->ser[i]);
583 if (err)
584 goto err_undo;
585
586 strscpy(sh->ser[i].name, session->name,
587 sizeof(sh->ser[i].name));
588 i++;
589 }
590 sh->header_ser->count = sh->count;
591
592 return 0;
593
594err_undo:
595 list_for_each_entry_continue_reverse(session, &sh->list, list) {
596 i--;
597 luo_session_unfreeze_one(session, &sh->ser[i]);
598 memset(sh->ser[i].name, 0, sizeof(sh->ser[i].name));
599 }
600
601 return err;
602}
603
604/**
605 * luo_session_quiesce - Ensure no active sessions exist and lock session lists.
606 *
607 * Acquires exclusive write locks on both incoming and outgoing session lists.
608 * It then validates no sessions exist in either list.
609 *
610 * This mechanism is used during file handler un/registration to ensure that no
611 * sessions are currently using the handler, and no new sessions can be created
612 * while un/registration is in progress.
613 *
614 * This prevents registering new handlers while sessions are active or
615 * while deserialization is in progress.
616 *
617 * Return:
618 * true - System is quiescent (0 sessions) and locked.
619 * false - Active sessions exist. The locks are released internally.
620 */
621bool luo_session_quiesce(void)
622{
623 down_write(&luo_session_global.incoming.rwsem);
624 down_write(&luo_session_global.outgoing.rwsem);
625
626 if (luo_session_global.incoming.count ||
627 luo_session_global.outgoing.count) {
628 up_write(&luo_session_global.outgoing.rwsem);
629 up_write(&luo_session_global.incoming.rwsem);
630 return false;
631 }
632
633 return true;
634}
635
636/**
637 * luo_session_resume - Unlock session lists and resume normal activity.
638 *
639 * Releases the exclusive locks acquired by a successful call to
640 * luo_session_quiesce().
641 */
642void luo_session_resume(void)
643{
644 up_write(&luo_session_global.outgoing.rwsem);
645 up_write(&luo_session_global.incoming.rwsem);
646}
kernel/module/main.c+1−1
@@ -954,7 +954,7 @@ size_t module_flags_taint(unsigned long taints, char *buf) · 953 unmodified lines
954 int i;954 int i;
955 955
956 for (i = 0; i < TAINT_FLAGS_COUNT; i++) {956 for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
957 if (taint_flags[i].module && test_bit(i, &taints))957 if (test_bit(i, &taints))
958 buf[l++] = taint_flags[i].c_true;958 buf[l++] = taint_flags[i].c_true;
959 }959 }
960 960
kernel/panic.c+27−25
@@ -401,7 +401,7 @@ static void panic_trigger_all_cpu_backtrace(void) · 400 unmodified lines
401 */401 */
402static void panic_other_cpus_shutdown(bool crash_kexec)402static void panic_other_cpus_shutdown(bool crash_kexec)
403{403{
404 if (panic_print & SYS_INFO_ALL_CPU_BT)404 if (panic_print & SYS_INFO_ALL_BT)
405 panic_trigger_all_cpu_backtrace();405 panic_trigger_all_cpu_backtrace();
406 406
407 /*407 /*
@@ -628,38 +628,40 @@ void panic(const char *fmt, ...) · 220 unmodified lines
628}628}
629EXPORT_SYMBOL(panic);629EXPORT_SYMBOL(panic);
630 630
631#define TAINT_FLAG(taint, _c_true, _c_false, _module) \631#define TAINT_FLAG(taint, _c_true, _c_false) \
632 [ TAINT_##taint ] = { \632 [ TAINT_##taint ] = { \
633 .c_true = _c_true, .c_false = _c_false, \633 .c_true = _c_true, .c_false = _c_false, \
634 .module = _module, \
635 .desc = #taint, \634 .desc = #taint, \
636 }635 }
637 636
638/*637/*
639 * TAINT_FORCED_RMMOD could be a per-module flag but the module638 * NOTE: if you modify the taint_flags or TAINT_FLAGS_COUNT,
640 * is being removed anyway.639 * please also modify tools/debugging/kernel-chktaint and
640 * Documentation/admin-guide/tainted-kernels.rst, including its
641 * small shell script that prints the TAINT_FLAGS_COUNT bits of
642 * /proc/sys/kernel/tainted.
641 */643 */
642const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {644const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
643 TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G', true),645 TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
644 TAINT_FLAG(FORCED_MODULE, 'F', ' ', true),646 TAINT_FLAG(FORCED_MODULE, 'F', ' '),
645 TAINT_FLAG(CPU_OUT_OF_SPEC, 'S', ' ', false),647 TAINT_FLAG(CPU_OUT_OF_SPEC, 'S', ' '),
646 TAINT_FLAG(FORCED_RMMOD, 'R', ' ', false),648 TAINT_FLAG(FORCED_RMMOD, 'R', ' '),
647 TAINT_FLAG(MACHINE_CHECK, 'M', ' ', false),649 TAINT_FLAG(MACHINE_CHECK, 'M', ' '),
648 TAINT_FLAG(BAD_PAGE, 'B', ' ', false),650 TAINT_FLAG(BAD_PAGE, 'B', ' '),
649 TAINT_FLAG(USER, 'U', ' ', false),651 TAINT_FLAG(USER, 'U', ' '),
650 TAINT_FLAG(DIE, 'D', ' ', false),652 TAINT_FLAG(DIE, 'D', ' '),
651 TAINT_FLAG(OVERRIDDEN_ACPI_TABLE, 'A', ' ', false),653 TAINT_FLAG(OVERRIDDEN_ACPI_TABLE, 'A', ' '),
652 TAINT_FLAG(WARN, 'W', ' ', false),654 TAINT_FLAG(WARN, 'W', ' '),
653 TAINT_FLAG(CRAP, 'C', ' ', true),655 TAINT_FLAG(CRAP, 'C', ' '),
654 TAINT_FLAG(FIRMWARE_WORKAROUND, 'I', ' ', false),656 TAINT_FLAG(FIRMWARE_WORKAROUND, 'I', ' '),
655 TAINT_FLAG(OOT_MODULE, 'O', ' ', true),657 TAINT_FLAG(OOT_MODULE, 'O', ' '),
656 TAINT_FLAG(UNSIGNED_MODULE, 'E', ' ', true),658 TAINT_FLAG(UNSIGNED_MODULE, 'E', ' '),
657 TAINT_FLAG(SOFTLOCKUP, 'L', ' ', false),659 TAINT_FLAG(SOFTLOCKUP, 'L', ' '),
658 TAINT_FLAG(LIVEPATCH, 'K', ' ', true),660 TAINT_FLAG(LIVEPATCH, 'K', ' '),
659 TAINT_FLAG(AUX, 'X', ' ', true),661 TAINT_FLAG(AUX, 'X', ' '),
660 TAINT_FLAG(RANDSTRUCT, 'T', ' ', true),662 TAINT_FLAG(RANDSTRUCT, 'T', ' '),
661 TAINT_FLAG(TEST, 'N', ' ', true),663 TAINT_FLAG(TEST, 'N', ' '),
662 TAINT_FLAG(FWCTL, 'J', ' ', true),664 TAINT_FLAG(FWCTL, 'J', ' '),
663};665};
664 666
665#undef TAINT_FLAG667#undef TAINT_FLAG
kernel/resource.c+9−1
@@ -341,6 +341,8 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, · 340 unmodified lines
341 unsigned long flags, unsigned long desc,341 unsigned long flags, unsigned long desc,
342 struct resource *res)342 struct resource *res)
343{343{
344 /* Skip children until we find a top level range that matches */
345 bool skip_children = true;
344 struct resource *p;346 struct resource *p;
345 347
346 if (!res)348 if (!res)
@@ -351,7 +353,7 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, · 4 unmodified lines
351 353
352 read_lock(&resource_lock);354 read_lock(&resource_lock);
353 355
354 for_each_resource(&iomem_resource, p, false) {356 for_each_resource(&iomem_resource, p, skip_children) {
355 /* If we passed the resource we are looking for, stop */357 /* If we passed the resource we are looking for, stop */
356 if (p->start > end) {358 if (p->start > end) {
357 p = NULL;359 p = NULL;
@@ -362,6 +364,12 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end, · 4 unmodified lines
362 if (p->end < start)364 if (p->end < start)
363 continue;365 continue;
364 366
367 /*
368 * We found a top level range that matches what we are looking
369 * for. Time to start checking children too.
370 */
371 skip_children = false;
372
365 /* Found a match, break */373 /* Found a match, break */
366 if (is_type_match(p, flags, desc))374 if (is_type_match(p, flags, desc))
367 break;375 break;
kernel/scs.c+1−1
@@ -135,7 +135,7 @@ static void scs_check_usage(struct task_struct *tsk) · 134 unmodified lines
135 if (!IS_ENABLED(CONFIG_DEBUG_STACK_USAGE))135 if (!IS_ENABLED(CONFIG_DEBUG_STACK_USAGE))
136 return;136 return;
137 137
138 for (p = task_scs(tsk); p < __scs_magic(tsk); ++p) {138 for (p = task_scs(tsk); p < __scs_magic(task_scs(tsk)); ++p) {
139 if (!READ_ONCE_NOCHECK(*p))139 if (!READ_ONCE_NOCHECK(*p))
140 break;140 break;
141 used += sizeof(*p);141 used += sizeof(*p);
kernel/vmcore_info.c+17−0
@@ -31,6 +31,13 @@ u32 *vmcoreinfo_note; · 30 unmodified lines
31/* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */31/* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
32static unsigned char *vmcoreinfo_data_safecopy;32static unsigned char *vmcoreinfo_data_safecopy;
33 33
34struct hwerr_info {
35 atomic_t count;
36 time64_t timestamp;
37};
38
39static struct hwerr_info hwerr_data[HWERR_RECOV_MAX];
40
34Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,41Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
35 void *data, size_t data_len)42 void *data, size_t data_len)
36{43{
@@ -118,6 +125,16 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void) · 81 unmodified lines
118}125}
119EXPORT_SYMBOL(paddr_vmcoreinfo_note);126EXPORT_SYMBOL(paddr_vmcoreinfo_note);
120 127
128void hwerr_log_error_type(enum hwerr_error_type src)
129{
130 if (src < 0 || src >= HWERR_RECOV_MAX)
131 return;
132
133 atomic_inc(&hwerr_data[src].count);
134 WRITE_ONCE(hwerr_data[src].timestamp, ktime_get_real_seconds());
135}
136EXPORT_SYMBOL_GPL(hwerr_log_error_type);
137
121static int __init crash_save_vmcoreinfo_init(void)138static int __init crash_save_vmcoreinfo_init(void)
122{139{
123 vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL);140 vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL);
kernel/watchdog.c+41−3
@@ -25,6 +25,7 @@ · 24 unmodified lines
25#include <linux/stop_machine.h>25#include <linux/stop_machine.h>
26#include <linux/sysctl.h>26#include <linux/sysctl.h>
27#include <linux/tick.h>27#include <linux/tick.h>
28#include <linux/sys_info.h>
28 29
29#include <linux/sched/clock.h>30#include <linux/sched/clock.h>
30#include <linux/sched/debug.h>31#include <linux/sched/debug.h>
@@ -65,6 +66,13 @@ int __read_mostly sysctl_hardlockup_all_cpu_backtrace; · 34 unmodified lines
65unsigned int __read_mostly hardlockup_panic =66unsigned int __read_mostly hardlockup_panic =
66 IS_ENABLED(CONFIG_BOOTPARAM_HARDLOCKUP_PANIC);67 IS_ENABLED(CONFIG_BOOTPARAM_HARDLOCKUP_PANIC);
67 68
69/*
70 * bitmasks to control what kinds of system info to be printed when
71 * hard lockup is detected, it could be task, memory, lock etc.
72 * Refer include/linux/sys_info.h for detailed bit definition.
73 */
74static unsigned long hardlockup_si_mask;
75
68#ifdef CONFIG_SYSFS76#ifdef CONFIG_SYSFS
69 77
70static unsigned int hardlockup_count;78static unsigned int hardlockup_count;
@@ -178,11 +186,15 @@ static void watchdog_hardlockup_kick(void) · 107 unmodified lines
178 186
179void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)187void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
180{188{
189 int hardlockup_all_cpu_backtrace;
190
181 if (per_cpu(watchdog_hardlockup_touched, cpu)) {191 if (per_cpu(watchdog_hardlockup_touched, cpu)) {
182 per_cpu(watchdog_hardlockup_touched, cpu) = false;192 per_cpu(watchdog_hardlockup_touched, cpu) = false;
183 return;193 return;
184 }194 }
185 195
196 hardlockup_all_cpu_backtrace = (hardlockup_si_mask & SYS_INFO_ALL_BT) ?
197 1 : sysctl_hardlockup_all_cpu_backtrace;
186 /*198 /*
187 * Check for a hardlockup by making sure the CPU's timer199 * Check for a hardlockup by making sure the CPU's timer
188 * interrupt is incrementing. The timer interrupt should have200 * interrupt is incrementing. The timer interrupt should have
@@ -214,7 +226,7 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs) · 25 unmodified lines
214 * Prevent multiple hard-lockup reports if one cpu is already226 * Prevent multiple hard-lockup reports if one cpu is already
215 * engaged in dumping all cpu back traces.227 * engaged in dumping all cpu back traces.
216 */228 */
217 if (sysctl_hardlockup_all_cpu_backtrace) {229 if (hardlockup_all_cpu_backtrace) {
218 if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))230 if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))
219 return;231 return;
220 }232 }
@@ -243,12 +255,13 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs) · 22 unmodified lines
243 trigger_single_cpu_backtrace(cpu);255 trigger_single_cpu_backtrace(cpu);
244 }256 }
245 257
246 if (sysctl_hardlockup_all_cpu_backtrace) {258 if (hardlockup_all_cpu_backtrace) {
247 trigger_allbutcpu_cpu_backtrace(cpu);259 trigger_allbutcpu_cpu_backtrace(cpu);
248 if (!hardlockup_panic)260 if (!hardlockup_panic)
249 clear_bit_unlock(0, &hard_lockup_nmi_warn);261 clear_bit_unlock(0, &hard_lockup_nmi_warn);
250 }262 }
251 263
264 sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
252 if (hardlockup_panic)265 if (hardlockup_panic)
253 nmi_panic(regs, "Hard LOCKUP");266 nmi_panic(regs, "Hard LOCKUP");
254 267
@@ -339,6 +352,13 @@ static void lockup_detector_update_enable(void) · 84 unmodified lines
339int __read_mostly sysctl_softlockup_all_cpu_backtrace;352int __read_mostly sysctl_softlockup_all_cpu_backtrace;
340#endif353#endif
341 354
355/*
356 * bitmasks to control what kinds of system info to be printed when
357 * soft lockup is detected, it could be task, memory, lock etc.
358 * Refer include/linux/sys_info.h for detailed bit definition.
359 */
360static unsigned long softlockup_si_mask;
361
342static struct cpumask watchdog_allowed_mask __read_mostly;362static struct cpumask watchdog_allowed_mask __read_mostly;
343 363
344/* Global variables, exported for sysctl */364/* Global variables, exported for sysctl */
@@ -755,7 +775,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) · 410 unmodified lines
755 unsigned long touch_ts, period_ts, now;775 unsigned long touch_ts, period_ts, now;
756 struct pt_regs *regs = get_irq_regs();776 struct pt_regs *regs = get_irq_regs();
757 int duration;777 int duration;
758 int softlockup_all_cpu_backtrace = sysctl_softlockup_all_cpu_backtrace;778 int softlockup_all_cpu_backtrace;
759 unsigned long flags;779 unsigned long flags;
760 780
761 if (!watchdog_enabled)781 if (!watchdog_enabled)
@@ -767,6 +787,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) · 5 unmodified lines
767 if (panic_in_progress())787 if (panic_in_progress())
768 return HRTIMER_NORESTART;788 return HRTIMER_NORESTART;
769 789
790 softlockup_all_cpu_backtrace = (softlockup_si_mask & SYS_INFO_ALL_BT) ?
791 1 : sysctl_softlockup_all_cpu_backtrace;
792
770 watchdog_hardlockup_kick();793 watchdog_hardlockup_kick();
771 794
772 /* kick the softlockup detector */795 /* kick the softlockup detector */
@@ -855,6 +878,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) · 82 unmodified lines
855 }878 }
856 879
857 add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);880 add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
881 sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
858 if (softlockup_panic)882 if (softlockup_panic)
859 panic("softlockup: hung tasks");883 panic("softlockup: hung tasks");
860 }884 }
@@ -1206,6 +1230,13 @@ static const struct ctl_table watchdog_sysctls[] = { · 345 unmodified lines
1206 .extra1 = SYSCTL_ZERO,1230 .extra1 = SYSCTL_ZERO,
1207 .extra2 = SYSCTL_ONE,1231 .extra2 = SYSCTL_ONE,
1208 },1232 },
1233 {
1234 .procname = "softlockup_sys_info",
1235 .data = &softlockup_si_mask,
1236 .maxlen = sizeof(softlockup_si_mask),
1237 .mode = 0644,
1238 .proc_handler = sysctl_sys_info_handler,
1239 },
1209#ifdef CONFIG_SMP1240#ifdef CONFIG_SMP
1210 {1241 {
1211 .procname = "softlockup_all_cpu_backtrace",1242 .procname = "softlockup_all_cpu_backtrace",
@@ -1228,6 +1259,13 @@ static const struct ctl_table watchdog_sysctls[] = { · 16 unmodified lines
1228 .extra1 = SYSCTL_ZERO,1259 .extra1 = SYSCTL_ZERO,
1229 .extra2 = SYSCTL_ONE,1260 .extra2 = SYSCTL_ONE,
1230 },1261 },
1262 {
1263 .procname = "hardlockup_sys_info",
1264 .data = &hardlockup_si_mask,
1265 .maxlen = sizeof(hardlockup_si_mask),
1266 .mode = 0644,
1267 .proc_handler = sysctl_sys_info_handler,
1268 },
1231#ifdef CONFIG_SMP1269#ifdef CONFIG_SMP
1232 {1270 {
1233 .procname = "hardlockup_all_cpu_backtrace",1271 .procname = "hardlockup_all_cpu_backtrace",
lib/Kconfig.debug+40−23
@@ -342,8 +342,7 @@ config DEBUG_INFO_COMPRESSED_ZLIB · 341 unmodified lines
342 depends on $(cc-option,-gz=zlib)342 depends on $(cc-option,-gz=zlib)
343 depends on $(ld-option,--compress-debug-sections=zlib)343 depends on $(ld-option,--compress-debug-sections=zlib)
344 help344 help
345 Compress the debug information using zlib. Requires GCC 5.0+ or Clang345 Compress the debug information using zlib.
346 5.0+, binutils 2.26+, and zlib.
347 346
348 Users of dpkg-deb via debian/rules may find an increase in347 Users of dpkg-deb via debian/rules may find an increase in
349 size of their debug .deb packages with this config set, due to the348 size of their debug .deb packages with this config set, due to the
@@ -493,23 +492,23 @@ config DEBUG_SECTION_MISMATCH · 143 unmodified lines
493 bool "Enable full Section mismatch analysis"492 bool "Enable full Section mismatch analysis"
494 depends on CC_IS_GCC493 depends on CC_IS_GCC
495 help494 help
496 The section mismatch analysis checks if there are illegal495 The section mismatch analysis checks if there are illegal references
497 references from one section to another section.496 from one section to another. During linktime or runtime, some
498 During linktime or runtime, some sections are dropped;497 sections are dropped; any use of code/data previously in these
499 any use of code/data previously in these sections would498 sections would most likely result in an oops.
500 most likely result in an oops.499
501 In the code, functions and variables are annotated with500 In the code, functions and variables are annotated with __init,
502 __init,, etc. (see the full list in include/linux/init.h),501 __initdata, and so on (see the full list in include/linux/init.h).
503 which results in the code/data being placed in specific sections.502 This directs the toolchain to place code/data in specific sections.
503
504 The section mismatch analysis is always performed after a full504 The section mismatch analysis is always performed after a full
505 kernel build, and enabling this option causes the following505 kernel build, and enabling this option causes the option
506 additional step to occur:506 -fno-inline-functions-called-once to be added to gcc commands.
507 - Add the option -fno-inline-functions-called-once to gcc commands.507
508 When inlining a function annotated with __init in a non-init508 However, when inlining a function annotated with __init in
509 function, we would lose the section information and thus509 a non-init function, we would lose the section information and thus
510 the analysis would not catch the illegal reference.510 the analysis would not catch the illegal reference. This option
511 This option tells gcc to inline less (but it does result in511 tells gcc to inline less (but it does result in a larger kernel).
512 a larger kernel).
513 512
514config SECTION_MISMATCH_WARN_ONLY513config SECTION_MISMATCH_WARN_ONLY
515 bool "Make section mismatch errors non-fatal"514 bool "Make section mismatch errors non-fatal"
@@ -1260,12 +1259,13 @@ config DEFAULT_HUNG_TASK_TIMEOUT · 744 unmodified lines
1260 Keeping the default should be fine in most cases.1259 Keeping the default should be fine in most cases.
1261 1260
1262config BOOTPARAM_HUNG_TASK_PANIC1261config BOOTPARAM_HUNG_TASK_PANIC
1263 bool "Panic (Reboot) On Hung Tasks"1262 int "Number of hung tasks to trigger kernel panic"
1264 depends on DETECT_HUNG_TASK1263 depends on DETECT_HUNG_TASK
1264 default 0
1265 help1265 help
1266 Say Y here to enable the kernel to panic on "hung tasks",1266 When set to a non-zero value, a kernel panic will be triggered
1267 which are bugs that cause the kernel to leave a task stuck1267 if the number of hung tasks found during a single scan reaches
1268 in uninterruptible "D" state.1268 this value.
1269 1269
1270 The panic can be used in combination with panic_timeout,1270 The panic can be used in combination with panic_timeout,
1271 to cause the system to reboot automatically after a1271 to cause the system to reboot automatically after a
@@ -2817,8 +2817,25 @@ config CMDLINE_KUNIT_TEST · 1545 unmodified lines
2817 2817
2818 If unsure, say N.2818 If unsure, say N.
2819 2819
2820config BASE64_KUNIT
2821 tristate "KUnit test for base64 decoding and encoding" if !KUNIT_ALL_TESTS
2822 depends on KUNIT
2823 default KUNIT_ALL_TESTS
2824 help
2825 This builds the base64 unit tests.
2826
2827 The tests cover the encoding and decoding logic of Base64 functions
2828 in the kernel.
2829 In addition to correctness checks, simple performance benchmarks
2830 for both encoding and decoding are also included.
2831
2832 For more information on KUnit and unit tests in general please refer
2833 to the KUnit documentation in Documentation/dev-tools/kunit/.
2834
2835 If unsure, say N.
2836
2820config BITS_TEST2837config BITS_TEST
2821 tristate "KUnit test for bits.h" if !KUNIT_ALL_TESTS2838 tristate "KUnit test for bit functions and macros" if !KUNIT_ALL_TESTS
2822 depends on KUNIT2839 depends on KUNIT
2823 default KUNIT_ALL_TESTS2840 default KUNIT_ALL_TESTS
2824 help2841 help
lib/base64.c+135−54
@@ -1,12 +1,12 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2/*2/*
3 * base64.c - RFC4648-compliant base64 encoding3 * base64.c - Base64 with support for multiple variants
4 *4 *
5 * Copyright (c) 2020 Hannes Reinecke, SUSE5 * Copyright (c) 2020 Hannes Reinecke, SUSE
6 *6 *
7 * Based on the base64url routines from fs/crypto/fname.c7 * Based on the base64url routines from fs/crypto/fname.c
8 * (which are using the URL-safe base64 encoding),8 * (which are using the URL-safe Base64 encoding),
9 * modified to use the standard coding table from RFC4648 section 4.9 * modified to support multiple Base64 variants.
10 */10 */
11 11
12#include <linux/kernel.h>12#include <linux/kernel.h>
@@ -15,89 +15,170 @@ · 2 unmodified lines
15#include <linux/string.h>15#include <linux/string.h>
16#include <linux/base64.h>16#include <linux/base64.h>
17 17
18static const char base64_table[65] =18static const char base64_tables[][65] = {
19 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";19 [BASE64_STD] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
20 [BASE64_URLSAFE] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
21 [BASE64_IMAP] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,",
22};
20 23
24/*
25 * Initialize the base64 reverse mapping for a single character
26 * This macro maps a character to its corresponding base64 value,
27 * returning -1 if the character is invalid.
28 * char 'A'-'Z' maps to 0-25, 'a'-'z' maps to 26-51, '0'-'9' maps to 52-61,
29 * ch_62 maps to 62, ch_63 maps to 63, and other characters return -1
30 */
31#define INIT_1(v, ch_62, ch_63) \
32 [v] = (v) >= 'A' && (v) <= 'Z' ? (v) - 'A' \
33 : (v) >= 'a' && (v) <= 'z' ? (v) - 'a' + 26 \
34 : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
35 : (v) == (ch_62) ? 62 : (v) == (ch_63) ? 63 : -1
36
37/*
38 * Recursive macros to generate multiple Base64 reverse mapping table entries.
39 * Each macro generates a sequence of entries in the lookup table:
40 * INIT_2 generates 2 entries, INIT_4 generates 4, INIT_8 generates 8, and so on up to INIT_32.
41 */
42#define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
43#define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
44#define INIT_8(v, ...) INIT_4(v, __VA_ARGS__), INIT_4((v) + 4, __VA_ARGS__)
45#define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
46#define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
47
48#define BASE64_REV_INIT(ch_62, ch_63) { \
49 [0 ... 0x1f] = -1, \
50 INIT_32(0x20, ch_62, ch_63), \
51 INIT_32(0x40, ch_62, ch_63), \
52 INIT_32(0x60, ch_62, ch_63), \
53 [0x80 ... 0xff] = -1 }
54
55static const s8 base64_rev_maps[][256] = {
56 [BASE64_STD] = BASE64_REV_INIT('+', '/'),
57 [BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
58 [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
59};
60
61#undef BASE64_REV_INIT
62#undef INIT_32
63#undef INIT_16
64#undef INIT_8
65#undef INIT_4
66#undef INIT_2
67#undef INIT_1
21/**68/**
22 * base64_encode() - base64-encode some binary data69 * base64_encode() - Base64-encode some binary data
23 * @src: the binary data to encode70 * @src: the binary data to encode
24 * @srclen: the length of @src in bytes71 * @srclen: the length of @src in bytes
25 * @dst: (output) the base64-encoded string. Not NUL-terminated.72 * @dst: (output) the Base64-encoded string. Not NUL-terminated.
73 * @padding: whether to append '=' padding characters
74 * @variant: which base64 variant to use
26 *75 *
27 * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specified76 * Encodes data using the selected Base64 variant.
28 * by RFC 4648, including the '='-padding.
29 *77 *
30 * Return: the length of the resulting base64-encoded string in bytes.78 * Return: the length of the resulting Base64-encoded string in bytes.
31 */79 */
32int base64_encode(const u8 *src, int srclen, char *dst)80int base64_encode(const u8 *src, int srclen, char *dst, bool padding, enum base64_variant variant)
33{81{
34 u32 ac = 0;82 u32 ac = 0;
35 int bits = 0;
36 int i;
37 char *cp = dst;83 char *cp = dst;
84 const char *base64_table = base64_tables[variant];
38 85
39 for (i = 0; i < srclen; i++) {86 while (srclen >= 3) {
40 ac = (ac << 8) | src[i];87 ac = src[0] << 16 | src[1] << 8 | src[2];
41 bits += 8;88 *cp++ = base64_table[ac >> 18];
42 do {89 *cp++ = base64_table[(ac >> 12) & 0x3f];
43 bits -= 6;90 *cp++ = base64_table[(ac >> 6) & 0x3f];
44 *cp++ = base64_table[(ac >> bits) & 0x3f];91 *cp++ = base64_table[ac & 0x3f];
45 } while (bits >= 6);92
46 }93 src += 3;
47 if (bits) {94 srclen -= 3;
48 *cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
49 bits -= 6;
50 }95 }
51 while (bits < 0) {96
52 *cp++ = '=';97 switch (srclen) {
53 bits += 2;98 case 2:
99 ac = src[0] << 16 | src[1] << 8;
100 *cp++ = base64_table[ac >> 18];
101 *cp++ = base64_table[(ac >> 12) & 0x3f];
102 *cp++ = base64_table[(ac >> 6) & 0x3f];
103 if (padding)
104 *cp++ = '=';
105 break;
106 case 1:
107 ac = src[0] << 16;
108 *cp++ = base64_table[ac >> 18];
109 *cp++ = base64_table[(ac >> 12) & 0x3f];
110 if (padding) {
111 *cp++ = '=';
112 *cp++ = '=';
113 }
114 break;
54 }115 }
55 return cp - dst;116 return cp - dst;
56}117}
57EXPORT_SYMBOL_GPL(base64_encode);118EXPORT_SYMBOL_GPL(base64_encode);
58 119
59/**120/**
60 * base64_decode() - base64-decode a string121 * base64_decode() - Base64-decode a string
61 * @src: the string to decode. Doesn't need to be NUL-terminated.122 * @src: the string to decode. Doesn't need to be NUL-terminated.
62 * @srclen: the length of @src in bytes123 * @srclen: the length of @src in bytes
63 * @dst: (output) the decoded binary data124 * @dst: (output) the decoded binary data
125 * @padding: whether to append '=' padding characters
126 * @variant: which base64 variant to use
64 *127 *
65 * Decodes a string using base64 encoding, i.e. the "Base 64 Encoding"128 * Decodes a string using the selected Base64 variant.
66 * specified by RFC 4648, including the '='-padding.
67 *
68 * This implementation hasn't been optimized for performance.
69 *129 *
70 * Return: the length of the resulting decoded binary data in bytes,130 * Return: the length of the resulting decoded binary data in bytes,
71 * or -1 if the string isn't a valid base64 string.131 * or -1 if the string isn't a valid Base64 string.
72 */132 */
73int base64_decode(const char *src, int srclen, u8 *dst)133int base64_decode(const char *src, int srclen, u8 *dst, bool padding, enum base64_variant variant)
74{134{
75 u32 ac = 0;
76 int bits = 0;
77 int i;
78 u8 *bp = dst;135 u8 *bp = dst;
136 s8 input[4];
137 s32 val;
138 const u8 *s = (const u8 *)src;
139 const s8 *base64_rev_tables = base64_rev_maps[variant];
79 140
80 for (i = 0; i < srclen; i++) {141 while (srclen >= 4) {
81 const char *p = strchr(base64_table, src[i]);142 input[0] = base64_rev_tables[s[0]];
143 input[1] = base64_rev_tables[s[1]];
144 input[2] = base64_rev_tables[s[2]];
145 input[3] = base64_rev_tables[s[3]];
82 146
83 if (src[i] == '=') {147 val = input[0] << 18 | input[1] << 12 | input[2] << 6 | input[3];
84 ac = (ac << 6);148
85 bits += 6;149 if (unlikely(val < 0)) {
86 if (bits >= 8)150 if (!padding || srclen != 4 || s[3] != '=')
87 bits -= 8;151 return -1;
88 continue;152 padding = 0;
89 }153 srclen = s[2] == '=' ? 2 : 3;
90 if (p == NULL || src[i] == 0)154 break;
91 return -1;
92 ac = (ac << 6) | (p - base64_table);
93 bits += 6;
94 if (bits >= 8) {
95 bits -= 8;
96 *bp++ = (u8)(ac >> bits);
97 }155 }
156
157 *bp++ = val >> 16;
158 *bp++ = val >> 8;
159 *bp++ = val;
160
161 s += 4;
162 srclen -= 4;
98 }163 }
99 if (ac & ((1 << bits) - 1))164
165 if (likely(!srclen))
166 return bp - dst;
167 if (padding || srclen == 1)
100 return -1;168 return -1;
169
170 val = (base64_rev_tables[s[0]] << 12) | (base64_rev_tables[s[1]] << 6);
171 *bp++ = val >> 10;
172
173 if (srclen == 2) {
174 if (val & 0x800003ff)
175 return -1;
176 } else {
177 val |= base64_rev_tables[s[2]];
178 if (val & 0x80000003)
179 return -1;
180 *bp++ = val >> 2;
181 }
101 return bp - dst;182 return bp - dst;
102}183}
103EXPORT_SYMBOL_GPL(base64_decode);184EXPORT_SYMBOL_GPL(base64_decode);
lib/dynamic_debug.c+1−0
@@ -95,6 +95,7 @@ static const struct { unsigned flag:8; char opt_char; } opt_array[] = { · 94 unmodified lines
95 { _DPRINTK_FLAGS_INCL_SOURCENAME, 's' },95 { _DPRINTK_FLAGS_INCL_SOURCENAME, 's' },
96 { _DPRINTK_FLAGS_INCL_LINENO, 'l' },96 { _DPRINTK_FLAGS_INCL_LINENO, 'l' },
97 { _DPRINTK_FLAGS_INCL_TID, 't' },97 { _DPRINTK_FLAGS_INCL_TID, 't' },
98 { _DPRINTK_FLAGS_INCL_STACK, 'd' },
98 { _DPRINTK_FLAGS_NONE, '_' },99 { _DPRINTK_FLAGS_NONE, '_' },
99};100};
100 101
lib/math/div64.c+124−61
@@ -177,94 +177,157 @@ EXPORT_SYMBOL(div64_s64); · 176 unmodified lines
177 * Iterative div/mod for use when dividend is not expected to be much177 * Iterative div/mod for use when dividend is not expected to be much
178 * bigger than divisor.178 * bigger than divisor.
179 */179 */
180#ifndef iter_div_u64_rem
180u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)181u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
181{182{
182 return __iter_div_u64_rem(dividend, divisor, remainder);183 return __iter_div_u64_rem(dividend, divisor, remainder);
183}184}
184EXPORT_SYMBOL(iter_div_u64_rem);185EXPORT_SYMBOL(iter_div_u64_rem);
186#endif
185 187
186#ifndef mul_u64_u64_div_u64188#if !defined(mul_u64_add_u64_div_u64) || defined(test_mul_u64_add_u64_div_u64)
187u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
188{
189 if (ilog2(a) + ilog2(b) <= 62)
190 return div64_u64(a * b, c);
191 189
192#if defined(__SIZEOF_INT128__)190#define mul_add(a, b, c) add_u64_u32(mul_u32_u32(a, b), c)
193 191
192#if defined(__SIZEOF_INT128__) && !defined(test_mul_u64_add_u64_div_u64)
193static inline u64 mul_u64_u64_add_u64(u64 *p_lo, u64 a, u64 b, u64 c)
194{
194 /* native 64x64=128 bits multiplication */195 /* native 64x64=128 bits multiplication */
195 u128 prod = (u128)a * b;196 u128 prod = (u128)a * b + c;
196 u64 n_lo = prod, n_hi = prod >> 64;
197 197
198 *p_lo = prod;
199 return prod >> 64;
200}
198#else201#else
199 202static inline u64 mul_u64_u64_add_u64(u64 *p_lo, u64 a, u64 b, u64 c)
200 /* perform a 64x64=128 bits multiplication manually */203{
201 u32 a_lo = a, a_hi = a >> 32, b_lo = b, b_hi = b >> 32;204 /* perform a 64x64=128 bits multiplication in 32bit chunks */
202 u64 x, y, z;205 u64 x, y, z;
203 206
204 x = (u64)a_lo * b_lo;207 /* Since (x-1)(x-1) + 2(x-1) == x.x - 1 two u32 can be added to a u64 */
205 y = (u64)a_lo * b_hi + (u32)(x >> 32);208 x = mul_add(a, b, c);
206 z = (u64)a_hi * b_hi + (u32)(y >> 32);209 y = mul_add(a, b >> 32, c >> 32);
207 y = (u64)a_hi * b_lo + (u32)y;210 y = add_u64_u32(y, x >> 32);
208 z += (u32)(y >> 32);211 z = mul_add(a >> 32, b >> 32, y >> 32);
209 x = (y << 32) + (u32)x;212 y = mul_add(a >> 32, b, y);
210 213 *p_lo = (y << 32) + (u32)x;
211 u64 n_lo = x, n_hi = z;214 return add_u64_u32(z, y >> 32);
215}
216#endif
212 217
218#ifndef BITS_PER_ITER
219#define BITS_PER_ITER (__LONG_WIDTH__ >= 64 ? 32 : 16)
213#endif220#endif
214 221
215 /* make sure c is not zero, trigger runtime exception otherwise */222#if BITS_PER_ITER == 32
216 if (unlikely(c == 0)) {223#define mul_u64_long_add_u64(p_lo, a, b, c) mul_u64_u64_add_u64(p_lo, a, b, c)
217 unsigned long zero = 0;224#define add_u64_long(a, b) ((a) + (b))
225#else
226#undef BITS_PER_ITER
227#define BITS_PER_ITER 16
228static inline u32 mul_u64_long_add_u64(u64 *p_lo, u64 a, u32 b, u64 c)
229{
230 u64 n_lo = mul_add(a, b, c);
231 u64 n_med = mul_add(a >> 32, b, c >> 32);
218 232
219 OPTIMIZER_HIDE_VAR(zero);233 n_med = add_u64_u32(n_med, n_lo >> 32);
220 return ~0UL/zero;234 *p_lo = n_med << 32 | (u32)n_lo;
221 }235 return n_med >> 32;
236}
237
238#define add_u64_long(a, b) add_u64_u32(a, b)
239#endif
240
241u64 mul_u64_add_u64_div_u64(u64 a, u64 b, u64 c, u64 d)
242{
243 unsigned long d_msig, q_digit;
244 unsigned int reps, d_z_hi;
245 u64 quotient, n_lo, n_hi;
246 u32 overflow;
222 247
223 int shift = __builtin_ctzll(c);248 n_hi = mul_u64_u64_add_u64(&n_lo, a, b, c);
224 249
225 /* try reducing the fraction in case the dividend becomes <= 64 bits */250 if (!n_hi)
226 if ((n_hi >> shift) == 0) {251 return div64_u64(n_lo, d);
227 u64 n = shift ? (n_lo >> shift) | (n_hi << (64 - shift)) : n_lo;
228 252
229 return div64_u64(n, c >> shift);253 if (unlikely(n_hi >= d)) {
230 /*254 /* trigger runtime exception if divisor is zero */
231 * The remainder value if needed would be:255 if (d == 0) {
232 * res = div64_u64_rem(n, c >> shift, &rem);256 unsigned long zero = 0;
233 * rem = (rem << shift) + (n_lo - (n << shift));
234 */
235 }
236 257
237 if (n_hi >= c) {258 OPTIMIZER_HIDE_VAR(zero);
259 return ~0UL/zero;
260 }
238 /* overflow: result is unrepresentable in a u64 */261 /* overflow: result is unrepresentable in a u64 */
239 return -1;262 return ~0ULL;
240 }263 }
241 264
242 /* Do the full 128 by 64 bits division */265 /* Left align the divisor, shifting the dividend to match */
243 266 d_z_hi = __builtin_clzll(d);
244 shift = __builtin_clzll(c);267 if (d_z_hi) {
245 c <<= shift;268 d <<= d_z_hi;
269 n_hi = n_hi << d_z_hi | n_lo >> (64 - d_z_hi);
270 n_lo <<= d_z_hi;
271 }
246 272
247 int p = 64 + shift;273 reps = 64 / BITS_PER_ITER;
248 u64 res = 0;274 /* Optimise loop count for small dividends */
249 bool carry;275 if (!(u32)(n_hi >> 32)) {
276 reps -= 32 / BITS_PER_ITER;
277 n_hi = n_hi << 32 | n_lo >> 32;
278 n_lo <<= 32;
279 }
280#if BITS_PER_ITER == 16
281 if (!(u32)(n_hi >> 48)) {
282 reps--;
283 n_hi = add_u64_u32(n_hi << 16, n_lo >> 48);
284 n_lo <<= 16;
285 }
286#endif
250 287
251 do {288 /* Invert the dividend so we can use add instead of subtract. */
252 carry = n_hi >> 63;289 n_lo = ~n_lo;
253 shift = carry ? 1 : __builtin_clzll(n_hi);290 n_hi = ~n_hi;
254 if (p < shift)291
255 break;292 /*
256 p -= shift;293 * Get the most significant BITS_PER_ITER bits of the divisor.
257 n_hi <<= shift;294 * This is used to get a low 'guestimate' of the quotient digit.
258 n_hi |= n_lo >> (64 - shift);295 */
259 n_lo <<= shift;296 d_msig = (d >> (64 - BITS_PER_ITER)) + 1;
260 if (carry || (n_hi >= c)) {297
261 n_hi -= c;298 /*
262 res |= 1ULL << p;299 * Now do a 'long division' with BITS_PER_ITER bit 'digits'.
300 * The 'guess' quotient digit can be low and BITS_PER_ITER+1 bits.
301 * The worst case is dividing ~0 by 0x8000 which requires two subtracts.
302 */
303 quotient = 0;
304 while (reps--) {
305 q_digit = (unsigned long)(~n_hi >> (64 - 2 * BITS_PER_ITER)) / d_msig;
306 /* Shift 'n' left to align with the product q_digit * d */
307 overflow = n_hi >> (64 - BITS_PER_ITER);
308 n_hi = add_u64_u32(n_hi << BITS_PER_ITER, n_lo >> (64 - BITS_PER_ITER));
309 n_lo <<= BITS_PER_ITER;
310 /* Add product to negated divisor */
311 overflow += mul_u64_long_add_u64(&n_hi, d, q_digit, n_hi);
312 /* Adjust for the q_digit 'guestimate' being low */
313 while (overflow < 0xffffffff >> (32 - BITS_PER_ITER)) {
314 q_digit++;
315 n_hi += d;
316 overflow += n_hi < d;
263 }317 }
264 } while (n_hi);318 quotient = add_u64_long(quotient << BITS_PER_ITER, q_digit);
265 /* The remainder value if needed would be n_hi << p */319 }
266 320
267 return res;321 /*
322 * The above only ensures the remainder doesn't overflow,
323 * it can still be possible to add (aka subtract) another copy
324 * of the divisor.
325 */
326 if ((n_hi + d) > n_hi)
327 quotient++;
328 return quotient;
268}329}
269EXPORT_SYMBOL(mul_u64_u64_div_u64);330#if !defined(test_mul_u64_add_u64_div_u64)
331EXPORT_SYMBOL(mul_u64_add_u64_div_u64);
332#endif
270#endif333#endif
lib/math/test_mul_u64_u64_div_u64.c+141−50
@@ -10,80 +10,141 @@ · 9 unmodified lines
10#include <linux/printk.h>10#include <linux/printk.h>
11#include <linux/math64.h>11#include <linux/math64.h>
12 12
13typedef struct { u64 a; u64 b; u64 c; u64 result; } test_params;13typedef struct { u64 a; u64 b; u64 d; u64 result; uint round_up;} test_params;
14 14
15static test_params test_values[] = {15static test_params test_values[] = {
16/* this contains many edge values followed by a couple random values */16/* this contains many edge values followed by a couple random values */
17{ 0xb, 0x7, 0x3, 0x19 },17{ 0xb, 0x7, 0x3, 0x19, 1 },
18{ 0xffff0000, 0xffff0000, 0xf, 0x1110eeef00000000 },18{ 0xffff0000, 0xffff0000, 0xf, 0x1110eeef00000000, 0 },
19{ 0xffffffff, 0xffffffff, 0x1, 0xfffffffe00000001 },19{ 0xffffffff, 0xffffffff, 0x1, 0xfffffffe00000001, 0 },
20{ 0xffffffff, 0xffffffff, 0x2, 0x7fffffff00000000 },20{ 0xffffffff, 0xffffffff, 0x2, 0x7fffffff00000000, 1 },
21{ 0x1ffffffff, 0xffffffff, 0x2, 0xfffffffe80000000 },21{ 0x1ffffffff, 0xffffffff, 0x2, 0xfffffffe80000000, 1 },
22{ 0x1ffffffff, 0xffffffff, 0x3, 0xaaaaaaa9aaaaaaab },22{ 0x1ffffffff, 0xffffffff, 0x3, 0xaaaaaaa9aaaaaaab, 0 },
23{ 0x1ffffffff, 0x1ffffffff, 0x4, 0xffffffff00000000 },23{ 0x1ffffffff, 0x1ffffffff, 0x4, 0xffffffff00000000, 1 },
24{ 0xffff000000000000, 0xffff000000000000, 0xffff000000000001, 0xfffeffffffffffff },24{ 0xffff000000000000, 0xffff000000000000, 0xffff000000000001, 0xfffeffffffffffff, 1 },
25{ 0x3333333333333333, 0x3333333333333333, 0x5555555555555555, 0x1eb851eb851eb851 },25{ 0x3333333333333333, 0x3333333333333333, 0x5555555555555555, 0x1eb851eb851eb851, 1 },
26{ 0x7fffffffffffffff, 0x2, 0x3, 0x5555555555555554 },26{ 0x7fffffffffffffff, 0x2, 0x3, 0x5555555555555554, 1 },
27{ 0xffffffffffffffff, 0x2, 0x8000000000000000, 0x3 },27{ 0xffffffffffffffff, 0x2, 0x8000000000000000, 0x3, 1 },
28{ 0xffffffffffffffff, 0x2, 0xc000000000000000, 0x2 },28{ 0xffffffffffffffff, 0x2, 0xc000000000000000, 0x2, 1 },
29{ 0xffffffffffffffff, 0x4000000000000004, 0x8000000000000000, 0x8000000000000007 },29{ 0xffffffffffffffff, 0x4000000000000004, 0x8000000000000000, 0x8000000000000007, 1 },
30{ 0xffffffffffffffff, 0x4000000000000001, 0x8000000000000000, 0x8000000000000001 },30{ 0xffffffffffffffff, 0x4000000000000001, 0x8000000000000000, 0x8000000000000001, 1 },
31{ 0xffffffffffffffff, 0x8000000000000001, 0xffffffffffffffff, 0x8000000000000001 },31{ 0xffffffffffffffff, 0x8000000000000001, 0xffffffffffffffff, 0x8000000000000001, 0 },
32{ 0xfffffffffffffffe, 0x8000000000000001, 0xffffffffffffffff, 0x8000000000000000 },32{ 0xfffffffffffffffe, 0x8000000000000001, 0xffffffffffffffff, 0x8000000000000000, 1 },
33{ 0xffffffffffffffff, 0x8000000000000001, 0xfffffffffffffffe, 0x8000000000000001 },33{ 0xffffffffffffffff, 0x8000000000000001, 0xfffffffffffffffe, 0x8000000000000001, 1 },
34{ 0xffffffffffffffff, 0x8000000000000001, 0xfffffffffffffffd, 0x8000000000000002 },34{ 0xffffffffffffffff, 0x8000000000000001, 0xfffffffffffffffd, 0x8000000000000002, 1 },
35{ 0x7fffffffffffffff, 0xffffffffffffffff, 0xc000000000000000, 0xaaaaaaaaaaaaaaa8 },35{ 0x7fffffffffffffff, 0xffffffffffffffff, 0xc000000000000000, 0xaaaaaaaaaaaaaaa8, 1 },
36{ 0xffffffffffffffff, 0x7fffffffffffffff, 0xa000000000000000, 0xccccccccccccccca },36{ 0xffffffffffffffff, 0x7fffffffffffffff, 0xa000000000000000, 0xccccccccccccccca, 1 },
37{ 0xffffffffffffffff, 0x7fffffffffffffff, 0x9000000000000000, 0xe38e38e38e38e38b },37{ 0xffffffffffffffff, 0x7fffffffffffffff, 0x9000000000000000, 0xe38e38e38e38e38b, 1 },
38{ 0x7fffffffffffffff, 0x7fffffffffffffff, 0x5000000000000000, 0xccccccccccccccc9 },38{ 0x7fffffffffffffff, 0x7fffffffffffffff, 0x5000000000000000, 0xccccccccccccccc9, 1 },
39{ 0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0xfffffffffffffffe },39{ 0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0xfffffffffffffffe, 0 },
40{ 0xe6102d256d7ea3ae, 0x70a77d0be4c31201, 0xd63ec35ab3220357, 0x78f8bf8cc86c6e18 },40{ 0xe6102d256d7ea3ae, 0x70a77d0be4c31201, 0xd63ec35ab3220357, 0x78f8bf8cc86c6e18, 1 },
41{ 0xf53bae05cb86c6e1, 0x3847b32d2f8d32e0, 0xcfd4f55a647f403c, 0x42687f79d8998d35 },41{ 0xf53bae05cb86c6e1, 0x3847b32d2f8d32e0, 0xcfd4f55a647f403c, 0x42687f79d8998d35, 1 },
42{ 0x9951c5498f941092, 0x1f8c8bfdf287a251, 0xa3c8dc5f81ea3fe2, 0x1d887cb25900091f },42{ 0x9951c5498f941092, 0x1f8c8bfdf287a251, 0xa3c8dc5f81ea3fe2, 0x1d887cb25900091f, 1 },
43{ 0x374fee9daa1bb2bb, 0x0d0bfbff7b8ae3ef, 0xc169337bd42d5179, 0x03bb2dbaffcbb961 },43{ 0x374fee9daa1bb2bb, 0x0d0bfbff7b8ae3ef, 0xc169337bd42d5179, 0x03bb2dbaffcbb961, 1 },
44{ 0xeac0d03ac10eeaf0, 0x89be05dfa162ed9b, 0x92bb1679a41f0e4b, 0xdc5f5cc9e270d216 },44{ 0xeac0d03ac10eeaf0, 0x89be05dfa162ed9b, 0x92bb1679a41f0e4b, 0xdc5f5cc9e270d216, 1 },
45};45};
46 46
47/*47/*
48 * The above table can be verified with the following shell script:48 * The above table can be verified with the following shell script:
49 *49
50 * #!/bin/sh50#!/bin/sh
51 * sed -ne 's/^{ \+\(.*\), \+\(.*\), \+\(.*\), \+\(.*\) },$/\1 \2 \3 \4/p' \51sed -ne 's/^{ \+\(.*\), \+\(.*\), \+\(.*\), \+\(.*\), \+\(.*\) },$/\1 \2 \3 \4 \5/p' \
52 * lib/math/test_mul_u64_u64_div_u64.c |52 lib/math/test_mul_u64_u64_div_u64.c |
53 * while read a b c r; do53while read a b d r e; do
54 * expected=$( printf "obase=16; ibase=16; %X * %X / %X\n" $a $b $c | bc )54 expected=$( printf "obase=16; ibase=16; %X * %X / %X\n" $a $b $d | bc )
55 * given=$( printf "%X\n" $r )55 given=$( printf "%X\n" $r )
56 * if [ "$expected" = "$given" ]; then56 if [ "$expected" = "$given" ]; then
57 * echo "$a * $b / $c = $r OK"57 echo "$a * $b / $d = $r OK"
58 * else58 else
59 * echo "$a * $b / $c = $r is wrong" >&259 echo "$a * $b / $d = $r is wrong" >&2
60 * echo "should be equivalent to 0x$expected" >&260 echo "should be equivalent to 0x$expected" >&2
61 * exit 161 exit 1
62 * fi62 fi
63 * done63 expected=$( printf "obase=16; ibase=16; (%X * %X + %X) / %X\n" $a $b $((d-1)) $d | bc )
64 given=$( printf "%X\n" $((r + e)) )
65 if [ "$expected" = "$given" ]; then
66 echo "$a * $b +/ $d = $(printf '%#x' $((r + e))) OK"
67 else
68 echo "$a * $b +/ $d = $(printf '%#x' $((r + e))) is wrong" >&2
69 echo "should be equivalent to 0x$expected" >&2
70 exit 1
71 fi
72done
73
64 */74 */
65 75
66static int __init test_init(void)76static u64 test_mul_u64_add_u64_div_u64(u64 a, u64 b, u64 c, u64 d);
77#if __LONG_WIDTH__ >= 64
78#define TEST_32BIT_DIV
79static u64 test_mul_u64_add_u64_div_u64_32bit(u64 a, u64 b, u64 c, u64 d);
80#endif
81
82static int __init test_run(unsigned int fn_no, const char *fn_name)
67{83{
84 u64 start_time;
85 int errors = 0;
86 int tests = 0;
68 int i;87 int i;
69 88
70 pr_info("Starting mul_u64_u64_div_u64() test\n");89 start_time = ktime_get_ns();
71 90
72 for (i = 0; i < ARRAY_SIZE(test_values); i++) {91 for (i = 0; i < ARRAY_SIZE(test_values); i++) {
73 u64 a = test_values[i].a;92 u64 a = test_values[i].a;
74 u64 b = test_values[i].b;93 u64 b = test_values[i].b;
75 u64 c = test_values[i].c;94 u64 d = test_values[i].d;
76 u64 expected_result = test_values[i].result;95 u64 expected_result = test_values[i].result;
77 u64 result = mul_u64_u64_div_u64(a, b, c);96 u64 result, result_up;
97
98 switch (fn_no) {
99 default:
100 result = mul_u64_u64_div_u64(a, b, d);
101 result_up = mul_u64_u64_div_u64_roundup(a, b, d);
102 break;
103 case 1:
104 result = test_mul_u64_add_u64_div_u64(a, b, 0, d);
105 result_up = test_mul_u64_add_u64_div_u64(a, b, d - 1, d);
106 break;
107#ifdef TEST_32BIT_DIV
108 case 2:
109 result = test_mul_u64_add_u64_div_u64_32bit(a, b, 0, d);
110 result_up = test_mul_u64_add_u64_div_u64_32bit(a, b, d - 1, d);
111 break;
112#endif
113 }
114
115 tests += 2;
78 116
79 if (result != expected_result) {117 if (result != expected_result) {
80 pr_err("ERROR: 0x%016llx * 0x%016llx / 0x%016llx\n", a, b, c);118 pr_err("ERROR: 0x%016llx * 0x%016llx / 0x%016llx\n", a, b, d);
81 pr_err("ERROR: expected result: %016llx\n", expected_result);119 pr_err("ERROR: expected result: %016llx\n", expected_result);
82 pr_err("ERROR: obtained result: %016llx\n", result);120 pr_err("ERROR: obtained result: %016llx\n", result);
121 errors++;
122 }
123 expected_result += test_values[i].round_up;
124 if (result_up != expected_result) {
125 pr_err("ERROR: 0x%016llx * 0x%016llx +/ 0x%016llx\n", a, b, d);
126 pr_err("ERROR: expected result: %016llx\n", expected_result);
127 pr_err("ERROR: obtained result: %016llx\n", result_up);
128 errors++;
83 }129 }
84 }130 }
85 131
86 pr_info("Completed mul_u64_u64_div_u64() test\n");132 pr_info("Completed %s() test, %d tests, %d errors, %llu ns\n",
133 fn_name, tests, errors, ktime_get_ns() - start_time);
134 return errors;
135}
136
137static int __init test_init(void)
138{
139 pr_info("Starting mul_u64_u64_div_u64() test\n");
140 if (test_run(0, "mul_u64_u64_div_u64"))
141 return -EINVAL;
142 if (test_run(1, "test_mul_u64_u64_div_u64"))
143 return -EINVAL;
144#ifdef TEST_32BIT_DIV
145 if (test_run(2, "test_mul_u64_u64_div_u64_32bit"))
146 return -EINVAL;
147#endif
87 return 0;148 return 0;
88}149}
89 150
@@ -91,6 +152,36 @@ static void __exit test_exit(void) · 1 unmodified line
91{152{
92}153}
93 154
155/* Compile the generic mul_u64_add_u64_div_u64() code */
156#undef __div64_32
157#define __div64_32 __div64_32
158#define div_s64_rem div_s64_rem
159#define div64_u64_rem div64_u64_rem
160#define div64_u64 div64_u64
161#define div64_s64 div64_s64
162#define iter_div_u64_rem iter_div_u64_rem
163
164#undef mul_u64_add_u64_div_u64
165#define mul_u64_add_u64_div_u64 test_mul_u64_add_u64_div_u64
166#define test_mul_u64_add_u64_div_u64 test_mul_u64_add_u64_div_u64
167
168#include "div64.c"
169
170#ifdef TEST_32BIT_DIV
171/* Recompile the generic code for 32bit long */
172#undef test_mul_u64_add_u64_div_u64
173#define test_mul_u64_add_u64_div_u64 test_mul_u64_add_u64_div_u64_32bit
174#undef BITS_PER_ITER
175#define BITS_PER_ITER 16
176
177#define mul_u64_u64_add_u64 mul_u64_u64_add_u64_32bit
178#undef mul_u64_long_add_u64
179#undef add_u64_long
180#undef mul_add
181
182#include "div64.c"
183#endif
184
94module_init(test_init);185module_init(test_init);
95module_exit(test_exit);186module_exit(test_exit);
96 187
lib/plist.c+2−2
@@ -47,8 +47,8 @@ static void plist_check_list(struct list_head *top) · 46 unmodified lines
47 47
48 plist_check_prev_next(top, prev, next);48 plist_check_prev_next(top, prev, next);
49 while (next != top) {49 while (next != top) {
50 WRITE_ONCE(prev, next);50 prev = next;
51 WRITE_ONCE(next, prev->next);51 next = prev->next;
52 plist_check_prev_next(top, prev, next);52 plist_check_prev_next(top, prev, next);
53 }53 }
54}54}
lib/ratelimit.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27int ___ratelimit(struct ratelimit_state *rs, const char *func)27int ___ratelimit(struct ratelimit_state *rs, const char *func)
28{28{
29 /* Paired with WRITE_ONCE() in .proc_handler().29 /* Paired with WRITE_ONCE() in .proc_handler().
30 * Changing two values seperately could be inconsistent30 * Changing two values separately could be inconsistent
31 * and some message could be lost. (See: net_ratelimit_state).31 * and some message could be lost. (See: net_ratelimit_state).
32 */32 */
33 int interval = READ_ONCE(rs->interval);33 int interval = READ_ONCE(rs->interval);
lib/rbtree.c+0−29
@@ -460,35 +460,6 @@ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, · 459 unmodified lines
460}460}
461EXPORT_SYMBOL(__rb_insert_augmented);461EXPORT_SYMBOL(__rb_insert_augmented);
462 462
463/*
464 * This function returns the first node (in sort order) of the tree.
465 */
466struct rb_node *rb_first(const struct rb_root *root)
467{
468 struct rb_node *n;
469
470 n = root->rb_node;
471 if (!n)
472 return NULL;
473 while (n->rb_left)
474 n = n->rb_left;
475 return n;
476}
477EXPORT_SYMBOL(rb_first);
478
479struct rb_node *rb_last(const struct rb_root *root)
480{
481 struct rb_node *n;
482
483 n = root->rb_node;
484 if (!n)
485 return NULL;
486 while (n->rb_right)
487 n = n->rb_right;
488 return n;
489}
490EXPORT_SYMBOL(rb_last);
491
492struct rb_node *rb_next(const struct rb_node *node)463struct rb_node *rb_next(const struct rb_node *node)
493{464{
494 struct rb_node *parent;465 struct rb_node *parent;
lib/sys_info.c+106−63
@@ -1,31 +1,35 @@
1// SPDX-License-Identifier: GPL-2.0-only1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/sched/debug.h>2#include <linux/array_size.h>
3#include <linux/bitops.h>
4#include <linux/cleanup.h>
3#include <linux/console.h>5#include <linux/console.h>
6#include <linux/log2.h>
4#include <linux/kernel.h>7#include <linux/kernel.h>
5#include <linux/ftrace.h>8#include <linux/ftrace.h>
6#include <linux/sysctl.h>
7#include <linux/nmi.h>9#include <linux/nmi.h>
10#include <linux/sched/debug.h>
11#include <linux/string.h>
12#include <linux/sysctl.h>
8 13
9#include <linux/sys_info.h>14#include <linux/sys_info.h>
10 15
11struct sys_info_name {16static const char * const si_names[] = {
12 unsigned long bit;17 [ilog2(SYS_INFO_TASKS)] = "tasks",
13 const char *name;18 [ilog2(SYS_INFO_MEM)] = "mem",
19 [ilog2(SYS_INFO_TIMERS)] = "timers",
20 [ilog2(SYS_INFO_LOCKS)] = "locks",
21 [ilog2(SYS_INFO_FTRACE)] = "ftrace",
22 [ilog2(SYS_INFO_PANIC_CONSOLE_REPLAY)] = "",
23 [ilog2(SYS_INFO_ALL_BT)] = "all_bt",
24 [ilog2(SYS_INFO_BLOCKED_TASKS)] = "blocked_tasks",
14};25};
15 26
16/*27/*
17 * When 'si_names' gets updated, please make sure the 'sys_info_avail'28 * Default kernel sys_info mask.
18 * below is updated accordingly.29 * If a kernel module calls sys_info() with "parameter == 0", then
30 * this mask will be used.
19 */31 */
20static const struct sys_info_name si_names[] = {32static unsigned long kernel_si_mask;
21 { SYS_INFO_TASKS, "tasks" },
22 { SYS_INFO_MEM, "mem" },
23 { SYS_INFO_TIMERS, "timers" },
24 { SYS_INFO_LOCKS, "locks" },
25 { SYS_INFO_FTRACE, "ftrace" },
26 { SYS_INFO_ALL_CPU_BT, "all_bt" },
27 { SYS_INFO_BLOCKED_TASKS, "blocked_tasks" },
28};
29 33
30/* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */34/* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */
31unsigned long sys_info_parse_param(char *str)35unsigned long sys_info_parse_param(char *str)
@@ -36,12 +40,9 @@ unsigned long sys_info_parse_param(char *str) · 4 unmodified lines
36 40
37 s = str;41 s = str;
38 while ((name = strsep(&s, ",")) && *name) {42 while ((name = strsep(&s, ",")) && *name) {
39 for (i = 0; i < ARRAY_SIZE(si_names); i++) {43 i = match_string(si_names, ARRAY_SIZE(si_names), name);
40 if (!strcmp(name, si_names[i].name)) {44 if (i >= 0)
41 si_bits |= si_names[i].bit;45 __set_bit(i, &si_bits);
42 break;
43 }
44 }
45 }46 }
46 47
47 return si_bits;48 return si_bits;
@@ -49,56 +50,93 @@ unsigned long sys_info_parse_param(char *str) · 1 unmodified line
49 50
50#ifdef CONFIG_SYSCTL51#ifdef CONFIG_SYSCTL
51 52
52static const char sys_info_avail[] __maybe_unused = "tasks,mem,timers,locks,ftrace,all_bt,blocked_tasks";53static int sys_info_write_handler(const struct ctl_table *table,
54 void *buffer, size_t *lenp, loff_t *ppos,
55 unsigned long *si_bits_global)
56{
57 unsigned long si_bits;
58 int ret;
59
60 ret = proc_dostring(table, 1, buffer, lenp, ppos);
61 if (ret)
62 return ret;
63
64 si_bits = sys_info_parse_param(table->data);
65
66 /* The access to the global value is not synchronized. */
67 WRITE_ONCE(*si_bits_global, si_bits);
68
69 return 0;
70}
71
72static int sys_info_read_handler(const struct ctl_table *table,
73 void *buffer, size_t *lenp, loff_t *ppos,
74 unsigned long *si_bits_global)
75{
76 unsigned long si_bits;
77 unsigned int len = 0;
78 char *delim = "";
79 unsigned int i;
80
81 /* The access to the global value is not synchronized. */
82 si_bits = READ_ONCE(*si_bits_global);
83
84 for_each_set_bit(i, &si_bits, ARRAY_SIZE(si_names)) {
85 if (*si_names[i]) {
86 len += scnprintf(table->data + len, table->maxlen - len,
87 "%s%s", delim, si_names[i]);
88 delim = ",";
89 }
90 }
91
92 return proc_dostring(table, 0, buffer, lenp, ppos);
93}
53 94
54int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,95int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
55 void *buffer, size_t *lenp,96 void *buffer, size_t *lenp,
56 loff_t *ppos)97 loff_t *ppos)
57{98{
58 char names[sizeof(sys_info_avail)];
59 struct ctl_table table;99 struct ctl_table table;
60 unsigned long *si_bits_global;100 unsigned int i;
61 101 size_t maxlen;
62 si_bits_global = ro_table->data;
63
64 if (write) {
65 unsigned long si_bits;
66 int ret;
67
68 table = *ro_table;
69 table.data = names;
70 table.maxlen = sizeof(names);
71 ret = proc_dostring(&table, write, buffer, lenp, ppos);
72 if (ret)
73 return ret;
74
75 si_bits = sys_info_parse_param(names);
76 /* The access to the global value is not synchronized. */
77 WRITE_ONCE(*si_bits_global, si_bits);
78 return 0;
79 } else {
80 /* for 'read' operation */
81 char *delim = "";
82 int i, len = 0;
83
84 names[0] = '\0';
85 for (i = 0; i < ARRAY_SIZE(si_names); i++) {
86 if (*si_bits_global & si_names[i].bit) {
87 len += scnprintf(names + len, sizeof(names) - len,
88 "%s%s", delim, si_names[i].name);
89 delim = ",";
90 }
91 }
92 102
93 table = *ro_table;103 maxlen = 0;
94 table.data = names;104 for (i = 0; i < ARRAY_SIZE(si_names); i++)
95 table.maxlen = sizeof(names);105 maxlen += strlen(si_names[i]) + 1;
96 return proc_dostring(&table, write, buffer, lenp, ppos);106
97 }107 char *names __free(kfree) = kzalloc(maxlen, GFP_KERNEL);
108 if (!names)
109 return -ENOMEM;
110
111 table = *ro_table;
112 table.data = names;
113 table.maxlen = maxlen;
114
115 if (write)
116 return sys_info_write_handler(&table, buffer, lenp, ppos, ro_table->data);
117 else
118 return sys_info_read_handler(&table, buffer, lenp, ppos, ro_table->data);
119}
120
121static const struct ctl_table sys_info_sysctls[] = {
122 {
123 .procname = "kernel_sys_info",
124 .data = &kernel_si_mask,
125 .maxlen = sizeof(kernel_si_mask),
126 .mode = 0644,
127 .proc_handler = sysctl_sys_info_handler,
128 },
129};
130
131static int __init sys_info_sysctl_init(void)
132{
133 register_sysctl_init("kernel", sys_info_sysctls);
134 return 0;
98}135}
136subsys_initcall(sys_info_sysctl_init);
99#endif137#endif
100 138
101void sys_info(unsigned long si_mask)139static void __sys_info(unsigned long si_mask)
102{140{
103 if (si_mask & SYS_INFO_TASKS)141 if (si_mask & SYS_INFO_TASKS)
104 show_state();142 show_state();
@@ -115,9 +153,14 @@ void sys_info(unsigned long si_mask) · 10 unmodified lines
115 if (si_mask & SYS_INFO_FTRACE)153 if (si_mask & SYS_INFO_FTRACE)
116 ftrace_dump(DUMP_ALL);154 ftrace_dump(DUMP_ALL);
117 155
118 if (si_mask & SYS_INFO_ALL_CPU_BT)156 if (si_mask & SYS_INFO_ALL_BT)
119 trigger_all_cpu_backtrace();157 trigger_all_cpu_backtrace();
120 158
121 if (si_mask & SYS_INFO_BLOCKED_TASKS)159 if (si_mask & SYS_INFO_BLOCKED_TASKS)
122 show_state_filter(TASK_UNINTERRUPTIBLE);160 show_state_filter(TASK_UNINTERRUPTIBLE);
123}161}
162
163void sys_info(unsigned long si_mask)
164{
165 __sys_info(si_mask ? : kernel_si_mask);
166}
lib/test_kho.c+80−60
@@ -33,44 +33,28 @@ struct kho_test_state { · 32 unmodified lines
33 unsigned int nr_folios;33 unsigned int nr_folios;
34 struct folio **folios;34 struct folio **folios;
35 phys_addr_t *folios_info;35 phys_addr_t *folios_info;
36 struct kho_vmalloc folios_info_phys;
37 int nr_folios_preserved;
36 struct folio *fdt;38 struct folio *fdt;
37 __wsum csum;39 __wsum csum;
38};40};
39 41
40static struct kho_test_state kho_test_state;42static struct kho_test_state kho_test_state;
41 43
42static int kho_test_notifier(struct notifier_block *self, unsigned long cmd,44static void kho_test_unpreserve_data(struct kho_test_state *state)
43 void *v)
44{45{
45 struct kho_test_state *state = &kho_test_state;46 for (int i = 0; i < state->nr_folios_preserved; i++)
46 struct kho_serialization *ser = v;47 kho_unpreserve_folio(state->folios[i]);
47 int err = 0;
48
49 switch (cmd) {
50 case KEXEC_KHO_ABORT:
51 return NOTIFY_DONE;
52 case KEXEC_KHO_FINALIZE:
53 /* Handled below */
54 break;
55 default:
56 return NOTIFY_BAD;
57 }
58
59 err |= kho_preserve_folio(state->fdt);
60 err |= kho_add_subtree(ser, KHO_TEST_FDT, folio_address(state->fdt));
61 48
62 return err ? NOTIFY_BAD : NOTIFY_DONE;49 kho_unpreserve_vmalloc(&state->folios_info_phys);
50 vfree(state->folios_info);
63}51}
64 52
65static struct notifier_block kho_test_nb = {53static int kho_test_preserve_data(struct kho_test_state *state)
66 .notifier_call = kho_test_notifier,
67};
68
69static int kho_test_save_data(struct kho_test_state *state, void *fdt)
70{54{
71 phys_addr_t *folios_info __free(kvfree) = NULL;
72 struct kho_vmalloc folios_info_phys;55 struct kho_vmalloc folios_info_phys;
73 int err = 0;56 phys_addr_t *folios_info;
57 int err;
74 58
75 folios_info = vmalloc_array(state->nr_folios, sizeof(*folios_info));59 folios_info = vmalloc_array(state->nr_folios, sizeof(*folios_info));
76 if (!folios_info)60 if (!folios_info)
@@ -78,62 +62,98 @@ static int kho_test_save_data(struct kho_test_state *state, void *fdt) · 1 unmodified line
78 62
79 err = kho_preserve_vmalloc(folios_info, &folios_info_phys);63 err = kho_preserve_vmalloc(folios_info, &folios_info_phys);
80 if (err)64 if (err)
81 return err;65 goto err_free_info;
66
67 state->folios_info_phys = folios_info_phys;
68 state->folios_info = folios_info;
82 69
83 for (int i = 0; i < state->nr_folios; i++) {70 for (int i = 0; i < state->nr_folios; i++) {
84 struct folio *folio = state->folios[i];71 struct folio *folio = state->folios[i];
85 unsigned int order = folio_order(folio);72 unsigned int order = folio_order(folio);
86 73
87 folios_info[i] = virt_to_phys(folio_address(folio)) | order;74 folios_info[i] = virt_to_phys(folio_address(folio)) | order;
88
89 err = kho_preserve_folio(folio);75 err = kho_preserve_folio(folio);
90 if (err)76 if (err)
91 break;77 goto err_unpreserve;
78 state->nr_folios_preserved++;
92 }79 }
93 80
81 return 0;
82
83err_unpreserve:
84 /*
85 * kho_test_unpreserve_data frees folio_info, bail out immediately to
86 * avoid double free
87 */
88 kho_test_unpreserve_data(state);
89 return err;
90
91err_free_info:
92 vfree(folios_info);
93 return err;
94}
95
96static int kho_test_prepare_fdt(struct kho_test_state *state, ssize_t fdt_size)
97{
98 const char compatible[] = KHO_TEST_COMPAT;
99 unsigned int magic = KHO_TEST_MAGIC;
100 void *fdt = folio_address(state->fdt);
101 int err;
102
103 err = fdt_create(fdt, fdt_size);
104 err |= fdt_finish_reservemap(fdt);
105 err |= fdt_begin_node(fdt, "");
106 err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible));
107 err |= fdt_property(fdt, "magic", &magic, sizeof(magic));
108
94 err |= fdt_begin_node(fdt, "data");109 err |= fdt_begin_node(fdt, "data");
95 err |= fdt_property(fdt, "nr_folios", &state->nr_folios,110 err |= fdt_property(fdt, "nr_folios", &state->nr_folios,
96 sizeof(state->nr_folios));111 sizeof(state->nr_folios));
97 err |= fdt_property(fdt, "folios_info", &folios_info_phys,112 err |= fdt_property(fdt, "folios_info", &state->folios_info_phys,
98 sizeof(folios_info_phys));113 sizeof(state->folios_info_phys));
99 err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum));114 err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum));
100 err |= fdt_end_node(fdt);115 err |= fdt_end_node(fdt);
101 116
102 if (!err)117 err |= fdt_end_node(fdt);
103 state->folios_info = no_free_ptr(folios_info);118 err |= fdt_finish(fdt);
104 119
105 return err;120 return err;
106}121}
107 122
108static int kho_test_prepare_fdt(struct kho_test_state *state)123static int kho_test_preserve(struct kho_test_state *state)
109{124{
110 const char compatible[] = KHO_TEST_COMPAT;
111 unsigned int magic = KHO_TEST_MAGIC;
112 ssize_t fdt_size;125 ssize_t fdt_size;
113 int err = 0;126 int err;
114 void *fdt;
115 127
116 fdt_size = state->nr_folios * sizeof(phys_addr_t) + PAGE_SIZE;128 fdt_size = state->nr_folios * sizeof(phys_addr_t) + PAGE_SIZE;
117 state->fdt = folio_alloc(GFP_KERNEL, get_order(fdt_size));129 state->fdt = folio_alloc(GFP_KERNEL, get_order(fdt_size));
118 if (!state->fdt)130 if (!state->fdt)
119 return -ENOMEM;131 return -ENOMEM;
120 132
121 fdt = folio_address(state->fdt);133 err = kho_preserve_folio(state->fdt);
122 134 if (err)
123 err |= fdt_create(fdt, fdt_size);135 goto err_free_fdt;
124 err |= fdt_finish_reservemap(fdt);
125 136
126 err |= fdt_begin_node(fdt, "");137 err = kho_test_preserve_data(state);
127 err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible));138 if (err)
128 err |= fdt_property(fdt, "magic", &magic, sizeof(magic));139 goto err_unpreserve_fdt;
129 err |= kho_test_save_data(state, fdt);
130 err |= fdt_end_node(fdt);
131 140
132 err |= fdt_finish(fdt);141 err = kho_test_prepare_fdt(state, fdt_size);
142 if (err)
143 goto err_unpreserve_data;
133 144
145 err = kho_add_subtree(KHO_TEST_FDT, folio_address(state->fdt));
134 if (err)146 if (err)
135 folio_put(state->fdt);147 goto err_unpreserve_data;
148
149 return 0;
136 150
151err_unpreserve_data:
152 kho_test_unpreserve_data(state);
153err_unpreserve_fdt:
154 kho_unpreserve_folio(state->fdt);
155err_free_fdt:
156 folio_put(state->fdt);
137 return err;157 return err;
138}158}
139 159
@@ -199,18 +219,12 @@ static int kho_test_save(void) · 59 unmodified lines
199 if (err)219 if (err)
200 goto err_free_folios;220 goto err_free_folios;
201 221
202 err = kho_test_prepare_fdt(state);222 err = kho_test_preserve(state);
203 if (err)223 if (err)
204 goto err_free_folios;224 goto err_free_folios;
205 225
206 err = register_kho_notifier(&kho_test_nb);
207 if (err)
208 goto err_free_fdt;
209
210 return 0;226 return 0;
211 227
212err_free_fdt:
213 folio_put(state->fdt);
214err_free_folios:228err_free_folios:
215 kvfree(folios);229 kvfree(folios);
216 return err;230 return err;
@@ -292,7 +306,6 @@ static int kho_test_restore(phys_addr_t fdt_phys) · 75 unmodified lines
292 if (err)306 if (err)
293 return err;307 return err;
294 308
295 pr_info("KHO restore succeeded\n");
296 return 0;309 return 0;
297}310}
298 311
@@ -305,8 +318,15 @@ static int __init kho_test_init(void) · 6 unmodified lines
305 return 0;318 return 0;
306 319
307 err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys);320 err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys);
308 if (!err)321 if (!err) {
309 return kho_test_restore(fdt_phys);322 err = kho_test_restore(fdt_phys);
323 if (err)
324 pr_err("KHO restore failed\n");
325 else
326 pr_info("KHO restore succeeded\n");
327
328 return err;
329 }
310 330
311 if (err != -ENOENT) {331 if (err != -ENOENT) {
312 pr_warn("failed to retrieve %s FDT: %d\n", KHO_TEST_FDT, err);332 pr_warn("failed to retrieve %s FDT: %d\n", KHO_TEST_FDT, err);
@@ -329,7 +349,7 @@ static void kho_test_cleanup(void) · 16 unmodified lines
329 349
330static void __exit kho_test_exit(void)350static void __exit kho_test_exit(void)
331{351{
332 unregister_kho_notifier(&kho_test_nb);352 kho_remove_subtree(folio_address(kho_test_state.fdt));
333 kho_test_cleanup();353 kho_test_cleanup();
334}354}
335module_exit(kho_test_exit);355module_exit(kho_test_exit);
lib/tests/Makefile+1−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
4 4
5# KUnit tests5# KUnit tests
6CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)6CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
7obj-$(CONFIG_BASE64_KUNIT) += base64_kunit.o
7obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o8obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
8obj-$(CONFIG_BITS_TEST) += test_bits.o9obj-$(CONFIG_BITS_TEST) += test_bits.o
9obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o10obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o
lib/tests/base64_kunit.c+294−0
@@ -0,0 +1,294 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * base64_kunit_test.c - KUnit tests for base64 encoding and decoding functions
4 *
5 * Copyright (c) 2025, Guan-Chun Wu <409411716@gms.tku.edu.tw>
6 */
7
8#include <kunit/test.h>
9#include <linux/base64.h>
10
11/* ---------- Benchmark helpers ---------- */
12static u64 bench_encode_ns(const u8 *data, int len, char *dst, int reps,
13 enum base64_variant variant)
14{
15 u64 t0, t1;
16
17 t0 = ktime_get_ns();
18 for (int i = 0; i < reps; i++)
19 base64_encode(data, len, dst, true, variant);
20 t1 = ktime_get_ns();
21
22 return div64_u64(t1 - t0, (u64)reps);
23}
24
25static u64 bench_decode_ns(const char *data, int len, u8 *dst, int reps,
26 enum base64_variant variant)
27{
28 u64 t0, t1;
29
30 t0 = ktime_get_ns();
31 for (int i = 0; i < reps; i++)
32 base64_decode(data, len, dst, true, variant);
33 t1 = ktime_get_ns();
34
35 return div64_u64(t1 - t0, (u64)reps);
36}
37
38static void run_perf_and_check(struct kunit *test, const char *label, int size,
39 enum base64_variant variant)
40{
41 const int reps = 1000;
42 size_t outlen = DIV_ROUND_UP(size, 3) * 4;
43 u8 *in = kmalloc(size, GFP_KERNEL);
44 char *enc = kmalloc(outlen, GFP_KERNEL);
45 u8 *decoded = kmalloc(size, GFP_KERNEL);
46
47 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, in);
48 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, enc);
49 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, decoded);
50
51 get_random_bytes(in, size);
52 int enc_len = base64_encode(in, size, enc, true, variant);
53 int dec_len = base64_decode(enc, enc_len, decoded, true, variant);
54
55 /* correctness sanity check */
56 KUNIT_EXPECT_EQ(test, dec_len, size);
57 KUNIT_EXPECT_MEMEQ(test, decoded, in, size);
58
59 /* benchmark encode */
60
61 u64 t1 = bench_encode_ns(in, size, enc, reps, variant);
62
63 kunit_info(test, "[%s] encode run : %lluns", label, t1);
64
65 u64 t2 = bench_decode_ns(enc, enc_len, decoded, reps, variant);
66
67 kunit_info(test, "[%s] decode run : %lluns", label, t2);
68
69 kfree(in);
70 kfree(enc);
71 kfree(decoded);
72}
73
74static void base64_performance_tests(struct kunit *test)
75{
76 /* run on STD variant only */
77 run_perf_and_check(test, "64B", 64, BASE64_STD);
78 run_perf_and_check(test, "1KB", 1024, BASE64_STD);
79}
80
81/* ---------- Helpers for encode ---------- */
82static void expect_encode_ok(struct kunit *test, const u8 *src, int srclen,
83 const char *expected, bool padding,
84 enum base64_variant variant)
85{
86 char buf[128];
87 int encoded_len = base64_encode(src, srclen, buf, padding, variant);
88
89 buf[encoded_len] = '\0';
90
91 KUNIT_EXPECT_EQ(test, encoded_len, strlen(expected));
92 KUNIT_EXPECT_STREQ(test, buf, expected);
93}
94
95/* ---------- Helpers for decode ---------- */
96static void expect_decode_ok(struct kunit *test, const char *src,
97 const u8 *expected, int expected_len, bool padding,
98 enum base64_variant variant)
99{
100 u8 buf[128];
101 int decoded_len = base64_decode(src, strlen(src), buf, padding, variant);
102
103 KUNIT_EXPECT_EQ(test, decoded_len, expected_len);
104 KUNIT_EXPECT_MEMEQ(test, buf, expected, expected_len);
105}
106
107static void expect_decode_err(struct kunit *test, const char *src,
108 int srclen, bool padding,
109 enum base64_variant variant)
110{
111 u8 buf[64];
112 int decoded_len = base64_decode(src, srclen, buf, padding, variant);
113
114 KUNIT_EXPECT_EQ(test, decoded_len, -1);
115}
116
117/* ---------- Encode Tests ---------- */
118static void base64_std_encode_tests(struct kunit *test)
119{
120 /* With padding */
121 expect_encode_ok(test, (const u8 *)"", 0, "", true, BASE64_STD);
122 expect_encode_ok(test, (const u8 *)"f", 1, "Zg==", true, BASE64_STD);
123 expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8=", true, BASE64_STD);
124 expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", true, BASE64_STD);
125 expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg==", true, BASE64_STD);
126 expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE=", true, BASE64_STD);
127 expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", true, BASE64_STD);
128
129 /* Extra cases with padding */
130 expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxkIQ==",
131 true, BASE64_STD);
132 expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26,
133 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", true, BASE64_STD);
134 expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26,
135 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", true, BASE64_STD);
136 expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv",
137 true, BASE64_STD);
138
139 /* Without padding */
140 expect_encode_ok(test, (const u8 *)"", 0, "", false, BASE64_STD);
141 expect_encode_ok(test, (const u8 *)"f", 1, "Zg", false, BASE64_STD);
142 expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8", false, BASE64_STD);
143 expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", false, BASE64_STD);
144 expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg", false, BASE64_STD);
145 expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE", false, BASE64_STD);
146 expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", false, BASE64_STD);
147
148 /* Extra cases without padding */
149 expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxkIQ",
150 false, BASE64_STD);
151 expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26,
152 "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", false, BASE64_STD);
153 expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26,
154 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", false, BASE64_STD);
155 expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv",
156 false, BASE64_STD);
157}
158
159/* ---------- Decode Tests ---------- */
160static void base64_std_decode_tests(struct kunit *test)
161{
162 /* -------- With padding --------*/
163 expect_decode_ok(test, "", (const u8 *)"", 0, true, BASE64_STD);
164 expect_decode_ok(test, "Zg==", (const u8 *)"f", 1, true, BASE64_STD);
165 expect_decode_ok(test, "Zm8=", (const u8 *)"fo", 2, true, BASE64_STD);
166 expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, true, BASE64_STD);
167 expect_decode_ok(test, "Zm9vYg==", (const u8 *)"foob", 4, true, BASE64_STD);
168 expect_decode_ok(test, "Zm9vYmE=", (const u8 *)"fooba", 5, true, BASE64_STD);
169 expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, true, BASE64_STD);
170 expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ==", (const u8 *)"Hello, world!", 13,
171 true, BASE64_STD);
172 expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=",
173 (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, true, BASE64_STD);
174 expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=",
175 (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, true, BASE64_STD);
176
177 /* Error cases */
178 expect_decode_err(test, "Zg=!", 4, true, BASE64_STD);
179 expect_decode_err(test, "Zm$=", 4, true, BASE64_STD);
180 expect_decode_err(test, "Z===", 4, true, BASE64_STD);
181 expect_decode_err(test, "Zg", 2, true, BASE64_STD);
182 expect_decode_err(test, "Zm9v====", 8, true, BASE64_STD);
183 expect_decode_err(test, "Zm==A", 5, true, BASE64_STD);
184
185 {
186 char with_nul[4] = { 'Z', 'g', '\0', '=' };
187
188 expect_decode_err(test, with_nul, 4, true, BASE64_STD);
189 }
190
191 /* -------- Without padding --------*/
192 expect_decode_ok(test, "", (const u8 *)"", 0, false, BASE64_STD);
193 expect_decode_ok(test, "Zg", (const u8 *)"f", 1, false, BASE64_STD);
194 expect_decode_ok(test, "Zm8", (const u8 *)"fo", 2, false, BASE64_STD);
195 expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, false, BASE64_STD);
196 expect_decode_ok(test, "Zm9vYg", (const u8 *)"foob", 4, false, BASE64_STD);
197 expect_decode_ok(test, "Zm9vYmE", (const u8 *)"fooba", 5, false, BASE64_STD);
198 expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, false, BASE64_STD);
199 expect_decode_ok(test, "TWFu", (const u8 *)"Man", 3, false, BASE64_STD);
200 expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ", (const u8 *)"Hello, world!", 13,
201 false, BASE64_STD);
202 expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo",
203 (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, false, BASE64_STD);
204 expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo",
205 (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, false, BASE64_STD);
206 expect_decode_ok(test, "MDEyMzQ1Njc4OSsv", (const u8 *)"0123456789+/", 12,
207 false, BASE64_STD);
208
209 /* Error cases */
210 expect_decode_err(test, "Zg=!", 4, false, BASE64_STD);
211 expect_decode_err(test, "Zm$=", 4, false, BASE64_STD);
212 expect_decode_err(test, "Z===", 4, false, BASE64_STD);
213 expect_decode_err(test, "Zg=", 3, false, BASE64_STD);
214 expect_decode_err(test, "Zm9v====", 8, false, BASE64_STD);
215 expect_decode_err(test, "Zm==v", 4, false, BASE64_STD);
216
217 {
218 char with_nul[4] = { 'Z', 'g', '\0', '=' };
219
220 expect_decode_err(test, with_nul, 4, false, BASE64_STD);
221 }
222}
223
224/* ---------- Variant tests (URLSAFE / IMAP) ---------- */
225static void base64_variant_tests(struct kunit *test)
226{
227 const u8 sample1[] = { 0x00, 0xfb, 0xff, 0x7f, 0x80 };
228 char std_buf[128], url_buf[128], imap_buf[128];
229 u8 back[128];
230 int n_std, n_url, n_imap, m;
231 int i;
232
233 n_std = base64_encode(sample1, sizeof(sample1), std_buf, false, BASE64_STD);
234 n_url = base64_encode(sample1, sizeof(sample1), url_buf, false, BASE64_URLSAFE);
235 std_buf[n_std] = '\0';
236 url_buf[n_url] = '\0';
237
238 for (i = 0; i < n_std; i++) {
239 if (std_buf[i] == '+')
240 std_buf[i] = '-';
241 else if (std_buf[i] == '/')
242 std_buf[i] = '_';
243 }
244 KUNIT_EXPECT_STREQ(test, std_buf, url_buf);
245
246 m = base64_decode(url_buf, n_url, back, false, BASE64_URLSAFE);
247 KUNIT_EXPECT_EQ(test, m, (int)sizeof(sample1));
248 KUNIT_EXPECT_MEMEQ(test, back, sample1, sizeof(sample1));
249
250 n_std = base64_encode(sample1, sizeof(sample1), std_buf, false, BASE64_STD);
251 n_imap = base64_encode(sample1, sizeof(sample1), imap_buf, false, BASE64_IMAP);
252 std_buf[n_std] = '\0';
253 imap_buf[n_imap] = '\0';
254
255 for (i = 0; i < n_std; i++)
256 if (std_buf[i] == '/')
257 std_buf[i] = ',';
258 KUNIT_EXPECT_STREQ(test, std_buf, imap_buf);
259
260 m = base64_decode(imap_buf, n_imap, back, false, BASE64_IMAP);
261 KUNIT_EXPECT_EQ(test, m, (int)sizeof(sample1));
262 KUNIT_EXPECT_MEMEQ(test, back, sample1, sizeof(sample1));
263
264 {
265 const char *bad = "Zg==";
266 u8 tmp[8];
267
268 m = base64_decode(bad, strlen(bad), tmp, false, BASE64_URLSAFE);
269 KUNIT_EXPECT_EQ(test, m, -1);
270
271 m = base64_decode(bad, strlen(bad), tmp, false, BASE64_IMAP);
272 KUNIT_EXPECT_EQ(test, m, -1);
273 }
274}
275
276/* ---------- Test registration ---------- */
277static struct kunit_case base64_test_cases[] = {
278 KUNIT_CASE(base64_performance_tests),
279 KUNIT_CASE(base64_std_encode_tests),
280 KUNIT_CASE(base64_std_decode_tests),
281 KUNIT_CASE(base64_variant_tests),
282 {}
283};
284
285static struct kunit_suite base64_test_suite = {
286 .name = "base64",
287 .test_cases = base64_test_cases,
288};
289
290kunit_test_suite(base64_test_suite);
291
292MODULE_AUTHOR("Guan-Chun Wu <409411716@gms.tku.edu.tw>");
293MODULE_DESCRIPTION("KUnit tests for Base64 encoding/decoding, including performance checks");
294MODULE_LICENSE("GPL");
lib/usercopy.c+2−2
@@ -12,7 +12,7 @@ · 11 unmodified lines
12 12
13/* out-of-line parts */13/* out-of-line parts */
14 14
15#if !defined(INLINE_COPY_FROM_USER) || defined(CONFIG_RUST)15#if !defined(INLINE_COPY_FROM_USER)
16unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n)16unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n)
17{17{
18 return _inline_copy_from_user(to, from, n);18 return _inline_copy_from_user(to, from, n);
@@ -20,7 +20,7 @@ unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n · 1 unmodified line
20EXPORT_SYMBOL(_copy_from_user);20EXPORT_SYMBOL(_copy_from_user);
21#endif21#endif
22 22
23#if !defined(INLINE_COPY_TO_USER) || defined(CONFIG_RUST)23#if !defined(INLINE_COPY_TO_USER)
24unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n)24unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n)
25{25{
26 return _inline_copy_to_user(to, from, n);26 return _inline_copy_to_user(to, from, n);
lib/xxhash.c+0−29
@@ -73,21 +73,6 @@ static const uint64_t PRIME64_3 = 1609587929392839161ULL; · 72 unmodified lines
73static const uint64_t PRIME64_4 = 9650029242287828579ULL;73static const uint64_t PRIME64_4 = 9650029242287828579ULL;
74static const uint64_t PRIME64_5 = 2870177450012600261ULL;74static const uint64_t PRIME64_5 = 2870177450012600261ULL;
75 75
76/*-**************************
77 * Utils
78 ***************************/
79void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
80{
81 memcpy(dst, src, sizeof(*dst));
82}
83EXPORT_SYMBOL(xxh32_copy_state);
84
85void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
86{
87 memcpy(dst, src, sizeof(*dst));
88}
89EXPORT_SYMBOL(xxh64_copy_state);
90
91/*-***************************76/*-***************************
92 * Simple Hash Functions77 * Simple Hash Functions
93 ****************************/78 ****************************/
@@ -239,20 +224,6 @@ EXPORT_SYMBOL(xxh64); · 145 unmodified lines
239/*-**************************************************224/*-**************************************************
240 * Advanced Hash Functions225 * Advanced Hash Functions
241 ***************************************************/226 ***************************************************/
242void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
243{
244 /* use a local state for memcpy() to avoid strict-aliasing warnings */
245 struct xxh32_state state;
246
247 memset(&state, 0, sizeof(state));
248 state.v1 = seed + PRIME32_1 + PRIME32_2;
249 state.v2 = seed + PRIME32_2;
250 state.v3 = seed + 0;
251 state.v4 = seed - PRIME32_1;
252 memcpy(statePtr, &state, sizeof(state));
253}
254EXPORT_SYMBOL(xxh32_reset);
255
256void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)227void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
257{228{
258 /* use a local state for memcpy() to avoid strict-aliasing warnings */229 /* use a local state for memcpy() to avoid strict-aliasing warnings */
lib/xz/xz_dec_bcj.c+0−95
@@ -20,7 +20,6 @@ struct xz_dec_bcj { · 19 unmodified lines
20 enum {20 enum {
21 BCJ_X86 = 4, /* x86 or x86-64 */21 BCJ_X86 = 4, /* x86 or x86-64 */
22 BCJ_POWERPC = 5, /* Big endian only */22 BCJ_POWERPC = 5, /* Big endian only */
23 BCJ_IA64 = 6, /* Big or little endian */
24 BCJ_ARM = 7, /* Little endian only */23 BCJ_ARM = 7, /* Little endian only */
25 BCJ_ARMTHUMB = 8, /* Little endian only */24 BCJ_ARMTHUMB = 8, /* Little endian only */
26 BCJ_SPARC = 9, /* Big or little endian */25 BCJ_SPARC = 9, /* Big or little endian */
@@ -180,92 +179,6 @@ static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) · 153 unmodified lines
180}179}
181#endif180#endif
182 181
183#ifdef XZ_DEC_IA64
184static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
185{
186 static const uint8_t branch_table[32] = {
187 0, 0, 0, 0, 0, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 0,
189 4, 4, 6, 6, 0, 0, 7, 7,
190 4, 4, 0, 0, 4, 4, 0, 0
191 };
192
193 /*
194 * The local variables take a little bit stack space, but it's less
195 * than what LZMA2 decoder takes, so it doesn't make sense to reduce
196 * stack usage here without doing that for the LZMA2 decoder too.
197 */
198
199 /* Loop counters */
200 size_t i;
201 size_t j;
202
203 /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
204 uint32_t slot;
205
206 /* Bitwise offset of the instruction indicated by slot */
207 uint32_t bit_pos;
208
209 /* bit_pos split into byte and bit parts */
210 uint32_t byte_pos;
211 uint32_t bit_res;
212
213 /* Address part of an instruction */
214 uint32_t addr;
215
216 /* Mask used to detect which instructions to convert */
217 uint32_t mask;
218
219 /* 41-bit instruction stored somewhere in the lowest 48 bits */
220 uint64_t instr;
221
222 /* Instruction normalized with bit_res for easier manipulation */
223 uint64_t norm;
224
225 size &= ~(size_t)15;
226
227 for (i = 0; i < size; i += 16) {
228 mask = branch_table[buf[i] & 0x1F];
229 for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
230 if (((mask >> slot) & 1) == 0)
231 continue;
232
233 byte_pos = bit_pos >> 3;
234 bit_res = bit_pos & 7;
235 instr = 0;
236 for (j = 0; j < 6; ++j)
237 instr |= (uint64_t)(buf[i + j + byte_pos])
238 << (8 * j);
239
240 norm = instr >> bit_res;
241
242 if (((norm >> 37) & 0x0F) == 0x05
243 && ((norm >> 9) & 0x07) == 0) {
244 addr = (norm >> 13) & 0x0FFFFF;
245 addr |= ((uint32_t)(norm >> 36) & 1) << 20;
246 addr <<= 4;
247 addr -= s->pos + (uint32_t)i;
248 addr >>= 4;
249
250 norm &= ~((uint64_t)0x8FFFFF << 13);
251 norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
252 norm |= (uint64_t)(addr & 0x100000)
253 << (36 - 20);
254
255 instr &= (1 << bit_res) - 1;
256 instr |= norm << bit_res;
257
258 for (j = 0; j < 6; j++)
259 buf[i + j + byte_pos]
260 = (uint8_t)(instr >> (8 * j));
261 }
262 }
263 }
264
265 return i;
266}
267#endif
268
269#ifdef XZ_DEC_ARM182#ifdef XZ_DEC_ARM
270static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)183static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
271{184{
@@ -509,11 +422,6 @@ static void bcj_apply(struct xz_dec_bcj *s, · 237 unmodified lines
509 filtered = bcj_powerpc(s, buf, size);422 filtered = bcj_powerpc(s, buf, size);
510 break;423 break;
511#endif424#endif
512#ifdef XZ_DEC_IA64
513 case BCJ_IA64:
514 filtered = bcj_ia64(s, buf, size);
515 break;
516#endif
517#ifdef XZ_DEC_ARM425#ifdef XZ_DEC_ARM
518 case BCJ_ARM:426 case BCJ_ARM:
519 filtered = bcj_arm(s, buf, size);427 filtered = bcj_arm(s, buf, size);
@@ -699,9 +607,6 @@ enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id) · 179 unmodified lines
699#ifdef XZ_DEC_POWERPC607#ifdef XZ_DEC_POWERPC
700 case BCJ_POWERPC:608 case BCJ_POWERPC:
701#endif609#endif
702#ifdef XZ_DEC_IA64
703 case BCJ_IA64:
704#endif
705#ifdef XZ_DEC_ARM610#ifdef XZ_DEC_ARM
706 case BCJ_ARM:611 case BCJ_ARM:
707#endif612#endif
lib/xz/xz_private.h+0−4
@@ -24,9 +24,6 @@ · 23 unmodified lines
24# ifdef CONFIG_XZ_DEC_POWERPC24# ifdef CONFIG_XZ_DEC_POWERPC
25# define XZ_DEC_POWERPC25# define XZ_DEC_POWERPC
26# endif26# endif
27# ifdef CONFIG_XZ_DEC_IA64
28# define XZ_DEC_IA64
29# endif
30# ifdef CONFIG_XZ_DEC_ARM27# ifdef CONFIG_XZ_DEC_ARM
31# define XZ_DEC_ARM28# define XZ_DEC_ARM
32# endif29# endif
@@ -103,7 +100,6 @@ · 70 unmodified lines
103 */100 */
104#ifndef XZ_DEC_BCJ101#ifndef XZ_DEC_BCJ
105# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \102# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
106 || defined(XZ_DEC_IA64) \
107 || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \103 || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
108 || defined(XZ_DEC_SPARC) || defined(XZ_DEC_ARM64) \104 || defined(XZ_DEC_SPARC) || defined(XZ_DEC_ARM64) \
109 || defined(XZ_DEC_RISCV)105 || defined(XZ_DEC_RISCV)
mm/Makefile+1−0
@@ -100,6 +100,7 @@ obj-$(CONFIG_NUMA) += memory-tiers.o · 99 unmodified lines
100obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o100obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o
101obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o101obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o
102obj-$(CONFIG_PAGE_COUNTER) += page_counter.o102obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
103obj-$(CONFIG_LIVEUPDATE) += memfd_luo.o
103obj-$(CONFIG_MEMCG_V1) += memcontrol-v1.o104obj-$(CONFIG_MEMCG_V1) += memcontrol-v1.o
104obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o105obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o
105ifdef CONFIG_SWAP106ifdef CONFIG_SWAP
mm/internal.h+6−0
@@ -1582,6 +1582,12 @@ void __meminit __init_page_from_nid(unsigned long pfn, int nid); · 1581 unmodified lines
1582unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg,1582unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg,
1583 int priority);1583 int priority);
1584 1584
1585int shmem_add_to_page_cache(struct folio *folio,
1586 struct address_space *mapping,
1587 pgoff_t index, void *expected, gfp_t gfp);
1588int shmem_inode_acct_blocks(struct inode *inode, long pages);
1589bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped);
1590
1585#ifdef CONFIG_SHRINKER_DEBUG1591#ifdef CONFIG_SHRINKER_DEBUG
1586static inline __printf(2, 0) int shrinker_debugfs_name_alloc(1592static inline __printf(2, 0) int shrinker_debugfs_name_alloc(
1587 struct shrinker *shrinker, const char *fmt, va_list ap)1593 struct shrinker *shrinker, const char *fmt, va_list ap)
mm/memblock.c+50−43
@@ -2445,60 +2445,59 @@ int reserve_mem_release_by_name(const char *name) · 2444 unmodified lines
2445#define MEMBLOCK_KHO_FDT "memblock"2445#define MEMBLOCK_KHO_FDT "memblock"
2446#define MEMBLOCK_KHO_NODE_COMPATIBLE "memblock-v1"2446#define MEMBLOCK_KHO_NODE_COMPATIBLE "memblock-v1"
2447#define RESERVE_MEM_KHO_NODE_COMPATIBLE "reserve-mem-v1"2447#define RESERVE_MEM_KHO_NODE_COMPATIBLE "reserve-mem-v1"
2448static struct page *kho_fdt;
2449 2448
2450static int reserve_mem_kho_finalize(struct kho_serialization *ser)2449static int __init reserved_mem_preserve(void)
2451{2450{
2452 int err = 0, i;2451 unsigned int nr_preserved = 0;
2452 int err;
2453 2453
2454 for (i = 0; i < reserved_mem_count; i++) {2454 for (unsigned int i = 0; i < reserved_mem_count; i++, nr_preserved++) {
2455 struct reserve_mem_table *map = &reserved_mem_table[i];2455 struct reserve_mem_table *map = &reserved_mem_table[i];
2456 struct page *page = phys_to_page(map->start);2456 struct page *page = phys_to_page(map->start);
2457 unsigned int nr_pages = map->size >> PAGE_SHIFT;2457 unsigned int nr_pages = map->size >> PAGE_SHIFT;
2458 2458
2459 err |= kho_preserve_pages(page, nr_pages);2459 err = kho_preserve_pages(page, nr_pages);
2460 if (err)
2461 goto err_unpreserve;
2460 }2462 }
2461 2463
2462 err |= kho_preserve_folio(page_folio(kho_fdt));2464 return 0;
2463 err |= kho_add_subtree(ser, MEMBLOCK_KHO_FDT, page_to_virt(kho_fdt));
2464 2465
2465 return notifier_from_errno(err);2466err_unpreserve:
2466}2467 for (unsigned int i = 0; i < nr_preserved; i++) {
2468 struct reserve_mem_table *map = &reserved_mem_table[i];
2469 struct page *page = phys_to_page(map->start);
2470 unsigned int nr_pages = map->size >> PAGE_SHIFT;
2467 2471
2468static int reserve_mem_kho_notifier(struct notifier_block *self,2472 kho_unpreserve_pages(page, nr_pages);
2469 unsigned long cmd, void *v)
2470{
2471 switch (cmd) {
2472 case KEXEC_KHO_FINALIZE:
2473 return reserve_mem_kho_finalize((struct kho_serialization *)v);
2474 case KEXEC_KHO_ABORT:
2475 return NOTIFY_DONE;
2476 default:
2477 return NOTIFY_BAD;
2478 }2473 }
2479}
2480 2474
2481static struct notifier_block reserve_mem_kho_nb = {2475 return err;
2482 .notifier_call = reserve_mem_kho_notifier,2476}
2483};
2484 2477
2485static int __init prepare_kho_fdt(void)2478static int __init prepare_kho_fdt(void)
2486{2479{
2487 int err = 0, i;2480 struct page *fdt_page;
2488 void *fdt;2481 void *fdt;
2482 int err;
2489 2483
2490 kho_fdt = alloc_page(GFP_KERNEL);2484 fdt_page = alloc_page(GFP_KERNEL);
2491 if (!kho_fdt)2485 if (!fdt_page) {
2492 return -ENOMEM;2486 err = -ENOMEM;
2487 goto err_report;
2488 }
2493 2489
2494 fdt = page_to_virt(kho_fdt);2490 fdt = page_to_virt(fdt_page);
2491 err = kho_preserve_pages(fdt_page, 1);
2492 if (err)
2493 goto err_free_fdt;
2495 2494
2496 err |= fdt_create(fdt, PAGE_SIZE);2495 err |= fdt_create(fdt, PAGE_SIZE);
2497 err |= fdt_finish_reservemap(fdt);2496 err |= fdt_finish_reservemap(fdt);
2498
2499 err |= fdt_begin_node(fdt, "");2497 err |= fdt_begin_node(fdt, "");
2500 err |= fdt_property_string(fdt, "compatible", MEMBLOCK_KHO_NODE_COMPATIBLE);2498 err |= fdt_property_string(fdt, "compatible", MEMBLOCK_KHO_NODE_COMPATIBLE);
2501 for (i = 0; i < reserved_mem_count; i++) {2499
2500 for (unsigned int i = 0; !err && i < reserved_mem_count; i++) {
2502 struct reserve_mem_table *map = &reserved_mem_table[i];2501 struct reserve_mem_table *map = &reserved_mem_table[i];
2503 2502
2504 err |= fdt_begin_node(fdt, map->name);2503 err |= fdt_begin_node(fdt, map->name);
@@ -2508,14 +2507,29 @@ static int __init prepare_kho_fdt(void) · 3 unmodified lines
2508 err |= fdt_end_node(fdt);2507 err |= fdt_end_node(fdt);
2509 }2508 }
2510 err |= fdt_end_node(fdt);2509 err |= fdt_end_node(fdt);
2511
2512 err |= fdt_finish(fdt);2510 err |= fdt_finish(fdt);
2513 2511
2514 if (err) {2512 if (err)
2515 pr_err("failed to prepare memblock FDT for KHO: %d\n", err);2513 goto err_unpreserve_fdt;
2516 put_page(kho_fdt);2514
2517 kho_fdt = NULL;2515 err = kho_add_subtree(MEMBLOCK_KHO_FDT, fdt);
2518 }2516 if (err)
2517 goto err_unpreserve_fdt;
2518
2519 err = reserved_mem_preserve();
2520 if (err)
2521 goto err_remove_subtree;
2522
2523 return 0;
2524
2525err_remove_subtree:
2526 kho_remove_subtree(fdt);
2527err_unpreserve_fdt:
2528 kho_unpreserve_pages(fdt_page, 1);
2529err_free_fdt:
2530 put_page(fdt_page);
2531err_report:
2532 pr_err("failed to prepare memblock FDT for KHO: %d\n", err);
2519 2533
2520 return err;2534 return err;
2521}2535}
@@ -2530,13 +2544,6 @@ static int __init reserve_mem_init(void) · 8 unmodified lines
2530 err = prepare_kho_fdt();2544 err = prepare_kho_fdt();
2531 if (err)2545 if (err)
2532 return err;2546 return err;
2533
2534 err = register_kho_notifier(&reserve_mem_kho_nb);
2535 if (err) {
2536 put_page(kho_fdt);
2537 kho_fdt = NULL;
2538 }
2539
2540 return err;2547 return err;
2541}2548}
2542late_initcall(reserve_mem_init);2549late_initcall(reserve_mem_init);
mm/memfd_luo.c+516−0
@@ -0,0 +1,516 @@
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 *
7 * Copyright (C) 2025 Amazon.com Inc. or its affiliates.
8 * Pratyush Yadav <ptyadav@amazon.de>
9 */
10
11/**
12 * DOC: Memfd Preservation via LUO
13 *
14 * Overview
15 * ========
16 *
17 * Memory file descriptors (memfd) can be preserved over a kexec using the Live
18 * Update Orchestrator (LUO) file preservation. This allows userspace to
19 * transfer its memory contents to the next kernel after a kexec.
20 *
21 * The preservation is not intended to be transparent. Only select properties of
22 * the file are preserved. All others are reset to default. The preserved
23 * properties are described below.
24 *
25 * .. note::
26 * The LUO API is not stabilized yet, so the preserved properties of a memfd
27 * are also not stable and are subject to backwards incompatible changes.
28 *
29 * .. note::
30 * Currently a memfd backed by Hugetlb is not supported. Memfds created
31 * with ``MFD_HUGETLB`` will be rejected.
32 *
33 * Preserved Properties
34 * ====================
35 *
36 * The following properties of the memfd are preserved across kexec:
37 *
38 * File Contents
39 * All data stored in the file is preserved.
40 *
41 * File Size
42 * The size of the file is preserved. Holes in the file are filled by
43 * allocating pages for them during preservation.
44 *
45 * File Position
46 * The current file position is preserved, allowing applications to continue
47 * reading/writing from their last position.
48 *
49 * File Status Flags
50 * memfds are always opened with ``O_RDWR`` and ``O_LARGEFILE``. This property
51 * is maintained.
52 *
53 * Non-Preserved Properties
54 * ========================
55 *
56 * All properties which are not preserved must be assumed to be reset to
57 * default. This section describes some of those properties which may be more of
58 * note.
59 *
60 * ``FD_CLOEXEC`` flag
61 * A memfd can be created with the ``MFD_CLOEXEC`` flag that sets the
62 * ``FD_CLOEXEC`` on the file. This flag is not preserved and must be set
63 * again after restore via ``fcntl()``.
64 *
65 * Seals
66 * File seals are not preserved. The file is unsealed on restore and if
67 * needed, must be sealed again via ``fcntl()``.
68 */
69
70#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
71
72#include <linux/bits.h>
73#include <linux/err.h>
74#include <linux/file.h>
75#include <linux/io.h>
76#include <linux/kexec_handover.h>
77#include <linux/kho/abi/memfd.h>
78#include <linux/liveupdate.h>
79#include <linux/shmem_fs.h>
80#include <linux/vmalloc.h>
81#include "internal.h"
82
83static int memfd_luo_preserve_folios(struct file *file,
84 struct kho_vmalloc *kho_vmalloc,
85 struct memfd_luo_folio_ser **out_folios_ser,
86 u64 *nr_foliosp)
87{
88 struct inode *inode = file_inode(file);
89 struct memfd_luo_folio_ser *folios_ser;
90 unsigned int max_folios;
91 long i, size, nr_pinned;
92 struct folio **folios;
93 int err = -EINVAL;
94 pgoff_t offset;
95 u64 nr_folios;
96
97 size = i_size_read(inode);
98 /*
99 * If the file has zero size, then the folios and nr_folios properties
100 * are not set.
101 */
102 if (!size) {
103 *nr_foliosp = 0;
104 *out_folios_ser = NULL;
105 memset(kho_vmalloc, 0, sizeof(*kho_vmalloc));
106 return 0;
107 }
108
109 /*
110 * Guess the number of folios based on inode size. Real number might end
111 * up being smaller if there are higher order folios.
112 */
113 max_folios = PAGE_ALIGN(size) / PAGE_SIZE;
114 folios = kvmalloc_array(max_folios, sizeof(*folios), GFP_KERNEL);
115 if (!folios)
116 return -ENOMEM;
117
118 /*
119 * Pin the folios so they don't move around behind our back. This also
120 * ensures none of the folios are in CMA -- which ensures they don't
121 * fall in KHO scratch memory. It also moves swapped out folios back to
122 * memory.
123 *
124 * A side effect of doing this is that it allocates a folio for all
125 * indices in the file. This might waste memory on sparse memfds. If
126 * that is really a problem in the future, we can have a
127 * memfd_pin_folios() variant that does not allocate a page on empty
128 * slots.
129 */
130 nr_pinned = memfd_pin_folios(file, 0, size - 1, folios, max_folios,
131 &offset);
132 if (nr_pinned < 0) {
133 err = nr_pinned;
134 pr_err("failed to pin folios: %d\n", err);
135 goto err_free_folios;
136 }
137 nr_folios = nr_pinned;
138
139 folios_ser = vcalloc(nr_folios, sizeof(*folios_ser));
140 if (!folios_ser) {
141 err = -ENOMEM;
142 goto err_unpin;
143 }
144
145 for (i = 0; i < nr_folios; i++) {
146 struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
147 struct folio *folio = folios[i];
148 unsigned int flags = 0;
149
150 err = kho_preserve_folio(folio);
151 if (err)
152 goto err_unpreserve;
153
154 if (folio_test_dirty(folio))
155 flags |= MEMFD_LUO_FOLIO_DIRTY;
156 if (folio_test_uptodate(folio))
157 flags |= MEMFD_LUO_FOLIO_UPTODATE;
158
159 pfolio->pfn = folio_pfn(folio);
160 pfolio->flags = flags;
161 pfolio->index = folio->index;
162 }
163
164 err = kho_preserve_vmalloc(folios_ser, kho_vmalloc);
165 if (err)
166 goto err_unpreserve;
167
168 kvfree(folios);
169 *nr_foliosp = nr_folios;
170 *out_folios_ser = folios_ser;
171
172 /*
173 * Note: folios_ser is purposely not freed here. It is preserved
174 * memory (via KHO). In the 'unpreserve' path, we use the vmap pointer
175 * that is passed via private_data.
176 */
177 return 0;
178
179err_unpreserve:
180 for (i = i - 1; i >= 0; i--)
181 kho_unpreserve_folio(folios[i]);
182 vfree(folios_ser);
183err_unpin:
184 unpin_folios(folios, nr_folios);
185err_free_folios:
186 kvfree(folios);
187
188 return err;
189}
190
191static void memfd_luo_unpreserve_folios(struct kho_vmalloc *kho_vmalloc,
192 struct memfd_luo_folio_ser *folios_ser,
193 u64 nr_folios)
194{
195 long i;
196
197 if (!nr_folios)
198 return;
199
200 kho_unpreserve_vmalloc(kho_vmalloc);
201
202 for (i = 0; i < nr_folios; i++) {
203 const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
204 struct folio *folio;
205
206 if (!pfolio->pfn)
207 continue;
208
209 folio = pfn_folio(pfolio->pfn);
210
211 kho_unpreserve_folio(folio);
212 unpin_folio(folio);
213 }
214
215 vfree(folios_ser);
216}
217
218static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
219{
220 struct inode *inode = file_inode(args->file);
221 struct memfd_luo_folio_ser *folios_ser;
222 struct memfd_luo_ser *ser;
223 u64 nr_folios;
224 int err = 0;
225
226 inode_lock(inode);
227 shmem_freeze(inode, true);
228
229 /* Allocate the main serialization structure in preserved memory */
230 ser = kho_alloc_preserve(sizeof(*ser));
231 if (IS_ERR(ser)) {
232 err = PTR_ERR(ser);
233 goto err_unlock;
234 }
235
236 ser->pos = args->file->f_pos;
237 ser->size = i_size_read(inode);
238
239 err = memfd_luo_preserve_folios(args->file, &ser->folios,
240 &folios_ser, &nr_folios);
241 if (err)
242 goto err_free_ser;
243
244 ser->nr_folios = nr_folios;
245 inode_unlock(inode);
246
247 args->private_data = folios_ser;
248 args->serialized_data = virt_to_phys(ser);
249
250 return 0;
251
252err_free_ser:
253 kho_unpreserve_free(ser);
254err_unlock:
255 shmem_freeze(inode, false);
256 inode_unlock(inode);
257 return err;
258}
259
260static int memfd_luo_freeze(struct liveupdate_file_op_args *args)
261{
262 struct memfd_luo_ser *ser;
263
264 if (WARN_ON_ONCE(!args->serialized_data))
265 return -EINVAL;
266
267 ser = phys_to_virt(args->serialized_data);
268
269 /*
270 * The pos might have changed since prepare. Everything else stays the
271 * same.
272 */
273 ser->pos = args->file->f_pos;
274
275 return 0;
276}
277
278static void memfd_luo_unpreserve(struct liveupdate_file_op_args *args)
279{
280 struct inode *inode = file_inode(args->file);
281 struct memfd_luo_ser *ser;
282
283 if (WARN_ON_ONCE(!args->serialized_data))
284 return;
285
286 inode_lock(inode);
287 shmem_freeze(inode, false);
288
289 ser = phys_to_virt(args->serialized_data);
290
291 memfd_luo_unpreserve_folios(&ser->folios, args->private_data,
292 ser->nr_folios);
293
294 kho_unpreserve_free(ser);
295 inode_unlock(inode);
296}
297
298static void memfd_luo_discard_folios(const struct memfd_luo_folio_ser *folios_ser,
299 u64 nr_folios)
300{
301 u64 i;
302
303 for (i = 0; i < nr_folios; i++) {
304 const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
305 struct folio *folio;
306 phys_addr_t phys;
307
308 if (!pfolio->pfn)
309 continue;
310
311 phys = PFN_PHYS(pfolio->pfn);
312 folio = kho_restore_folio(phys);
313 if (!folio) {
314 pr_warn_ratelimited("Unable to restore folio at physical address: %llx\n",
315 phys);
316 continue;
317 }
318
319 folio_put(folio);
320 }
321}
322
323static void memfd_luo_finish(struct liveupdate_file_op_args *args)
324{
325 struct memfd_luo_folio_ser *folios_ser;
326 struct memfd_luo_ser *ser;
327
328 if (args->retrieved)
329 return;
330
331 ser = phys_to_virt(args->serialized_data);
332 if (!ser)
333 return;
334
335 if (ser->nr_folios) {
336 folios_ser = kho_restore_vmalloc(&ser->folios);
337 if (!folios_ser)
338 goto out;
339
340 memfd_luo_discard_folios(folios_ser, ser->nr_folios);
341 vfree(folios_ser);
342 }
343
344out:
345 kho_restore_free(ser);
346}
347
348static int memfd_luo_retrieve_folios(struct file *file,
349 struct memfd_luo_folio_ser *folios_ser,
350 u64 nr_folios)
351{
352 struct inode *inode = file_inode(file);
353 struct address_space *mapping = inode->i_mapping;
354 struct folio *folio;
355 int err = -EIO;
356 long i;
357
358 for (i = 0; i < nr_folios; i++) {
359 const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
360 phys_addr_t phys;
361 u64 index;
362 int flags;
363
364 if (!pfolio->pfn)
365 continue;
366
367 phys = PFN_PHYS(pfolio->pfn);
368 folio = kho_restore_folio(phys);
369 if (!folio) {
370 pr_err("Unable to restore folio at physical address: %llx\n",
371 phys);
372 goto put_folios;
373 }
374 index = pfolio->index;
375 flags = pfolio->flags;
376
377 /* Set up the folio for insertion. */
378 __folio_set_locked(folio);
379 __folio_set_swapbacked(folio);
380
381 err = mem_cgroup_charge(folio, NULL, mapping_gfp_mask(mapping));
382 if (err) {
383 pr_err("shmem: failed to charge folio index %ld: %d\n",
384 i, err);
385 goto unlock_folio;
386 }
387
388 err = shmem_add_to_page_cache(folio, mapping, index, NULL,
389 mapping_gfp_mask(mapping));
390 if (err) {
391 pr_err("shmem: failed to add to page cache folio index %ld: %d\n",
392 i, err);
393 goto unlock_folio;
394 }
395
396 if (flags & MEMFD_LUO_FOLIO_UPTODATE)
397 folio_mark_uptodate(folio);
398 if (flags & MEMFD_LUO_FOLIO_DIRTY)
399 folio_mark_dirty(folio);
400
401 err = shmem_inode_acct_blocks(inode, 1);
402 if (err) {
403 pr_err("shmem: failed to account folio index %ld: %d\n",
404 i, err);
405 goto unlock_folio;
406 }
407
408 shmem_recalc_inode(inode, 1, 0);
409 folio_add_lru(folio);
410 folio_unlock(folio);
411 folio_put(folio);
412 }
413
414 return 0;
415
416unlock_folio:
417 folio_unlock(folio);
418 folio_put(folio);
419put_folios:
420 /*
421 * Note: don't free the folios already added to the file. They will be
422 * freed when the file is freed. Free the ones not added yet here.
423 */
424 for (long j = i + 1; j < nr_folios; j++) {
425 const struct memfd_luo_folio_ser *pfolio = &folios_ser[j];
426
427 folio = kho_restore_folio(pfolio->pfn);
428 if (folio)
429 folio_put(folio);
430 }
431
432 return err;
433}
434
435static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
436{
437 struct memfd_luo_folio_ser *folios_ser;
438 struct memfd_luo_ser *ser;
439 struct file *file;
440 int err;
441
442 ser = phys_to_virt(args->serialized_data);
443 if (!ser)
444 return -EINVAL;
445
446 file = shmem_file_setup("", 0, VM_NORESERVE);
447
448 if (IS_ERR(file)) {
449 pr_err("failed to setup file: %pe\n", file);
450 return PTR_ERR(file);
451 }
452
453 vfs_setpos(file, ser->pos, MAX_LFS_FILESIZE);
454 file->f_inode->i_size = ser->size;
455
456 if (ser->nr_folios) {
457 folios_ser = kho_restore_vmalloc(&ser->folios);
458 if (!folios_ser) {
459 err = -EINVAL;
460 goto put_file;
461 }
462
463 err = memfd_luo_retrieve_folios(file, folios_ser, ser->nr_folios);
464 vfree(folios_ser);
465 if (err)
466 goto put_file;
467 }
468
469 args->file = file;
470 kho_restore_free(ser);
471
472 return 0;
473
474put_file:
475 fput(file);
476
477 return err;
478}
479
480static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
481 struct file *file)
482{
483 struct inode *inode = file_inode(file);
484
485 return shmem_file(file) && !inode->i_nlink;
486}
487
488static const struct liveupdate_file_ops memfd_luo_file_ops = {
489 .freeze = memfd_luo_freeze,
490 .finish = memfd_luo_finish,
491 .retrieve = memfd_luo_retrieve,
492 .preserve = memfd_luo_preserve,
493 .unpreserve = memfd_luo_unpreserve,
494 .can_preserve = memfd_luo_can_preserve,
495 .owner = THIS_MODULE,
496};
497
498static struct liveupdate_file_handler memfd_luo_handler = {
499 .ops = &memfd_luo_file_ops,
500 .compatible = MEMFD_LUO_FH_COMPATIBLE,
501};
502
503static int __init memfd_luo_init(void)
504{
505 int err = liveupdate_register_file_handler(&memfd_luo_handler);
506
507 if (err && err != -EOPNOTSUPP) {
508 pr_err("Could not register luo filesystem handler: %pe\n",
509 ERR_PTR(err));
510
511 return err;
512 }
513
514 return 0;
515}
516late_initcall(memfd_luo_init);
mm/shmem.c+31−18
@@ -174,20 +174,20 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) · 173 unmodified lines
174 */174 */
175static inline int shmem_acct_size(unsigned long flags, loff_t size)175static inline int shmem_acct_size(unsigned long flags, loff_t size)
176{176{
177 return (flags & VM_NORESERVE) ?177 return (flags & SHMEM_F_NORESERVE) ?
178 0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size));178 0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size));
179}179}
180 180
181static inline void shmem_unacct_size(unsigned long flags, loff_t size)181static inline void shmem_unacct_size(unsigned long flags, loff_t size)
182{182{
183 if (!(flags & VM_NORESERVE))183 if (!(flags & SHMEM_F_NORESERVE))
184 vm_unacct_memory(VM_ACCT(size));184 vm_unacct_memory(VM_ACCT(size));
185}185}
186 186
187static inline int shmem_reacct_size(unsigned long flags,187static inline int shmem_reacct_size(unsigned long flags,
188 loff_t oldsize, loff_t newsize)188 loff_t oldsize, loff_t newsize)
189{189{
190 if (!(flags & VM_NORESERVE)) {190 if (!(flags & SHMEM_F_NORESERVE)) {
191 if (VM_ACCT(newsize) > VM_ACCT(oldsize))191 if (VM_ACCT(newsize) > VM_ACCT(oldsize))
192 return security_vm_enough_memory_mm(current->mm,192 return security_vm_enough_memory_mm(current->mm,
193 VM_ACCT(newsize) - VM_ACCT(oldsize));193 VM_ACCT(newsize) - VM_ACCT(oldsize));
@@ -205,7 +205,7 @@ static inline int shmem_reacct_size(unsigned long flags, · 11 unmodified lines
205 */205 */
206static inline int shmem_acct_blocks(unsigned long flags, long pages)206static inline int shmem_acct_blocks(unsigned long flags, long pages)
207{207{
208 if (!(flags & VM_NORESERVE))208 if (!(flags & SHMEM_F_NORESERVE))
209 return 0;209 return 0;
210 210
211 return security_vm_enough_memory_mm(current->mm,211 return security_vm_enough_memory_mm(current->mm,
@@ -214,11 +214,11 @@ static inline int shmem_acct_blocks(unsigned long flags, long pages) · 2 unmodified lines
214 214
215static inline void shmem_unacct_blocks(unsigned long flags, long pages)215static inline void shmem_unacct_blocks(unsigned long flags, long pages)
216{216{
217 if (flags & VM_NORESERVE)217 if (flags & SHMEM_F_NORESERVE)
218 vm_unacct_memory(pages * VM_ACCT(PAGE_SIZE));218 vm_unacct_memory(pages * VM_ACCT(PAGE_SIZE));
219}219}
220 220
221static int shmem_inode_acct_blocks(struct inode *inode, long pages)221int shmem_inode_acct_blocks(struct inode *inode, long pages)
222{222{
223 struct shmem_inode_info *info = SHMEM_I(inode);223 struct shmem_inode_info *info = SHMEM_I(inode);
224 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);224 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
@@ -434,7 +434,7 @@ static void shmem_free_inode(struct super_block *sb, size_t freed_ispace) · 209 unmodified lines
434 *434 *
435 * Return: true if swapped was incremented from 0, for shmem_writeout().435 * Return: true if swapped was incremented from 0, for shmem_writeout().
436 */436 */
437static bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped)437bool shmem_recalc_inode(struct inode *inode, long alloced, long swapped)
438{438{
439 struct shmem_inode_info *info = SHMEM_I(inode);439 struct shmem_inode_info *info = SHMEM_I(inode);
440 bool first_swapped = false;440 bool first_swapped = false;
@@ -878,9 +878,9 @@ static void shmem_update_stats(struct folio *folio, int nr_pages) · 437 unmodified lines
878/*878/*
879 * Somewhat like filemap_add_folio, but error if expected item has gone.879 * Somewhat like filemap_add_folio, but error if expected item has gone.
880 */880 */
881static int shmem_add_to_page_cache(struct folio *folio,881int shmem_add_to_page_cache(struct folio *folio,
882 struct address_space *mapping,882 struct address_space *mapping,
883 pgoff_t index, void *expected, gfp_t gfp)883 pgoff_t index, void *expected, gfp_t gfp)
884{884{
885 XA_STATE_ORDER(xas, &mapping->i_pages, index, folio_order(folio));885 XA_STATE_ORDER(xas, &mapping->i_pages, index, folio_order(folio));
886 unsigned long nr = folio_nr_pages(folio);886 unsigned long nr = folio_nr_pages(folio);
@@ -1314,6 +1314,8 @@ static int shmem_setattr(struct mnt_idmap *idmap, · 427 unmodified lines
1314 return -EPERM;1314 return -EPERM;
1315 1315
1316 if (newsize != oldsize) {1316 if (newsize != oldsize) {
1317 if (info->flags & SHMEM_F_MAPPING_FROZEN)
1318 return -EPERM;
1317 error = shmem_reacct_size(SHMEM_I(inode)->flags,1319 error = shmem_reacct_size(SHMEM_I(inode)->flags,
1318 oldsize, newsize);1320 oldsize, newsize);
1319 if (error)1321 if (error)
@@ -1568,7 +1570,7 @@ int shmem_writeout(struct folio *folio, struct swap_iocb **plug, · 248 unmodified lines
1568 int nr_pages;1570 int nr_pages;
1569 bool split = false;1571 bool split = false;
1570 1572
1571 if ((info->flags & VM_LOCKED) || sbinfo->noswap)1573 if ((info->flags & SHMEM_F_LOCKED) || sbinfo->noswap)
1572 goto redirty;1574 goto redirty;
1573 1575
1574 if (!total_swap_pages)1576 if (!total_swap_pages)
@@ -2926,15 +2928,15 @@ int shmem_lock(struct file *file, int lock, struct ucounts *ucounts) · 1351 unmodified lines
2926 * ipc_lock_object() when called from shmctl_do_lock(),2928 * ipc_lock_object() when called from shmctl_do_lock(),
2927 * no serialization needed when called from shm_destroy().2929 * no serialization needed when called from shm_destroy().
2928 */2930 */
2929 if (lock && !(info->flags & VM_LOCKED)) {2931 if (lock && !(info->flags & SHMEM_F_LOCKED)) {
2930 if (!user_shm_lock(inode->i_size, ucounts))2932 if (!user_shm_lock(inode->i_size, ucounts))
2931 goto out_nomem;2933 goto out_nomem;
2932 info->flags |= VM_LOCKED;2934 info->flags |= SHMEM_F_LOCKED;
2933 mapping_set_unevictable(file->f_mapping);2935 mapping_set_unevictable(file->f_mapping);
2934 }2936 }
2935 if (!lock && (info->flags & VM_LOCKED) && ucounts) {2937 if (!lock && (info->flags & SHMEM_F_LOCKED) && ucounts) {
2936 user_shm_unlock(inode->i_size, ucounts);2938 user_shm_unlock(inode->i_size, ucounts);
2937 info->flags &= ~VM_LOCKED;2939 info->flags &= ~SHMEM_F_LOCKED;
2938 mapping_clear_unevictable(file->f_mapping);2940 mapping_clear_unevictable(file->f_mapping);
2939 }2941 }
2940 retval = 0;2942 retval = 0;
@@ -3079,7 +3081,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap, · 138 unmodified lines
3079 spin_lock_init(&info->lock);3081 spin_lock_init(&info->lock);
3080 atomic_set(&info->stop_eviction, 0);3082 atomic_set(&info->stop_eviction, 0);
3081 info->seals = F_SEAL_SEAL;3083 info->seals = F_SEAL_SEAL;
3082 info->flags = flags & VM_NORESERVE;3084 info->flags = (flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
3083 info->i_crtime = inode_get_mtime(inode);3085 info->i_crtime = inode_get_mtime(inode);
3084 info->fsflags = (dir == NULL) ? 0 :3086 info->fsflags = (dir == NULL) ? 0 :
3085 SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;3087 SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
@@ -3306,6 +3308,10 @@ shmem_write_begin(const struct kiocb *iocb, struct address_space *mapping, · 220 unmodified lines
3306 return -EPERM;3308 return -EPERM;
3307 }3309 }
3308 3310
3311 if (unlikely((info->flags & SHMEM_F_MAPPING_FROZEN) &&
3312 pos + len > inode->i_size))
3313 return -EPERM;
3314
3309 ret = shmem_get_folio(inode, index, pos + len, &folio, SGP_WRITE);3315 ret = shmem_get_folio(inode, index, pos + len, &folio, SGP_WRITE);
3310 if (ret)3316 if (ret)
3311 return ret;3317 return ret;
@@ -3679,6 +3685,11 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, · 367 unmodified lines
3679 3685
3680 inode_lock(inode);3686 inode_lock(inode);
3681 3687
3688 if (info->flags & SHMEM_F_MAPPING_FROZEN) {
3689 error = -EPERM;
3690 goto out;
3691 }
3692
3682 if (mode & FALLOC_FL_PUNCH_HOLE) {3693 if (mode & FALLOC_FL_PUNCH_HOLE) {
3683 struct address_space *mapping = file->f_mapping;3694 struct address_space *mapping = file->f_mapping;
3684 loff_t unmap_start = round_up(offset, PAGE_SIZE);3695 loff_t unmap_start = round_up(offset, PAGE_SIZE);
@@ -5799,8 +5810,10 @@ static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap, · 2114 unmodified lines
5799/* common code */5810/* common code */
5800 5811
5801static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,5812static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
5802 loff_t size, unsigned long flags, unsigned int i_flags)5813 loff_t size, unsigned long vm_flags,
5814 unsigned int i_flags)
5803{5815{
5816 unsigned long flags = (vm_flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
5804 struct inode *inode;5817 struct inode *inode;
5805 struct file *res;5818 struct file *res;
5806 5819
@@ -5817,7 +5830,7 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name, · 10 unmodified lines
5817 return ERR_PTR(-ENOMEM);5830 return ERR_PTR(-ENOMEM);
5818 5831
5819 inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,5832 inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
5820 S_IFREG | S_IRWXUGO, 0, flags);5833 S_IFREG | S_IRWXUGO, 0, vm_flags);
5821 if (IS_ERR(inode)) {5834 if (IS_ERR(inode)) {
5822 shmem_unacct_size(flags, size);5835 shmem_unacct_size(flags, size);
5823 return ERR_CAST(inode);5836 return ERR_CAST(inode);
rust/helpers/rbtree.c+10−0
@@ -7,3 +7,13 @@ void rust_helper_rb_link_node(struct rb_node *node, struct rb_node *parent, · 6 unmodified lines
7{7{
8 rb_link_node(node, parent, rb_link);8 rb_link_node(node, parent, rb_link);
9}9}
10
11struct rb_node *rust_helper_rb_first(const struct rb_root *root)
12{
13 return rb_first(root);
14}
15
16struct rb_node *rust_helper_rb_last(const struct rb_root *root)
17{
18 return rb_last(root);
19}
rust/helpers/uaccess.c+12−0
@@ -13,3 +13,15 @@ unsigned long rust_helper_copy_to_user(void __user *to, const void *from, · 12 unmodified lines
13{13{
14 return copy_to_user(to, from, n);14 return copy_to_user(to, from, n);
15}15}
16
17#ifdef INLINE_COPY_FROM_USER
18unsigned long rust_helper__copy_from_user(void *to, const void __user *from, unsigned long n)
19{
20 return _inline_copy_from_user(to, from, n);
21}
22
23unsigned long rust_helper__copy_to_user(void __user *to, const void *from, unsigned long n)
24{
25 return _inline_copy_to_user(to, from, n);
26}
27#endif
samples/Kconfig+11−11
@@ -23,11 +23,11 @@ config SAMPLE_TRACE_CUSTOM_EVENTS · 22 unmodified lines
23 This builds the custom trace event example module.23 This builds the custom trace event example module.
24 24
25config SAMPLE_TRACE_PRINTK25config SAMPLE_TRACE_PRINTK
26 tristate "Build trace_printk module - tests various trace_printk formats"26 tristate "Build trace_printk module - tests various trace_printk formats"
27 depends on EVENT_TRACING && m27 depends on EVENT_TRACING && m
28 help28 help
29 This builds a module that calls trace_printk() and can be used to29 This builds a module that calls trace_printk() and can be used to
30 test various trace_printk() calls from a module.30 test various trace_printk() calls from a module.
31 31
32config SAMPLE_FTRACE_DIRECT32config SAMPLE_FTRACE_DIRECT
33 tristate "Build register_ftrace_direct() example"33 tristate "Build register_ftrace_direct() example"
@@ -54,11 +54,11 @@ config SAMPLE_FTRACE_OPS · 20 unmodified lines
54 measures the time taken to invoke one function a number of times.54 measures the time taken to invoke one function a number of times.
55 55
56config SAMPLE_TRACE_ARRAY56config SAMPLE_TRACE_ARRAY
57 tristate "Build sample module for kernel access to Ftrace instances"57 tristate "Build sample module for kernel access to Ftrace instances"
58 depends on EVENT_TRACING && m58 depends on EVENT_TRACING && m
59 help59 help
60 This builds a module that demonstrates the use of various APIs to60 This builds a module that demonstrates the use of various APIs to
61 access Ftrace instances from within the kernel.61 access Ftrace instances from within the kernel.
62 62
63config SAMPLE_KOBJECT63config SAMPLE_KOBJECT
64 tristate "Build kobject examples"64 tristate "Build kobject examples"
@@ -290,11 +290,11 @@ config SAMPLE_CORESIGHT_SYSCFG · 225 unmodified lines
290 configurations and easily load them into the system at runtime.290 configurations and easily load them into the system at runtime.
291 291
292config SAMPLE_KMEMLEAK292config SAMPLE_KMEMLEAK
293 tristate "Simple test for the kernel memory leak detector"293 tristate "Simple test for the kernel memory leak detector"
294 depends on DEBUG_KMEMLEAK && m294 depends on DEBUG_KMEMLEAK && m
295 help295 help
296 Build a sample program which have explicitly leaks memory to test296 Build a sample program which have explicitly leaks memory to test
297 kmemleak297 kmemleak.
298 298
299config SAMPLE_CGROUP299config SAMPLE_CGROUP
300 bool "Build cgroup sample code"300 bool "Build cgroup sample code"
samples/vfs/Makefile+1−0
@@ -1,4 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2userprogs-always-y += test-fsmount test-statx mountinfo test-list-all-mounts2userprogs-always-y += test-fsmount test-statx mountinfo test-list-all-mounts
3 3
4userccflags += -I $(srctree)/tools/testing/selftests/
4userccflags += -I usr/include5userccflags += -I usr/include
scripts/checkpatch.pl+11−0
@@ -860,6 +860,10 @@ our %deprecated_apis = ( · 859 unmodified lines
860 "kunmap" => "kunmap_local",860 "kunmap" => "kunmap_local",
861 "kmap_atomic" => "kmap_local_page",861 "kmap_atomic" => "kmap_local_page",
862 "kunmap_atomic" => "kunmap_local",862 "kunmap_atomic" => "kunmap_local",
863 #These should be enough to drive away new IDR users
864 "DEFINE_IDR" => "DEFINE_XARRAY",
865 "idr_init" => "xa_init",
866 "idr_init_base" => "xa_init_flags"
863);867);
864 868
865#Create a search pattern for all these strings to speed up a loop below869#Create a search pattern for all these strings to speed up a loop below
@@ -3345,6 +3349,13 @@ sub process { · 2479 unmodified lines
3345 }3349 }
3346 }3350 }
3347 3351
3352# Check for auto-generated unhandled placeholder text (mostly for cover letters)
3353 if (($in_commit_log || $in_header_lines) &&
3354 $rawline =~ /(?:SUBJECT|BLURB) HERE/) {
3355 ERROR("PLACEHOLDER_USE",
3356 "Placeholder text detected\n" . $herecurr);
3357 }
3358
3348# Check for git id commit length and improperly formed commit descriptions3359# Check for git id commit length and improperly formed commit descriptions
3349# A correctly formed commit description is:3360# A correctly formed commit description is:
3350# commit <SHA-1 hash length 12+ chars> ("Complete commit subject")3361# commit <SHA-1 hash length 12+ chars> ("Complete commit subject")
scripts/gdb/linux/bpf.py+253−0
@@ -0,0 +1,253 @@
1# SPDX-License-Identifier: GPL-2.0
2
3import json
4import subprocess
5import tempfile
6
7import gdb
8
9from linux import constants, lists, radixtree, utils
10
11
12if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
13 bpf_ksym_type = utils.CachedType("struct bpf_ksym")
14if constants.LX_CONFIG_BPF_SYSCALL:
15 bpf_prog_type = utils.CachedType("struct bpf_prog")
16
17
18def get_ksym_name(ksym):
19 name = ksym["name"].bytes
20 end = name.find(b"\x00")
21 if end != -1:
22 name = name[:end]
23 return name.decode()
24
25
26def list_ksyms():
27 if not (constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT):
28 return []
29 bpf_kallsyms = gdb.parse_and_eval("&bpf_kallsyms")
30 bpf_ksym_ptr_type = bpf_ksym_type.get_type().pointer()
31 return list(lists.list_for_each_entry(bpf_kallsyms,
32 bpf_ksym_ptr_type,
33 "lnode"))
34
35
36class KsymAddBreakpoint(gdb.Breakpoint):
37 def __init__(self, monitor):
38 super(KsymAddBreakpoint, self).__init__("bpf_ksym_add", internal=True)
39 self.silent = True
40 self.monitor = monitor
41
42 def stop(self):
43 self.monitor.add(gdb.parse_and_eval("ksym"))
44 return False
45
46
47class KsymRemoveBreakpoint(gdb.Breakpoint):
48 def __init__(self, monitor):
49 super(KsymRemoveBreakpoint, self).__init__("bpf_ksym_del",
50 internal=True)
51 self.silent = True
52 self.monitor = monitor
53
54 def stop(self):
55 self.monitor.remove(gdb.parse_and_eval("ksym"))
56 return False
57
58
59class KsymMonitor:
60 def __init__(self, add, remove):
61 self.add = add
62 self.remove = remove
63
64 self.add_bp = KsymAddBreakpoint(self)
65 self.remove_bp = KsymRemoveBreakpoint(self)
66
67 self.notify_initial()
68
69 def notify_initial(self):
70 for ksym in list_ksyms():
71 self.add(ksym)
72
73 def delete(self):
74 self.add_bp.delete()
75 self.remove_bp.delete()
76
77
78def list_progs():
79 if not constants.LX_CONFIG_BPF_SYSCALL:
80 return []
81 idr_rt = gdb.parse_and_eval("&prog_idr.idr_rt")
82 bpf_prog_ptr_type = bpf_prog_type.get_type().pointer()
83 progs = []
84 for _, slot in radixtree.for_each_slot(idr_rt):
85 prog = slot.dereference().cast(bpf_prog_ptr_type)
86 progs.append(prog)
87 # Subprogs are not registered in prog_idr, fetch them manually.
88 # func[0] is the current prog.
89 aux = prog["aux"]
90 func = aux["func"]
91 real_func_cnt = int(aux["real_func_cnt"])
92 for i in range(1, real_func_cnt):
93 progs.append(func[i])
94 return progs
95
96
97class ProgAddBreakpoint(gdb.Breakpoint):
98 def __init__(self, monitor):
99 super(ProgAddBreakpoint, self).__init__("bpf_prog_kallsyms_add",
100 internal=True)
101 self.silent = True
102 self.monitor = monitor
103
104 def stop(self):
105 self.monitor.add(gdb.parse_and_eval("fp"))
106 return False
107
108
109class ProgRemoveBreakpoint(gdb.Breakpoint):
110 def __init__(self, monitor):
111 super(ProgRemoveBreakpoint, self).__init__("bpf_prog_free_id",
112 internal=True)
113 self.silent = True
114 self.monitor = monitor
115
116 def stop(self):
117 self.monitor.remove(gdb.parse_and_eval("prog"))
118 return False
119
120
121class ProgMonitor:
122 def __init__(self, add, remove):
123 self.add = add
124 self.remove = remove
125
126 self.add_bp = ProgAddBreakpoint(self)
127 self.remove_bp = ProgRemoveBreakpoint(self)
128
129 self.notify_initial()
130
131 def notify_initial(self):
132 for prog in list_progs():
133 self.add(prog)
134
135 def delete(self):
136 self.add_bp.delete()
137 self.remove_bp.delete()
138
139
140def btf_str_by_offset(btf, offset):
141 while offset < btf["start_str_off"]:
142 btf = btf["base_btf"]
143
144 offset -= btf["start_str_off"]
145 if offset < btf["hdr"]["str_len"]:
146 return (btf["strings"] + offset).string()
147
148 return None
149
150
151def bpf_line_info_line_num(line_col):
152 return line_col >> 10
153
154
155def bpf_line_info_line_col(line_col):
156 return line_col & 0x3ff
157
158
159class LInfoIter:
160 def __init__(self, prog):
161 # See bpf_prog_get_file_line() for details.
162 self.pos = 0
163 self.nr_linfo = 0
164
165 if prog is None:
166 return
167
168 self.bpf_func = int(prog["bpf_func"])
169 aux = prog["aux"]
170 self.btf = aux["btf"]
171 linfo_idx = aux["linfo_idx"]
172 self.nr_linfo = int(aux["nr_linfo"]) - linfo_idx
173 if self.nr_linfo == 0:
174 return
175
176 linfo_ptr = aux["linfo"]
177 tpe = linfo_ptr.type.target().array(self.nr_linfo).pointer()
178 self.linfo = (linfo_ptr + linfo_idx).cast(tpe).dereference()
179 jited_linfo_ptr = aux["jited_linfo"]
180 tpe = jited_linfo_ptr.type.target().array(self.nr_linfo).pointer()
181 self.jited_linfo = (jited_linfo_ptr + linfo_idx).cast(tpe).dereference()
182
183 self.filenos = {}
184
185 def get_code_off(self):
186 if self.pos >= self.nr_linfo:
187 return -1
188 return self.jited_linfo[self.pos] - self.bpf_func
189
190 def advance(self):
191 self.pos += 1
192
193 def get_fileno(self):
194 file_name_off = int(self.linfo[self.pos]["file_name_off"])
195 fileno = self.filenos.get(file_name_off)
196 if fileno is not None:
197 return fileno, None
198 file_name = btf_str_by_offset(self.btf, file_name_off)
199 fileno = len(self.filenos) + 1
200 self.filenos[file_name_off] = fileno
201 return fileno, file_name
202
203 def get_line_col(self):
204 line_col = int(self.linfo[self.pos]["line_col"])
205 return bpf_line_info_line_num(line_col), \
206 bpf_line_info_line_col(line_col)
207
208
209def generate_debug_obj(ksym, prog):
210 name = get_ksym_name(ksym)
211 # Avoid read_memory(); it throws bogus gdb.MemoryError in some contexts.
212 start = ksym["start"]
213 code = start.cast(gdb.lookup_type("unsigned char")
214 .array(int(ksym["end"]) - int(start))
215 .pointer()).dereference().bytes
216 linfo_iter = LInfoIter(prog)
217
218 result = tempfile.NamedTemporaryFile(suffix=".o", mode="wb")
219 try:
220 with tempfile.NamedTemporaryFile(suffix=".s", mode="w") as src:
221 # ".loc" does not apply to ".byte"s, only to ".insn"s, but since
222 # this needs to work for all architectures, the latter are not an
223 # option. Ask the assembler to apply ".loc"s to labels as well,
224 # and generate dummy labels after each ".loc".
225 src.write(".loc_mark_labels 1\n")
226
227 src.write(".globl {}\n".format(name))
228 src.write(".type {},@function\n".format(name))
229 src.write("{}:\n".format(name))
230 for code_off, code_byte in enumerate(code):
231 if linfo_iter.get_code_off() == code_off:
232 fileno, file_name = linfo_iter.get_fileno()
233 if file_name is not None:
234 src.write(".file {} {}\n".format(
235 fileno, json.dumps(file_name)))
236 line, col = linfo_iter.get_line_col()
237 src.write(".loc {} {} {}\n".format(fileno, line, col))
238 src.write("0:\n")
239 linfo_iter.advance()
240 src.write(".byte {}\n".format(code_byte))
241 src.write(".size {},{}\n".format(name, len(code)))
242 src.flush()
243
244 try:
245 subprocess.check_call(["as", "-c", src.name, "-o", result.name])
246 except FileNotFoundError:
247 # "as" is not installed.
248 result.close()
249 return None
250 return result
251 except:
252 result.close()
253 raise
scripts/gdb/linux/constants.py.in+3−0
@@ -170,3 +170,6 @@ LX_CONFIG(CONFIG_PAGE_OWNER) · 169 unmodified lines
170LX_CONFIG(CONFIG_SLUB_DEBUG)170LX_CONFIG(CONFIG_SLUB_DEBUG)
171LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)171LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)
172LX_CONFIG(CONFIG_MMU)172LX_CONFIG(CONFIG_MMU)
173LX_CONFIG(CONFIG_BPF)
174LX_CONFIG(CONFIG_BPF_JIT)
175LX_CONFIG(CONFIG_BPF_SYSCALL)
scripts/gdb/linux/radixtree.py+132−7
@@ -30,13 +30,16 @@ def entry_to_node(node): · 29 unmodified lines
30def node_maxindex(node):30def node_maxindex(node):
31 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 131 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
32 32
33def lookup(root, index):33def resolve_root(root):
34 if root.type == radix_tree_root_type.get_type():
35 return root
34 if root.type == radix_tree_root_type.get_type().pointer():36 if root.type == radix_tree_root_type.get_type().pointer():
35 node = root.dereference()37 return root.dereference()
36 elif root.type != radix_tree_root_type.get_type():38 raise gdb.GdbError("must be {} not {}"
37 raise gdb.GdbError("must be {} not {}"39 .format(radix_tree_root_type.get_type(), root.type))
38 .format(radix_tree_root_type.get_type(), root.type))
39 40
41def lookup(root, index):
42 root = resolve_root(root)
40 node = root['xa_head']43 node = root['xa_head']
41 if node == 0:44 if node == 0:
42 return None45 return None
@@ -71,14 +74,120 @@ def lookup(root, index): · 28 unmodified lines
71 74
72 return node75 return node
73 76
74class LxRadixTree(gdb.Function):77def descend(parent, index):
78 offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK
79 return offset, parent["slots"][offset]
80
81def load_root(root):
82 node = root["xa_head"]
83 nodep = node
84
85 if is_internal_node(node):
86 node = entry_to_node(node)
87 maxindex = node_maxindex(node)
88 return int(node["shift"]) + constants.LX_RADIX_TREE_MAP_SHIFT, \
89 nodep, maxindex
90
91 return 0, nodep, 0
92
93class RadixTreeIter:
94 def __init__(self, start):
95 self.index = 0
96 self.next_index = start
97 self.node = None
98
99def xa_mk_internal(v):
100 return (v << 2) | 2
101
102LX_XA_RETRY_ENTRY = xa_mk_internal(256)
103LX_RADIX_TREE_RETRY = LX_XA_RETRY_ENTRY
104
105def next_chunk(root, iter):
106 mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
107
108 index = iter.next_index
109 if index == 0 and iter.index != 0:
110 return None
111
112 restart = True
113 while restart:
114 restart = False
115
116 _, child, maxindex = load_root(root)
117 if index > maxindex:
118 return None
119 if not child:
120 return None
121
122 if not is_internal_node(child):
123 iter.index = index
124 iter.next_index = (maxindex + 1) & mask
125 iter.node = None
126 return root["xa_head"].address
127
128 while True:
129 node = entry_to_node(child)
130 offset, child = descend(node, index)
131
132 if not child:
133 while True:
134 offset += 1
135 if offset >= constants.LX_RADIX_TREE_MAP_SIZE:
136 break
137 slot = node["slots"][offset]
138 if slot:
139 break
140 index &= ~node_maxindex(node)
141 index = (index + (offset << int(node["shift"]))) & mask
142 if index == 0:
143 return None
144 if offset == constants.LX_RADIX_TREE_MAP_SIZE:
145 restart = True
146 break
147 child = node["slots"][offset]
148
149 if not child:
150 restart = True
151 break
152 if child == LX_XA_RETRY_ENTRY:
153 break
154 if not node["shift"] or not is_internal_node(child):
155 break
156
157 iter.index = (index & ~node_maxindex(node)) | offset
158 iter.next_index = ((index | node_maxindex(node)) + 1) & mask
159 iter.node = node
160
161 return node["slots"][offset].address
162
163def next_slot(slot, iter):
164 mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
165 for _ in range(iter.next_index - iter.index - 1):
166 slot += 1
167 iter.index = (iter.index + 1) & mask
168 if slot.dereference():
169 return slot
170 return None
171
172def for_each_slot(root, start=0):
173 iter = RadixTreeIter(start)
174 slot = None
175 while True:
176 if not slot:
177 slot = next_chunk(root, iter)
178 if not slot:
179 break
180 yield iter.index, slot
181 slot = next_slot(slot, iter)
182
183class LxRadixTreeLookup(gdb.Function):
75 """ Lookup and return a node from a RadixTree.184 """ Lookup and return a node from a RadixTree.
76 185
77$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.186$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
78If index is omitted, the root node is dereference and returned."""187If index is omitted, the root node is dereference and returned."""
79 188
80 def __init__(self):189 def __init__(self):
81 super(LxRadixTree, self).__init__("lx_radix_tree_lookup")190 super(LxRadixTreeLookup, self).__init__("lx_radix_tree_lookup")
82 191
83 def invoke(self, root, index=0):192 def invoke(self, root, index=0):
84 result = lookup(root, index)193 result = lookup(root, index)
@@ -87,4 +196,20 @@ If index is omitted, the root node is dereference and returned.""" · 2 unmodified lines
87 196
88 return result197 return result
89 198
199class LxRadixTree(gdb.Command):
200 """Show all values stored in a RadixTree."""
201
202 def __init__(self):
203 super(LxRadixTree, self).__init__("lx-radix-tree", gdb.COMMAND_DATA,
204 gdb.COMPLETE_NONE)
205
206 def invoke(self, argument, from_tty):
207 args = gdb.string_to_argv(argument)
208 if len(args) != 1:
209 raise gdb.GdbError("Usage: lx-radix-tree ROOT")
210 root = gdb.parse_and_eval(args[0])
211 for index, slot in for_each_slot(root):
212 gdb.write("[{}] = {}\n".format(index, slot.dereference()))
213
90LxRadixTree()214LxRadixTree()
215LxRadixTreeLookup()
scripts/gdb/linux/symbols.py+93−12
@@ -11,13 +11,14 @@ · 10 unmodified lines
11# This work is licensed under the terms of the GNU GPL version 2.11# This work is licensed under the terms of the GNU GPL version 2.
12#12#
13 13
14import atexit
14import gdb15import gdb
15import os16import os
16import re17import re
17import struct18import struct
18 19
19from itertools import count20from itertools import count
20from linux import modules, utils, constants21from linux import bpf, constants, modules, utils
21 22
22 23
23if hasattr(gdb, 'Breakpoint'):24if hasattr(gdb, 'Breakpoint'):
@@ -114,17 +115,27 @@ class LxSymbols(gdb.Command): · 90 unmodified lines
114The kernel (vmlinux) is taken from the current working directly. Modules (.ko)115The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
115are scanned recursively, starting in the same directory. Optionally, the module116are scanned recursively, starting in the same directory. Optionally, the module
116search path can be extended by a space separated list of paths passed to the117search path can be extended by a space separated list of paths passed to the
117lx-symbols command."""118lx-symbols command.
119
120When the -bpf flag is specified, symbols from the currently loaded BPF programs
121are loaded as well."""
118 122
119 module_paths = []123 module_paths = []
120 module_files = []124 module_files = []
121 module_files_updated = False125 module_files_updated = False
122 loaded_modules = []126 loaded_modules = []
123 breakpoint = None127 breakpoint = None
128 bpf_prog_monitor = None
129 bpf_ksym_monitor = None
130 bpf_progs = {}
131 # The remove-symbol-file command, even when invoked with -a, requires the
132 # respective object file to exist, so keep them around.
133 bpf_debug_objs = {}
124 134
125 def __init__(self):135 def __init__(self):
126 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,136 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
127 gdb.COMPLETE_FILENAME)137 gdb.COMPLETE_FILENAME)
138 atexit.register(self.cleanup_bpf)
128 139
129 def _update_module_files(self):140 def _update_module_files(self):
130 self.module_files = []141 self.module_files = []
@@ -197,6 +208,51 @@ lx-symbols command.""" · 66 unmodified lines
197 else:208 else:
198 gdb.write("no module object found for '{0}'\n".format(module_name))209 gdb.write("no module object found for '{0}'\n".format(module_name))
199 210
211 def add_bpf_prog(self, prog):
212 if prog["jited"]:
213 self.bpf_progs[int(prog["bpf_func"])] = prog
214
215 def remove_bpf_prog(self, prog):
216 self.bpf_progs.pop(int(prog["bpf_func"]), None)
217
218 def add_bpf_ksym(self, ksym):
219 addr = int(ksym["start"])
220 name = bpf.get_ksym_name(ksym)
221 with utils.pagination_off():
222 gdb.write("loading @{addr}: {name}\n".format(
223 addr=hex(addr), name=name))
224 debug_obj = bpf.generate_debug_obj(ksym, self.bpf_progs.get(addr))
225 if debug_obj is None:
226 return
227 try:
228 cmdline = "add-symbol-file {obj} {addr}".format(
229 obj=debug_obj.name, addr=hex(addr))
230 gdb.execute(cmdline, to_string=True)
231 except:
232 debug_obj.close()
233 raise
234 self.bpf_debug_objs[addr] = debug_obj
235
236 def remove_bpf_ksym(self, ksym):
237 addr = int(ksym["start"])
238 debug_obj = self.bpf_debug_objs.pop(addr, None)
239 if debug_obj is None:
240 return
241 try:
242 name = bpf.get_ksym_name(ksym)
243 gdb.write("unloading @{addr}: {name}\n".format(
244 addr=hex(addr), name=name))
245 cmdline = "remove-symbol-file {path}".format(path=debug_obj.name)
246 gdb.execute(cmdline, to_string=True)
247 finally:
248 debug_obj.close()
249
250 def cleanup_bpf(self):
251 self.bpf_progs = {}
252 while len(self.bpf_debug_objs) > 0:
253 self.bpf_debug_objs.popitem()[1].close()
254
255
200 def load_all_symbols(self):256 def load_all_symbols(self):
201 gdb.write("loading vmlinux\n")257 gdb.write("loading vmlinux\n")
202 258
@@ -224,34 +280,59 @@ lx-symbols command.""" · 21 unmodified lines
224 else:280 else:
225 [self.load_module_symbols(module) for module in module_list]281 [self.load_module_symbols(module) for module in module_list]
226 282
283 self.cleanup_bpf()
284 if self.bpf_prog_monitor is not None:
285 self.bpf_prog_monitor.notify_initial()
286 if self.bpf_ksym_monitor is not None:
287 self.bpf_ksym_monitor.notify_initial()
288
227 for saved_state in saved_states:289 for saved_state in saved_states:
228 saved_state['breakpoint'].enabled = saved_state['enabled']290 saved_state['breakpoint'].enabled = saved_state['enabled']
229 291
230 def invoke(self, arg, from_tty):292 def invoke(self, arg, from_tty):
231 skip_decompressor()293 skip_decompressor()
232 294
233 self.module_paths = [os.path.abspath(os.path.expanduser(p))295 monitor_bpf = False
234 for p in arg.split()]296 self.module_paths = []
297 for p in arg.split():
298 if p == "-bpf":
299 monitor_bpf = True
300 else:
301 p.append(os.path.abspath(os.path.expanduser(p)))
235 self.module_paths.append(os.getcwd())302 self.module_paths.append(os.getcwd())
236 303
304 if self.breakpoint is not None:
305 self.breakpoint.delete()
306 self.breakpoint = None
307 if self.bpf_prog_monitor is not None:
308 self.bpf_prog_monitor.delete()
309 self.bpf_prog_monitor = None
310 if self.bpf_ksym_monitor is not None:
311 self.bpf_ksym_monitor.delete()
312 self.bpf_ksym_monitor = None
313
237 # enforce update314 # enforce update
238 self.module_files = []315 self.module_files = []
239 self.module_files_updated = False316 self.module_files_updated = False
240 317
241 self.load_all_symbols()318 self.load_all_symbols()
242 319
243 if not modules.has_modules():320 if not hasattr(gdb, 'Breakpoint'):
321 gdb.write("Note: symbol update on module and BPF loading not "
322 "supported with this gdb version\n")
244 return323 return
245 324
246 if hasattr(gdb, 'Breakpoint'):325 if modules.has_modules():
247 if self.breakpoint is not None:
248 self.breakpoint.delete()
249 self.breakpoint = None
250 self.breakpoint = LoadModuleBreakpoint(326 self.breakpoint = LoadModuleBreakpoint(
251 "kernel/module/main.c:do_init_module", self)327 "kernel/module/main.c:do_init_module", self)
252 else:328
253 gdb.write("Note: symbol update on module loading not supported "329 if monitor_bpf:
254 "with this gdb version\n")330 if constants.LX_CONFIG_BPF_SYSCALL:
331 self.bpf_prog_monitor = bpf.ProgMonitor(self.add_bpf_prog,
332 self.remove_bpf_prog)
333 if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
334 self.bpf_ksym_monitor = bpf.KsymMonitor(self.add_bpf_ksym,
335 self.remove_bpf_ksym)
255 336
256 337
257LxSymbols()338LxSymbols()
tools/testing/selftests/Makefile+1−0
@@ -54,6 +54,7 @@ TARGETS += kvm · 53 unmodified lines
54TARGETS += landlock54TARGETS += landlock
55TARGETS += lib55TARGETS += lib
56TARGETS += livepatch56TARGETS += livepatch
57TARGETS += liveupdate
57TARGETS += lkdtm58TARGETS += lkdtm
58TARGETS += lsm59TARGETS += lsm
59TARGETS += membarrier60TARGETS += membarrier
tools/testing/selftests/acct/acct_syscall.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <string.h>9#include <string.h>
10#include <sys/wait.h>10#include <sys/wait.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13 13
14int main(void)14int main(void)
15{15{
tools/testing/selftests/alsa/conf.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <regex.h>14#include <regex.h>
15#include <sys/stat.h>15#include <sys/stat.h>
16 16
17#include "../kselftest.h"17#include "kselftest.h"
18#include "alsa-local.h"18#include "alsa-local.h"
19 19
20#define SYSFS_ROOT "/sys"20#define SYSFS_ROOT "/sys"
tools/testing/selftests/alsa/mixer-test.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <poll.h>25#include <poll.h>
26#include <stdint.h>26#include <stdint.h>
27 27
28#include "../kselftest.h"28#include "kselftest.h"
29#include "alsa-local.h"29#include "alsa-local.h"
30 30
31#define TESTS_PER_CONTROL 731#define TESTS_PER_CONTROL 7
tools/testing/selftests/alsa/pcm-test.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <assert.h>17#include <assert.h>
18#include <pthread.h>18#include <pthread.h>
19 19
20#include "../kselftest.h"20#include "kselftest.h"
21#include "alsa-local.h"21#include "alsa-local.h"
22 22
23typedef struct timespec timestamp_t;23typedef struct timespec timestamp_t;
tools/testing/selftests/alsa/test-pcmtest-driver.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 */7 */
8#include <string.h>8#include <string.h>
9#include <alsa/asoundlib.h>9#include <alsa/asoundlib.h>
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11 11
12#define CH_NUM 412#define CH_NUM 4
13 13
tools/testing/selftests/alsa/utimer-test.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6 *6 *
7 * Author: Ivan Orlov <ivan.orlov0322@gmail.com>7 * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
8 */8 */
9#include "../kselftest_harness.h"9#include "kselftest_harness.h"
10#include <sound/asound.h>10#include <sound/asound.h>
11#include <unistd.h>11#include <unistd.h>
12#include <fcntl.h>12#include <fcntl.h>
tools/testing/selftests/arm64/abi/hwcap.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19 19
20#include <linux/auxvec.h>20#include <linux/auxvec.h>
21 21
22#include "../../kselftest.h"22#include "kselftest.h"
23 23
24#define TESTS_PER_HWCAP 324#define TESTS_PER_HWCAP 3
25 25
tools/testing/selftests/arm64/abi/ptrace.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <asm/sigcontext.h>18#include <asm/sigcontext.h>
19#include <asm/ptrace.h>19#include <asm/ptrace.h>
20 20
21#include "../../kselftest.h"21#include "kselftest.h"
22 22
23#define EXPECTED_TESTS 1123#define EXPECTED_TESTS 11
24 24
tools/testing/selftests/arm64/abi/syscall-abi.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <asm/sigcontext.h>16#include <asm/sigcontext.h>
17#include <asm/unistd.h>17#include <asm/unistd.h>
18 18
19#include "../../kselftest.h"19#include "kselftest.h"
20 20
21#include "syscall-abi.h"21#include "syscall-abi.h"
22 22
tools/testing/selftests/arm64/fp/fp-ptrace.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27#include <asm/sve_context.h>27#include <asm/sve_context.h>
28#include <asm/ptrace.h>28#include <asm/ptrace.h>
29 29
30#include "../../kselftest.h"30#include "kselftest.h"
31 31
32#include "fp-ptrace.h"32#include "fp-ptrace.h"
33 33
tools/testing/selftests/arm64/fp/fp-stress.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <sys/wait.h>24#include <sys/wait.h>
25#include <asm/hwcap.h>25#include <asm/hwcap.h>
26 26
27#include "../../kselftest.h"27#include "kselftest.h"
28 28
29#define MAX_VLS 1629#define MAX_VLS 16
30 30
tools/testing/selftests/arm64/fp/sve-probe-vls.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <sys/prctl.h>12#include <sys/prctl.h>
13#include <asm/sigcontext.h>13#include <asm/sigcontext.h>
14 14
15#include "../../kselftest.h"15#include "kselftest.h"
16#include "rdvl.h"16#include "rdvl.h"
17 17
18int main(int argc, char **argv)18int main(int argc, char **argv)
tools/testing/selftests/arm64/fp/sve-ptrace.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <asm/sigcontext.h>19#include <asm/sigcontext.h>
20#include <asm/ptrace.h>20#include <asm/ptrace.h>
21 21
22#include "../../kselftest.h"22#include "kselftest.h"
23 23
24/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */24/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
25#ifndef NT_ARM_SVE25#ifndef NT_ARM_SVE
tools/testing/selftests/arm64/fp/vec-syscfg.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <asm/sigcontext.h>19#include <asm/sigcontext.h>
20#include <asm/hwcap.h>20#include <asm/hwcap.h>
21 21
22#include "../../kselftest.h"22#include "kselftest.h"
23#include "rdvl.h"23#include "rdvl.h"
24 24
25#define ARCH_MIN_VL SVE_VL_MIN25#define ARCH_MIN_VL SVE_VL_MIN
tools/testing/selftests/arm64/fp/za-ptrace.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <asm/sigcontext.h>18#include <asm/sigcontext.h>
19#include <asm/ptrace.h>19#include <asm/ptrace.h>
20 20
21#include "../../kselftest.h"21#include "kselftest.h"
22 22
23/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */23/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
24#ifndef NT_ARM_ZA24#ifndef NT_ARM_ZA
tools/testing/selftests/arm64/fp/zt-ptrace.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <asm/sigcontext.h>18#include <asm/sigcontext.h>
19#include <asm/ptrace.h>19#include <asm/ptrace.h>
20 20
21#include "../../kselftest.h"21#include "kselftest.h"
22 22
23/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */23/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
24#ifndef NT_ARM_ZA24#ifndef NT_ARM_ZA
tools/testing/selftests/arm64/gcs/gcs-stress.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <sys/wait.h>24#include <sys/wait.h>
25#include <asm/hwcap.h>25#include <asm/hwcap.h>
26 26
27#include "../../kselftest.h"27#include "kselftest.h"
28 28
29struct child_data {29struct child_data {
30 char *name, *output;30 char *name, *output;
tools/testing/selftests/arm64/pauth/pac.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <setjmp.h>10#include <setjmp.h>
11#include <sched.h>11#include <sched.h>
12 12
13#include "../../kselftest_harness.h"13#include "kselftest_harness.h"
14#include "helper.h"14#include "helper.h"
15 15
16#define PAC_COLLISION_ATTEMPTS 100016#define PAC_COLLISION_ATTEMPTS 1000
tools/testing/selftests/arm64/tags/tags_test.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <stdint.h>6#include <stdint.h>
7#include <sys/prctl.h>7#include <sys/prctl.h>
8#include <sys/utsname.h>8#include <sys/utsname.h>
9#include "../../kselftest.h"9#include "kselftest.h"
10 10
11#define SHIFT_TAG(tag) ((uint64_t)(tag) << 56)11#define SHIFT_TAG(tag) ((uint64_t)(tag) << 56)
12#define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \12#define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \
tools/testing/selftests/bpf/xskxceiver.c+1−1
@@ -96,7 +96,7 @@ · 95 unmodified lines
96#include "xskxceiver.h"96#include "xskxceiver.h"
97#include <bpf/bpf.h>97#include <bpf/bpf.h>
98#include <linux/filter.h>98#include <linux/filter.h>
99#include "../kselftest.h"99#include "kselftest.h"
100#include "xsk_xdp_common.h"100#include "xsk_xdp_common.h"
101 101
102#include <network_helpers.h>102#include <network_helpers.h>
tools/testing/selftests/breakpoints/breakpoint_test.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <errno.h>18#include <errno.h>
19#include <string.h>19#include <string.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23#define COUNT_ISN_BPS 423#define COUNT_ISN_BPS 4
24#define COUNT_WPS 424#define COUNT_WPS 4
tools/testing/selftests/breakpoints/breakpoint_test_arm64.c+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#include <errno.h>26#include <errno.h>
27#include <signal.h>27#include <signal.h>
28 28
29#include "../kselftest.h"29#include "kselftest.h"
30 30
31static volatile uint8_t var[96] __attribute__((__aligned__(32)));31static volatile uint8_t var[96] __attribute__((__aligned__(32)));
32 32
tools/testing/selftests/breakpoints/step_after_suspend_test.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <sys/types.h>19#include <sys/types.h>
20#include <sys/wait.h>20#include <sys/wait.h>
21 21
22#include "../kselftest.h"22#include "kselftest.h"
23 23
24void child(int cpu)24void child(int cpu)
25{25{
tools/testing/selftests/cachestat/test_cachestat.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <fcntl.h>16#include <fcntl.h>
17#include <errno.h>17#include <errno.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21#define NR_TESTS 921#define NR_TESTS 9
22 22
tools/testing/selftests/capabilities/test_execve.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <sys/prctl.h>18#include <sys/prctl.h>
19#include <sys/stat.h>19#include <sys/stat.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23static int nerrs;23static int nerrs;
24static pid_t mpid; /* main() pid is used to avoid duplicate test counts */24static pid_t mpid; /* main() pid is used to avoid duplicate test counts */
tools/testing/selftests/capabilities/validate_cap.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/prctl.h>7#include <sys/prctl.h>
8#include <sys/auxv.h>8#include <sys/auxv.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19)12#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19)
13# define HAVE_GETAUXVAL13# define HAVE_GETAUXVAL
tools/testing/selftests/cgroup/test_core.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <string.h>17#include <string.h>
18#include <pthread.h>18#include <pthread.h>
19 19
20#include "../kselftest.h"20#include "kselftest.h"
21#include "cgroup_util.h"21#include "cgroup_util.h"
22 22
23static bool nsdelegate;23static bool nsdelegate;
tools/testing/selftests/cgroup/test_cpu.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <time.h>11#include <time.h>
12#include <unistd.h>12#include <unistd.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15#include "cgroup_util.h"15#include "cgroup_util.h"
16 16
17enum hog_clock_type {17enum hog_clock_type {
tools/testing/selftests/cgroup/test_cpuset.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3#include <linux/limits.h>3#include <linux/limits.h>
4#include <signal.h>4#include <signal.h>
5 5
6#include "../kselftest.h"6#include "kselftest.h"
7#include "cgroup_util.h"7#include "cgroup_util.h"
8 8
9static int idle_process_fn(const char *cgroup, void *arg)9static int idle_process_fn(const char *cgroup, void *arg)
tools/testing/selftests/cgroup/test_freezer.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <string.h>11#include <string.h>
12#include <sys/wait.h>12#include <sys/wait.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15#include "cgroup_util.h"15#include "cgroup_util.h"
16 16
17#define DEBUG17#define DEBUG
tools/testing/selftests/cgroup/test_hugetlb_memcg.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <stdlib.h>7#include <stdlib.h>
8#include <string.h>8#include <string.h>
9#include <fcntl.h>9#include <fcntl.h>
10#include "../kselftest.h"10#include "kselftest.h"
11#include "cgroup_util.h"11#include "cgroup_util.h"
12 12
13#define ADDR ((void *)(0x0UL))13#define ADDR ((void *)(0x0UL))
tools/testing/selftests/cgroup/test_kill.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <sys/types.h>9#include <sys/types.h>
10#include <unistd.h>10#include <unistd.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13#include "../pidfd/pidfd.h"13#include "../pidfd/pidfd.h"
14#include "cgroup_util.h"14#include "cgroup_util.h"
15 15
tools/testing/selftests/cgroup/test_kmem.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/sysinfo.h>14#include <sys/sysinfo.h>
15#include <pthread.h>15#include <pthread.h>
16 16
17#include "../kselftest.h"17#include "kselftest.h"
18#include "cgroup_util.h"18#include "cgroup_util.h"
19 19
20 20
tools/testing/selftests/cgroup/test_memcontrol.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <errno.h>18#include <errno.h>
19#include <sys/mman.h>19#include <sys/mman.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22#include "cgroup_util.h"22#include "cgroup_util.h"
23 23
24static bool has_localevents;24static bool has_localevents;
tools/testing/selftests/cgroup/test_pids.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <sys/types.h>9#include <sys/types.h>
10#include <unistd.h>10#include <unistd.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13#include "cgroup_util.h"13#include "cgroup_util.h"
14 14
15static int run_success(const char *cgroup, void *arg)15static int run_success(const char *cgroup, void *arg)
tools/testing/selftests/cgroup/test_zswap.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <sys/wait.h>10#include <sys/wait.h>
11#include <sys/mman.h>11#include <sys/mman.h>
12 12
13#include "../kselftest.h"13#include "kselftest.h"
14#include "cgroup_util.h"14#include "cgroup_util.h"
15 15
16static int read_int(const char *path, size_t *value)16static int read_int(const char *path, size_t *value)
tools/testing/selftests/clone3/clone3.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <unistd.h>18#include <unistd.h>
19#include <sched.h>19#include <sched.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22#include "clone3_selftests.h"22#include "clone3_selftests.h"
23 23
24enum test_mode {24enum test_mode {
tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <unistd.h>24#include <unistd.h>
25#include <sched.h>25#include <sched.h>
26 26
27#include "../kselftest_harness.h"27#include "kselftest_harness.h"
28#include "clone3_selftests.h"28#include "clone3_selftests.h"
29 29
30static void child_exit(int ret)30static void child_exit(int ret)
tools/testing/selftests/clone3/clone3_clear_sighand.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <sys/syscall.h>13#include <sys/syscall.h>
14#include <sys/wait.h>14#include <sys/wait.h>
15 15
16#include "../kselftest.h"16#include "kselftest.h"
17#include "clone3_selftests.h"17#include "clone3_selftests.h"
18 18
19static void nop_handler(int signo)19static void nop_handler(int signo)
tools/testing/selftests/clone3/clone3_selftests.h+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <syscall.h>11#include <syscall.h>
12#include <sys/wait.h>12#include <sys/wait.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15 15
16#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))16#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
17 17
tools/testing/selftests/clone3/clone3_set_tid.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <unistd.h>20#include <unistd.h>
21#include <sched.h>21#include <sched.h>
22 22
23#include "../kselftest.h"23#include "kselftest.h"
24#include "clone3_selftests.h"24#include "clone3_selftests.h"
25 25
26#define MAX_PID_NS_LEVEL 3226#define MAX_PID_NS_LEVEL 32
tools/testing/selftests/connector/proc_filter.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <signal.h>16#include <signal.h>
17#include <string.h>17#include <string.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21#define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \21#define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
22 sizeof(struct proc_input))22 sizeof(struct proc_input))
tools/testing/selftests/core/close_range_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/resource.h>14#include <sys/resource.h>
15#include <linux/close_range.h>15#include <linux/close_range.h>
16 16
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18#include "../clone3/clone3_selftests.h"18#include "../clone3/clone3_selftests.h"
19 19
20 20
tools/testing/selftests/core/unshare_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/resource.h>14#include <sys/resource.h>
15#include <linux/close_range.h>15#include <linux/close_range.h>
16 16
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18#include "../clone3/clone3_selftests.h"18#include "../clone3/clone3_selftests.h"
19 19
20TEST(unshare_EMFILE)20TEST(unshare_EMFILE)
tools/testing/selftests/coredump/stackdump_test.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <sys/un.h>19#include <sys/un.h>
20#include <unistd.h>20#include <unistd.h>
21 21
22#include "../kselftest_harness.h"22#include "kselftest_harness.h"
23#include "../filesystems/wrappers.h"23#include "../filesystems/wrappers.h"
24#include "../pidfd/pidfd.h"24#include "../pidfd/pidfd.h"
25 25
tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <linux/dma-buf.h>15#include <linux/dma-buf.h>
16#include <linux/dma-heap.h>16#include <linux/dma-heap.h>
17#include <drm/drm.h>17#include <drm/drm.h>
18#include "../kselftest.h"18#include "kselftest.h"
19 19
20#define DEVPATH "/dev/dma_heap"20#define DEVPATH "/dev/dma_heap"
21 21
tools/testing/selftests/drivers/dma-buf/udmabuf.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/mman.h>16#include <sys/mman.h>
17#include <linux/memfd.h>17#include <linux/memfd.h>
18#include <linux/udmabuf.h>18#include <linux/udmabuf.h>
19#include "../../kselftest.h"19#include "kselftest.h"
20 20
21#define TEST_PREFIX "drivers/dma-buf/udmabuf"21#define TEST_PREFIX "drivers/dma-buf/udmabuf"
22#define NUM_PAGES 422#define NUM_PAGES 4
tools/testing/selftests/drivers/net/gro.c+1−1
@@ -57,7 +57,7 @@ · 56 unmodified lines
57#include <string.h>57#include <string.h>
58#include <unistd.h>58#include <unistd.h>
59 59
60#include "../../kselftest.h"60#include "kselftest.h"
61#include "../../net/lib/ksft.h"61#include "../../net/lib/ksft.h"
62 62
63#define DPORT 800063#define DPORT 8000
tools/testing/selftests/drivers/net/hw/toeplitz.c+1−1
@@ -55,7 +55,7 @@ · 54 unmodified lines
55#include <ynl.h>55#include <ynl.h>
56#include "ethtool-user.h"56#include "ethtool-user.h"
57 57
58#include "../../../kselftest.h"58#include "kselftest.h"
59#include "../../../net/lib/ksft.h"59#include "../../../net/lib/ksft.h"
60 60
61#define TOEPLITZ_KEY_MIN_LEN 4061#define TOEPLITZ_KEY_MIN_LEN 40
tools/testing/selftests/drivers/ntsync/ntsync.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <time.h>12#include <time.h>
13#include <pthread.h>13#include <pthread.h>
14#include <linux/ntsync.h>14#include <linux/ntsync.h>
15#include "../../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17static int read_sem_state(int sem, __u32 *count, __u32 *max)17static int read_sem_state(int sem, __u32 *count, __u32 *max)
18{18{
tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14 14
15#include <asm/uvdevice.h>15#include <asm/uvdevice.h>
16 16
17#include "../../../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#define UV_PATH "/dev/uv"19#define UV_PATH "/dev/uv"
20#define BUFFER_SIZE 0x20020#define BUFFER_SIZE 0x200
tools/testing/selftests/exec/check-exec.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#define _ASM_GENERIC_FCNTL_H30#define _ASM_GENERIC_FCNTL_H
31#include <linux/fcntl.h>31#include <linux/fcntl.h>
32 32
33#include "../kselftest_harness.h"33#include "kselftest_harness.h"
34 34
35static int sys_execveat(int dirfd, const char *pathname, char *const argv[],35static int sys_execveat(int dirfd, const char *pathname, char *const argv[],
36 char *const envp[], int flags)36 char *const envp[], int flags)
tools/testing/selftests/exec/execveat.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <string.h>21#include <string.h>
22#include <unistd.h>22#include <unistd.h>
23 23
24#include "../kselftest.h"24#include "kselftest.h"
25 25
26#define TESTS_EXPECTED 5426#define TESTS_EXPECTED 54
27#define TEST_NAME_LEN (PATH_MAX * 4)27#define TEST_NAME_LEN (PATH_MAX * 4)
tools/testing/selftests/exec/load_address.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <stdio.h>6#include <stdio.h>
7#include <stdlib.h>7#include <stdlib.h>
8#include <stdbool.h>8#include <stdbool.h>
9#include "../kselftest.h"9#include "kselftest.h"
10 10
11struct Statistics {11struct Statistics {
12 unsigned long long load_address;12 unsigned long long load_address;
tools/testing/selftests/exec/non-regular.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <sys/sysmacros.h>9#include <sys/sysmacros.h>
10#include <sys/types.h>10#include <sys/types.h>
11 11
12#include "../kselftest_harness.h"12#include "kselftest_harness.h"
13 13
14/* Remove a file, ignoring the result if it didn't exist. */14/* Remove a file, ignoring the result if it didn't exist. */
15void rm(struct __test_metadata *_metadata, const char *pathname,15void rm(struct __test_metadata *_metadata, const char *pathname,
tools/testing/selftests/exec/null-argv.c+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
5#include <sys/types.h>5#include <sys/types.h>
6#include <sys/wait.h>6#include <sys/wait.h>
7 7
8#include "../kselftest.h"8#include "kselftest.h"
9 9
10#define FORK(exec) \10#define FORK(exec) \
11do { \11do { \
tools/testing/selftests/exec/recursion-depth.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <fcntl.h>23#include <fcntl.h>
24#include <sys/mount.h>24#include <sys/mount.h>
25#include <unistd.h>25#include <unistd.h>
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28int main(void)28int main(void)
29{29{
tools/testing/selftests/fchmodat2/fchmodat2_test.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <syscall.h>7#include <syscall.h>
8#include <unistd.h>8#include <unistd.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12int sys_fchmodat2(int dfd, const char *filename, mode_t mode, int flags)12int sys_fchmodat2(int dfd, const char *filename, mode_t mode, int flags)
13{13{
tools/testing/selftests/filelock/ofdlocks.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <stdio.h>6#include <stdio.h>
7#include <unistd.h>7#include <unistd.h>
8#include <string.h>8#include <string.h>
9#include "../kselftest.h"9#include "kselftest.h"
10 10
11static int lock_set(int fd, struct flock *fl)11static int lock_set(int fd, struct flock *fl)
12{12{
tools/testing/selftests/filesystems/anon_inode_test.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <stdio.h>6#include <stdio.h>
7#include <sys/stat.h>7#include <sys/stat.h>
8 8
9#include "../kselftest_harness.h"9#include "kselftest_harness.h"
10#include "wrappers.h"10#include "wrappers.h"
11 11
12TEST(anon_inode_no_chown)12TEST(anon_inode_no_chown)
tools/testing/selftests/filesystems/binderfs/binderfs_test.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <linux/android/binder.h>21#include <linux/android/binder.h>
22#include <linux/android/binderfs.h>22#include <linux/android/binderfs.h>
23 23
24#include "../../kselftest_harness.h"24#include "kselftest_harness.h"
25 25
26#define DEFAULT_THREADS 426#define DEFAULT_THREADS 4
27 27
tools/testing/selftests/filesystems/devpts_pts.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <asm/ioctls.h>11#include <asm/ioctls.h>
12#include <sys/mount.h>12#include <sys/mount.h>
13#include <sys/wait.h>13#include <sys/wait.h>
14#include "../kselftest.h"14#include "kselftest.h"
15 15
16static bool terminal_dup2(int duplicate, int original)16static bool terminal_dup2(int duplicate, int original)
17{17{
tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <sys/epoll.h>11#include <sys/epoll.h>
12#include <sys/socket.h>12#include <sys/socket.h>
13#include <sys/eventfd.h>13#include <sys/eventfd.h>
14#include "../../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16struct epoll_mtcontext16struct epoll_mtcontext
17{17{
tools/testing/selftests/filesystems/eventfd/eventfd_test.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <pthread.h>11#include <pthread.h>
12#include <sys/epoll.h>12#include <sys/epoll.h>
13#include <sys/eventfd.h>13#include <sys/eventfd.h>
14#include "../../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16#define EVENTFD_TEST_ITERATIONS 100000UL16#define EVENTFD_TEST_ITERATIONS 100000UL
17 17
tools/testing/selftests/filesystems/fclog.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <unistd.h>13#include <unistd.h>
14#include <sys/mount.h>14#include <sys/mount.h>
15 15
16#include "../kselftest_harness.h"16#include "kselftest_harness.h"
17 17
18#define ASSERT_ERRNO(expected, _t, seen) \18#define ASSERT_ERRNO(expected, _t, seen) \
19 __EXPECT(expected, #expected, \19 __EXPECT(expected, #expected, \
tools/testing/selftests/filesystems/file_stressor.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <sys/mount.h>12#include <sys/mount.h>
13#include <unistd.h>13#include <unistd.h>
14 14
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17#include <linux/types.h>17#include <linux/types.h>
18#include <linux/mount.h>18#include <linux/mount.h>
tools/testing/selftests/filesystems/fuse/fusectl_test.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <sched.h>17#include <sched.h>
18#include <linux/limits.h>18#include <linux/limits.h>
19 19
20#include "../../kselftest_harness.h"20#include "kselftest_harness.h"
21 21
22#define FUSECTL_MOUNTPOINT "/sys/fs/fuse/connections"22#define FUSECTL_MOUNTPOINT "/sys/fs/fuse/connections"
23#define FUSE_MOUNTPOINT "/tmp/fuse_mnt_XXXXXX"23#define FUSE_MOUNTPOINT "/tmp/fuse_mnt_XXXXXX"
tools/testing/selftests/filesystems/kernfs_test.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/stat.h>7#include <sys/stat.h>
8#include <sys/xattr.h>8#include <sys/xattr.h>
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11#include "wrappers.h"11#include "wrappers.h"
12 12
13TEST(kernfs_listxattr)13TEST(kernfs_listxattr)
tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c+1−1
@@ -19,7 +19,7 @@ typedef struct { · 18 unmodified lines
19#include <sys/syscall.h>19#include <sys/syscall.h>
20#include <sys/fanotify.h>20#include <sys/fanotify.h>
21 21
22#include "../../kselftest_harness.h"22#include "kselftest_harness.h"
23#include "../statmount/statmount.h"23#include "../statmount/statmount.h"
24#include "../utils.h"24#include "../utils.h"
25 25
tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c+1−1
@@ -19,7 +19,7 @@ typedef struct { · 18 unmodified lines
19#include <sys/syscall.h>19#include <sys/syscall.h>
20#include <sys/fanotify.h>20#include <sys/fanotify.h>
21 21
22#include "../../kselftest_harness.h"22#include "kselftest_harness.h"
23#include "../statmount/statmount.h"23#include "../statmount/statmount.h"
24#include "../utils.h"24#include "../utils.h"
25 25
tools/testing/selftests/filesystems/nsfs/iterate_mntns.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <sys/mount.h>12#include <sys/mount.h>
13#include <unistd.h>13#include <unistd.h>
14 14
15#include "../../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17#define MNT_NS_COUNT 1117#define MNT_NS_COUNT 11
18#define MNT_NS_LAST_INDEX 1018#define MNT_NS_LAST_INDEX 10
tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <sched.h>15#include <sched.h>
16#include <fcntl.h>16#include <fcntl.h>
17 17
18#include "../../kselftest.h"18#include "kselftest.h"
19#include "log.h"19#include "log.h"
20#include "../wrappers.h"20#include "../wrappers.h"
21 21
tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <sys/mount.h>12#include <sys/mount.h>
13#include <unistd.h>13#include <unistd.h>
14 14
15#include "../../kselftest_harness.h"15#include "kselftest_harness.h"
16#include "../../pidfd/pidfd.h"16#include "../../pidfd/pidfd.h"
17#include "log.h"17#include "log.h"
18#include "../utils.h"18#include "../utils.h"
tools/testing/selftests/filesystems/statmount/listmount_test.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <unistd.h>11#include <unistd.h>
12 12
13#include "statmount.h"13#include "statmount.h"
14#include "../../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16#ifndef LISTMOUNT_REVERSE16#ifndef LISTMOUNT_REVERSE
17#define LISTMOUNT_REVERSE (1 << 0) /* List later mounts first */17#define LISTMOUNT_REVERSE (1 << 0) /* List later mounts first */
tools/testing/selftests/filesystems/statmount/statmount_test.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <linux/stat.h>13#include <linux/stat.h>
14 14
15#include "statmount.h"15#include "statmount.h"
16#include "../../kselftest.h"16#include "kselftest.h"
17 17
18static const char *const known_fs[] = {18static const char *const known_fs[] = {
19 "9p", "adfs", "affs", "afs", "aio", "anon_inodefs", "apparmorfs",19 "9p", "adfs", "affs", "afs", "aio", "anon_inodefs", "apparmorfs",
tools/testing/selftests/filesystems/statmount/statmount_test_ns.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15 15
16#include "statmount.h"16#include "statmount.h"
17#include "../utils.h"17#include "../utils.h"
18#include "../../kselftest.h"18#include "kselftest.h"
19 19
20#define NSID_PASS 020#define NSID_PASS 0
21#define NSID_FAIL 121#define NSID_FAIL 1
tools/testing/selftests/filesystems/utils.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <sys/xattr.h>20#include <sys/xattr.h>
21#include <sys/mount.h>21#include <sys/mount.h>
22 22
23#include "../kselftest.h"23#include "kselftest.h"
24#include "wrappers.h"24#include "wrappers.h"
25#include "utils.h"25#include "utils.h"
26 26
tools/testing/selftests/futex/functional/futex_numa_mpol.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18 18
19#include "futextest.h"19#include "futextest.h"
20#include "futex2test.h"20#include "futex2test.h"
21#include "../../kselftest_harness.h"21#include "kselftest_harness.h"
22 22
23#define MAX_THREADS 6423#define MAX_THREADS 64
24 24
tools/testing/selftests/futex/functional/futex_priv_hash.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <linux/prctl.h>14#include <linux/prctl.h>
15#include <sys/prctl.h>15#include <sys/prctl.h>
16 16
17#include "../../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#define MAX_THREADS 6419#define MAX_THREADS 64
20 20
tools/testing/selftests/futex/functional/futex_requeue.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <limits.h>9#include <limits.h>
10 10
11#include "futextest.h"11#include "futextest.h"
12#include "../../kselftest_harness.h"12#include "kselftest_harness.h"
13 13
14#define timeout_ns 3000000014#define timeout_ns 30000000
15#define WAKE_WAIT_US 1000015#define WAKE_WAIT_US 10000
tools/testing/selftests/futex/functional/futex_requeue_pi.c+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29 29
30#include "atomic.h"30#include "atomic.h"
31#include "futextest.h"31#include "futextest.h"
32#include "../../kselftest_harness.h"32#include "kselftest_harness.h"
33 33
34#define MAX_WAKE_ITERS 100034#define MAX_WAKE_ITERS 1000
35#define THREAD_MAX 1035#define THREAD_MAX 10
tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <time.h>25#include <time.h>
26 26
27#include "futextest.h"27#include "futextest.h"
28#include "../../kselftest_harness.h"28#include "kselftest_harness.h"
29 29
30futex_t f1 = FUTEX_INITIALIZER;30futex_t f1 = FUTEX_INITIALIZER;
31futex_t f2 = FUTEX_INITIALIZER;31futex_t f2 = FUTEX_INITIALIZER;
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27 27
28#include "atomic.h"28#include "atomic.h"
29#include "futextest.h"29#include "futextest.h"
30#include "../../kselftest_harness.h"30#include "kselftest_harness.h"
31 31
32#define DELAY_US 10032#define DELAY_US 100
33 33
tools/testing/selftests/futex/functional/futex_wait.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <fcntl.h>11#include <fcntl.h>
12 12
13#include "futextest.h"13#include "futextest.h"
14#include "../../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16#define timeout_ns 3000000016#define timeout_ns 30000000
17#define WAKE_WAIT_US 1000017#define WAKE_WAIT_US 10000
tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
28#include <signal.h>28#include <signal.h>
29 29
30#include "futextest.h"30#include "futextest.h"
31#include "../../kselftest_harness.h"31#include "kselftest_harness.h"
32 32
33#define PAGE_SZ 409633#define PAGE_SZ 4096
34 34
tools/testing/selftests/futex/functional/futex_wait_timeout.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19 19
20#include "futextest.h"20#include "futextest.h"
21#include "futex2test.h"21#include "futex2test.h"
22#include "../../kselftest_harness.h"22#include "kselftest_harness.h"
23 23
24static long timeout_ns = 100000; /* 100us default timeout */24static long timeout_ns = 100000; /* 100us default timeout */
25static futex_t futex_pi;25static futex_t futex_pi;
tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include <libgen.h>30#include <libgen.h>
31 31
32#include "futextest.h"32#include "futextest.h"
33#include "../../kselftest_harness.h"33#include "kselftest_harness.h"
34 34
35#define WAIT_US 500000035#define WAIT_US 5000000
36 36
tools/testing/selftests/futex/functional/futex_wait_wouldblock.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24 24
25#include "futextest.h"25#include "futextest.h"
26#include "futex2test.h"26#include "futex2test.h"
27#include "../../kselftest_harness.h"27#include "kselftest_harness.h"
28 28
29#define timeout_ns 10000029#define timeout_ns 100000
30 30
tools/testing/selftests/futex/functional/futex_waitv.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18 18
19#include "futextest.h"19#include "futextest.h"
20#include "futex2test.h"20#include "futex2test.h"
21#include "../../kselftest_harness.h"21#include "kselftest_harness.h"
22 22
23#define WAKE_WAIT_US 1000023#define WAKE_WAIT_US 10000
24#define NR_FUTEXES 3024#define NR_FUTEXES 30
tools/testing/selftests/hid/hid_common.h+1−1
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */1/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (c) 2022-2024 Red Hat */2/* Copyright (c) 2022-2024 Red Hat */
3 3
4#include "../kselftest_harness.h"4#include "kselftest_harness.h"
5 5
6#include <fcntl.h>6#include <fcntl.h>
7#include <fnmatch.h>7#include <fnmatch.h>
tools/testing/selftests/intel_pstate/aperf.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <errno.h>11#include <errno.h>
12#include <string.h>12#include <string.h>
13#include <time.h>13#include <time.h>
14#include "../kselftest.h"14#include "kselftest.h"
15 15
16#define MSEC_PER_SEC 1000L16#define MSEC_PER_SEC 1000L
17#define NSEC_PER_MSEC 1000000L17#define NSEC_PER_MSEC 1000000L
tools/testing/selftests/iommu/iommufd_utils.h+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <assert.h>11#include <assert.h>
12#include <poll.h>12#include <poll.h>
13 13
14#include "../kselftest_harness.h"14#include "kselftest_harness.h"
15#include "../../../../drivers/iommu/iommufd/iommufd_test.h"15#include "../../../../drivers/iommu/iommufd/iommufd_test.h"
16 16
17/* Hack to make assertions more readable */17/* Hack to make assertions more readable */
tools/testing/selftests/ipc/msgque.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/msg.h>7#include <sys/msg.h>
8#include <fcntl.h>8#include <fcntl.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12#define MAX_MSG_SIZE 3212#define MAX_MSG_SIZE 32
13 13
tools/testing/selftests/ir/ir_loopback.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <dirent.h>23#include <dirent.h>
24#include <sys/stat.h>24#include <sys/stat.h>
25#include <fcntl.h>25#include <fcntl.h>
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28#define TEST_SCANCODES 1028#define TEST_SCANCODES 10
29#define SYSFS_PATH_MAX 25629#define SYSFS_PATH_MAX 256
tools/testing/selftests/kcmp/kcmp_test.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <sys/wait.h>18#include <sys/wait.h>
19#include <sys/epoll.h>19#include <sys/epoll.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2)23static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2)
24{24{
tools/testing/selftests/kho/vmtest.sh+1−0
@@ -59,6 +59,7 @@ function build_kernel() { · 58 unmodified lines
59 tee "$kconfig" > "$kho_config" <<EOF59 tee "$kconfig" > "$kho_config" <<EOF
60CONFIG_BLK_DEV_INITRD=y60CONFIG_BLK_DEV_INITRD=y
61CONFIG_KEXEC_HANDOVER=y61CONFIG_KEXEC_HANDOVER=y
62CONFIG_KEXEC_HANDOVER_DEBUGFS=y
62CONFIG_TEST_KEXEC_HANDOVER=y63CONFIG_TEST_KEXEC_HANDOVER=y
63CONFIG_DEBUG_KERNEL=y64CONFIG_DEBUG_KERNEL=y
64CONFIG_DEBUG_VM=y65CONFIG_DEBUG_VM=y
tools/testing/selftests/kselftest_harness.h+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14 *14 *
15 * .. code-block:: c15 * .. code-block:: c
16 *16 *
17 * #include "../kselftest_harness.h"17 * #include "kselftest_harness.h"
18 *18 *
19 * TEST(standalone_test) {19 * TEST(standalone_test) {
20 * do_some_stuff;20 * do_some_stuff;
tools/testing/selftests/kselftest_harness/harness-selftest.c+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
8/* Avoid any inconsistencies */8/* Avoid any inconsistencies */
9#define TH_LOG_STREAM stdout9#define TH_LOG_STREAM stdout
10 10
11#include "../kselftest_harness.h"11#include "kselftest_harness.h"
12 12
13static void test_helper(struct __test_metadata *_metadata)13static void test_helper(struct __test_metadata *_metadata)
14{14{
tools/testing/selftests/landlock/audit.h+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <sys/time.h>20#include <sys/time.h>
21#include <unistd.h>21#include <unistd.h>
22 22
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25#ifndef ARRAY_SIZE25#ifndef ARRAY_SIZE
26#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))26#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
tools/testing/selftests/landlock/common.h+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <sys/wait.h>17#include <sys/wait.h>
18#include <unistd.h>18#include <unistd.h>
19 19
20#include "../kselftest_harness.h"20#include "kselftest_harness.h"
21#include "wrappers.h"21#include "wrappers.h"
22 22
23#define TMP_DIR "tmp"23#define TMP_DIR "tmp"
tools/testing/selftests/lib.mk+3−0
@@ -199,6 +199,9 @@ clean: $(if $(TEST_GEN_MODS_DIR),clean_mods_dir) · 198 unmodified lines
199# Build with _GNU_SOURCE by default199# Build with _GNU_SOURCE by default
200CFLAGS += -D_GNU_SOURCE=200CFLAGS += -D_GNU_SOURCE=
201 201
202# Additional include paths needed by kselftest.h and local headers
203CFLAGS += -I${top_srcdir}/tools/testing/selftests
204
202# Enables to extend CFLAGS and LDFLAGS from command line, e.g.205# Enables to extend CFLAGS and LDFLAGS from command line, e.g.
203# make USERCFLAGS=-Werror USERLDFLAGS=-static206# make USERCFLAGS=-Werror USERLDFLAGS=-static
204CFLAGS += $(USERCFLAGS)207CFLAGS += $(USERCFLAGS)
tools/testing/selftests/liveupdate/.gitignore+9−0
@@ -0,0 +1,9 @@
1# SPDX-License-Identifier: GPL-2.0-only
2*
3!/**/
4!*.c
5!*.h
6!*.sh
7!.gitignore
8!config
9!Makefile
tools/testing/selftests/liveupdate/Makefile+34−0
@@ -0,0 +1,34 @@
1# SPDX-License-Identifier: GPL-2.0-only
2
3LIB_C += luo_test_utils.c
4
5TEST_GEN_PROGS += liveupdate
6
7TEST_GEN_PROGS_EXTENDED += luo_kexec_simple
8TEST_GEN_PROGS_EXTENDED += luo_multi_session
9
10TEST_FILES += do_kexec.sh
11
12include ../lib.mk
13
14CFLAGS += $(KHDR_INCLUDES)
15CFLAGS += -Wall -O2 -Wno-unused-function
16CFLAGS += -MD
17
18LIB_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIB_C))
19TEST_O := $(patsubst %, %.o, $(TEST_GEN_PROGS))
20TEST_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
21
22TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIB_O))
23TEST_DEP_FILES += $(patsubst %.o, %.d, $(TEST_O))
24-include $(TEST_DEP_FILES)
25
26$(LIB_O): $(OUTPUT)/%.o: %.c
27 $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
28
29$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIB_O)
30 $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIB_O) $(LDLIBS) -o $@
31
32EXTRA_CLEAN += $(LIB_O)
33EXTRA_CLEAN += $(TEST_O)
34EXTRA_CLEAN += $(TEST_DEP_FILES)
tools/testing/selftests/liveupdate/config+11−0
@@ -0,0 +1,11 @@
1CONFIG_BLK_DEV_INITRD=y
2CONFIG_KEXEC_FILE=y
3CONFIG_KEXEC_HANDOVER=y
4CONFIG_KEXEC_HANDOVER_ENABLE_DEFAULT=y
5CONFIG_KEXEC_HANDOVER_DEBUGFS=y
6CONFIG_KEXEC_HANDOVER_DEBUG=y
7CONFIG_LIVEUPDATE=y
8CONFIG_LIVEUPDATE_TEST=y
9CONFIG_MEMFD_CREATE=y
10CONFIG_TMPFS=y
11CONFIG_SHMEM=y
tools/testing/selftests/liveupdate/do_kexec.sh+16−0
@@ -0,0 +1,16 @@
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3set -e
4
5# Use $KERNEL and $INITRAMFS to pass custom Kernel and optional initramfs
6
7KERNEL="${KERNEL:-/boot/bzImage}"
8set -- -l -s --reuse-cmdline "$KERNEL"
9
10INITRAMFS="${INITRAMFS:-/boot/initramfs}"
11if [ -f "$INITRAMFS" ]; then
12 set -- "$@" --initrd="$INITRAMFS"
13fi
14
15kexec "$@"
16kexec -e
tools/testing/selftests/liveupdate/liveupdate.c+348−0
@@ -0,0 +1,348 @@
1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8/*
9 * Selftests for the Live Update Orchestrator.
10 * This test suite verifies the functionality and behavior of the
11 * /dev/liveupdate character device and its session management capabilities.
12 *
13 * Tests include:
14 * - Device access: basic open/close, and enforcement of exclusive access.
15 * - Session management: creation of unique sessions, and duplicate name detection.
16 * - Resource preservation: successfully preserving individual and multiple memfds,
17 * verifying contents remain accessible.
18 * - Complex multi-session scenarios involving mixed empty and populated files.
19 */
20
21#include <errno.h>
22#include <fcntl.h>
23#include <string.h>
24#include <sys/ioctl.h>
25#include <unistd.h>
26
27#include <linux/liveupdate.h>
28
29#include "../kselftest.h"
30#include "../kselftest_harness.h"
31
32#define LIVEUPDATE_DEV "/dev/liveupdate"
33
34FIXTURE(liveupdate_device) {
35 int fd1;
36 int fd2;
37};
38
39FIXTURE_SETUP(liveupdate_device)
40{
41 self->fd1 = -1;
42 self->fd2 = -1;
43}
44
45FIXTURE_TEARDOWN(liveupdate_device)
46{
47 if (self->fd1 >= 0)
48 close(self->fd1);
49 if (self->fd2 >= 0)
50 close(self->fd2);
51}
52
53/*
54 * Test Case: Basic Open and Close
55 *
56 * Verifies that the /dev/liveupdate device can be opened and subsequently
57 * closed without errors. Skips if the device does not exist.
58 */
59TEST_F(liveupdate_device, basic_open_close)
60{
61 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
62
63 if (self->fd1 < 0 && errno == ENOENT)
64 SKIP(return, "%s does not exist.", LIVEUPDATE_DEV);
65
66 ASSERT_GE(self->fd1, 0);
67 ASSERT_EQ(close(self->fd1), 0);
68 self->fd1 = -1;
69}
70
71/*
72 * Test Case: Exclusive Open Enforcement
73 *
74 * Verifies that the /dev/liveupdate device can only be opened by one process
75 * at a time. It checks that a second attempt to open the device fails with
76 * the EBUSY error code.
77 */
78TEST_F(liveupdate_device, exclusive_open)
79{
80 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
81
82 if (self->fd1 < 0 && errno == ENOENT)
83 SKIP(return, "%s does not exist.", LIVEUPDATE_DEV);
84
85 ASSERT_GE(self->fd1, 0);
86 self->fd2 = open(LIVEUPDATE_DEV, O_RDWR);
87 EXPECT_LT(self->fd2, 0);
88 EXPECT_EQ(errno, EBUSY);
89}
90
91/* Helper function to create a LUO session via ioctl. */
92static int create_session(int lu_fd, const char *name)
93{
94 struct liveupdate_ioctl_create_session args = {};
95
96 args.size = sizeof(args);
97 strncpy((char *)args.name, name, sizeof(args.name) - 1);
98
99 if (ioctl(lu_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &args))
100 return -errno;
101
102 return args.fd;
103}
104
105/*
106 * Test Case: Create Duplicate Session
107 *
108 * Verifies that attempting to create two sessions with the same name fails
109 * on the second attempt with EEXIST.
110 */
111TEST_F(liveupdate_device, create_duplicate_session)
112{
113 int session_fd1, session_fd2;
114
115 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
116 if (self->fd1 < 0 && errno == ENOENT)
117 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
118
119 ASSERT_GE(self->fd1, 0);
120
121 session_fd1 = create_session(self->fd1, "duplicate-session-test");
122 ASSERT_GE(session_fd1, 0);
123
124 session_fd2 = create_session(self->fd1, "duplicate-session-test");
125 EXPECT_LT(session_fd2, 0);
126 EXPECT_EQ(-session_fd2, EEXIST);
127
128 ASSERT_EQ(close(session_fd1), 0);
129}
130
131/*
132 * Test Case: Create Distinct Sessions
133 *
134 * Verifies that creating two sessions with different names succeeds.
135 */
136TEST_F(liveupdate_device, create_distinct_sessions)
137{
138 int session_fd1, session_fd2;
139
140 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
141 if (self->fd1 < 0 && errno == ENOENT)
142 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
143
144 ASSERT_GE(self->fd1, 0);
145
146 session_fd1 = create_session(self->fd1, "distinct-session-1");
147 ASSERT_GE(session_fd1, 0);
148
149 session_fd2 = create_session(self->fd1, "distinct-session-2");
150 ASSERT_GE(session_fd2, 0);
151
152 ASSERT_EQ(close(session_fd1), 0);
153 ASSERT_EQ(close(session_fd2), 0);
154}
155
156static int preserve_fd(int session_fd, int fd_to_preserve, __u64 token)
157{
158 struct liveupdate_session_preserve_fd args = {};
159
160 args.size = sizeof(args);
161 args.fd = fd_to_preserve;
162 args.token = token;
163
164 if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &args))
165 return -errno;
166
167 return 0;
168}
169
170/*
171 * Test Case: Preserve MemFD
172 *
173 * Verifies that a valid memfd can be successfully preserved in a session and
174 * that its contents remain intact after the preservation call.
175 */
176TEST_F(liveupdate_device, preserve_memfd)
177{
178 const char *test_str = "hello liveupdate";
179 char read_buf[64] = {};
180 int session_fd, mem_fd;
181
182 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
183 if (self->fd1 < 0 && errno == ENOENT)
184 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
185 ASSERT_GE(self->fd1, 0);
186
187 session_fd = create_session(self->fd1, "preserve-memfd-test");
188 ASSERT_GE(session_fd, 0);
189
190 mem_fd = memfd_create("test-memfd", 0);
191 ASSERT_GE(mem_fd, 0);
192
193 ASSERT_EQ(write(mem_fd, test_str, strlen(test_str)), strlen(test_str));
194 ASSERT_EQ(preserve_fd(session_fd, mem_fd, 0x1234), 0);
195 ASSERT_EQ(close(session_fd), 0);
196
197 ASSERT_EQ(lseek(mem_fd, 0, SEEK_SET), 0);
198 ASSERT_EQ(read(mem_fd, read_buf, sizeof(read_buf)), strlen(test_str));
199 ASSERT_STREQ(read_buf, test_str);
200 ASSERT_EQ(close(mem_fd), 0);
201}
202
203/*
204 * Test Case: Preserve Multiple MemFDs
205 *
206 * Verifies that multiple memfds can be preserved in a single session,
207 * each with a unique token, and that their contents remain distinct and
208 * correct after preservation.
209 */
210TEST_F(liveupdate_device, preserve_multiple_memfds)
211{
212 const char *test_str1 = "data for memfd one";
213 const char *test_str2 = "data for memfd two";
214 char read_buf[64] = {};
215 int session_fd, mem_fd1, mem_fd2;
216
217 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
218 if (self->fd1 < 0 && errno == ENOENT)
219 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
220 ASSERT_GE(self->fd1, 0);
221
222 session_fd = create_session(self->fd1, "preserve-multi-memfd-test");
223 ASSERT_GE(session_fd, 0);
224
225 mem_fd1 = memfd_create("test-memfd-1", 0);
226 ASSERT_GE(mem_fd1, 0);
227 mem_fd2 = memfd_create("test-memfd-2", 0);
228 ASSERT_GE(mem_fd2, 0);
229
230 ASSERT_EQ(write(mem_fd1, test_str1, strlen(test_str1)), strlen(test_str1));
231 ASSERT_EQ(write(mem_fd2, test_str2, strlen(test_str2)), strlen(test_str2));
232
233 ASSERT_EQ(preserve_fd(session_fd, mem_fd1, 0xAAAA), 0);
234 ASSERT_EQ(preserve_fd(session_fd, mem_fd2, 0xBBBB), 0);
235
236 memset(read_buf, 0, sizeof(read_buf));
237 ASSERT_EQ(lseek(mem_fd1, 0, SEEK_SET), 0);
238 ASSERT_EQ(read(mem_fd1, read_buf, sizeof(read_buf)), strlen(test_str1));
239 ASSERT_STREQ(read_buf, test_str1);
240
241 memset(read_buf, 0, sizeof(read_buf));
242 ASSERT_EQ(lseek(mem_fd2, 0, SEEK_SET), 0);
243 ASSERT_EQ(read(mem_fd2, read_buf, sizeof(read_buf)), strlen(test_str2));
244 ASSERT_STREQ(read_buf, test_str2);
245
246 ASSERT_EQ(close(mem_fd1), 0);
247 ASSERT_EQ(close(mem_fd2), 0);
248 ASSERT_EQ(close(session_fd), 0);
249}
250
251/*
252 * Test Case: Preserve Complex Scenario
253 *
254 * Verifies a more complex scenario with multiple sessions and a mix of empty
255 * and non-empty memfds distributed across them.
256 */
257TEST_F(liveupdate_device, preserve_complex_scenario)
258{
259 const char *data1 = "data for session 1";
260 const char *data2 = "data for session 2";
261 char read_buf[64] = {};
262 int session_fd1, session_fd2;
263 int mem_fd_data1, mem_fd_empty1, mem_fd_data2, mem_fd_empty2;
264
265 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
266 if (self->fd1 < 0 && errno == ENOENT)
267 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
268 ASSERT_GE(self->fd1, 0);
269
270 session_fd1 = create_session(self->fd1, "complex-session-1");
271 ASSERT_GE(session_fd1, 0);
272 session_fd2 = create_session(self->fd1, "complex-session-2");
273 ASSERT_GE(session_fd2, 0);
274
275 mem_fd_data1 = memfd_create("data1", 0);
276 ASSERT_GE(mem_fd_data1, 0);
277 ASSERT_EQ(write(mem_fd_data1, data1, strlen(data1)), strlen(data1));
278
279 mem_fd_empty1 = memfd_create("empty1", 0);
280 ASSERT_GE(mem_fd_empty1, 0);
281
282 mem_fd_data2 = memfd_create("data2", 0);
283 ASSERT_GE(mem_fd_data2, 0);
284 ASSERT_EQ(write(mem_fd_data2, data2, strlen(data2)), strlen(data2));
285
286 mem_fd_empty2 = memfd_create("empty2", 0);
287 ASSERT_GE(mem_fd_empty2, 0);
288
289 ASSERT_EQ(preserve_fd(session_fd1, mem_fd_data1, 0x1111), 0);
290 ASSERT_EQ(preserve_fd(session_fd1, mem_fd_empty1, 0x2222), 0);
291 ASSERT_EQ(preserve_fd(session_fd2, mem_fd_data2, 0x3333), 0);
292 ASSERT_EQ(preserve_fd(session_fd2, mem_fd_empty2, 0x4444), 0);
293
294 ASSERT_EQ(lseek(mem_fd_data1, 0, SEEK_SET), 0);
295 ASSERT_EQ(read(mem_fd_data1, read_buf, sizeof(read_buf)), strlen(data1));
296 ASSERT_STREQ(read_buf, data1);
297
298 memset(read_buf, 0, sizeof(read_buf));
299 ASSERT_EQ(lseek(mem_fd_data2, 0, SEEK_SET), 0);
300 ASSERT_EQ(read(mem_fd_data2, read_buf, sizeof(read_buf)), strlen(data2));
301 ASSERT_STREQ(read_buf, data2);
302
303 ASSERT_EQ(lseek(mem_fd_empty1, 0, SEEK_SET), 0);
304 ASSERT_EQ(read(mem_fd_empty1, read_buf, sizeof(read_buf)), 0);
305
306 ASSERT_EQ(lseek(mem_fd_empty2, 0, SEEK_SET), 0);
307 ASSERT_EQ(read(mem_fd_empty2, read_buf, sizeof(read_buf)), 0);
308
309 ASSERT_EQ(close(mem_fd_data1), 0);
310 ASSERT_EQ(close(mem_fd_empty1), 0);
311 ASSERT_EQ(close(mem_fd_data2), 0);
312 ASSERT_EQ(close(mem_fd_empty2), 0);
313 ASSERT_EQ(close(session_fd1), 0);
314 ASSERT_EQ(close(session_fd2), 0);
315}
316
317/*
318 * Test Case: Preserve Unsupported File Descriptor
319 *
320 * Verifies that attempting to preserve a file descriptor that does not have
321 * a registered Live Update handler fails gracefully.
322 * Uses /dev/null as a representative of a file type (character device)
323 * that is not supported by the orchestrator.
324 */
325TEST_F(liveupdate_device, preserve_unsupported_fd)
326{
327 int session_fd, unsupported_fd;
328 int ret;
329
330 self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
331 if (self->fd1 < 0 && errno == ENOENT)
332 SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
333 ASSERT_GE(self->fd1, 0);
334
335 session_fd = create_session(self->fd1, "unsupported-fd-test");
336 ASSERT_GE(session_fd, 0);
337
338 unsupported_fd = open("/dev/null", O_RDWR);
339 ASSERT_GE(unsupported_fd, 0);
340
341 ret = preserve_fd(session_fd, unsupported_fd, 0xDEAD);
342 EXPECT_EQ(ret, -ENOENT);
343
344 ASSERT_EQ(close(unsupported_fd), 0);
345 ASSERT_EQ(close(session_fd), 0);
346}
347
348TEST_HARNESS_MAIN
tools/testing/selftests/liveupdate/luo_kexec_simple.c+89−0
@@ -0,0 +1,89 @@
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 *
7 * A simple selftest to validate the end-to-end lifecycle of a LUO session
8 * across a single kexec reboot.
9 */
10
11#include "luo_test_utils.h"
12
13#define TEST_SESSION_NAME "test-session"
14#define TEST_MEMFD_TOKEN 0x1A
15#define TEST_MEMFD_DATA "hello kexec world"
16
17/* Constants for the state-tracking mechanism, specific to this test file. */
18#define STATE_SESSION_NAME "kexec_simple_state"
19#define STATE_MEMFD_TOKEN 999
20
21/* Stage 1: Executed before the kexec reboot. */
22static void run_stage_1(int luo_fd)
23{
24 int session_fd;
25
26 ksft_print_msg("[STAGE 1] Starting pre-kexec setup...\n");
27
28 ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n");
29 create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2);
30
31 ksft_print_msg("[STAGE 1] Creating session '%s' and preserving memfd...\n",
32 TEST_SESSION_NAME);
33 session_fd = luo_create_session(luo_fd, TEST_SESSION_NAME);
34 if (session_fd < 0)
35 fail_exit("luo_create_session for '%s'", TEST_SESSION_NAME);
36
37 if (create_and_preserve_memfd(session_fd, TEST_MEMFD_TOKEN,
38 TEST_MEMFD_DATA) < 0) {
39 fail_exit("create_and_preserve_memfd for token %#x",
40 TEST_MEMFD_TOKEN);
41 }
42
43 close(luo_fd);
44 daemonize_and_wait();
45}
46
47/* Stage 2: Executed after the kexec reboot. */
48static void run_stage_2(int luo_fd, int state_session_fd)
49{
50 int session_fd, mfd, stage;
51
52 ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n");
53
54 restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage);
55 if (stage != 2)
56 fail_exit("Expected stage 2, but state file contains %d", stage);
57
58 ksft_print_msg("[STAGE 2] Retrieving session '%s'...\n", TEST_SESSION_NAME);
59 session_fd = luo_retrieve_session(luo_fd, TEST_SESSION_NAME);
60 if (session_fd < 0)
61 fail_exit("luo_retrieve_session for '%s'", TEST_SESSION_NAME);
62
63 ksft_print_msg("[STAGE 2] Restoring and verifying memfd (token %#x)...\n",
64 TEST_MEMFD_TOKEN);
65 mfd = restore_and_verify_memfd(session_fd, TEST_MEMFD_TOKEN,
66 TEST_MEMFD_DATA);
67 if (mfd < 0)
68 fail_exit("restore_and_verify_memfd for token %#x", TEST_MEMFD_TOKEN);
69 close(mfd);
70
71 ksft_print_msg("[STAGE 2] Test data verified successfully.\n");
72 ksft_print_msg("[STAGE 2] Finalizing test session...\n");
73 if (luo_session_finish(session_fd) < 0)
74 fail_exit("luo_session_finish for test session");
75 close(session_fd);
76
77 ksft_print_msg("[STAGE 2] Finalizing state session...\n");
78 if (luo_session_finish(state_session_fd) < 0)
79 fail_exit("luo_session_finish for state session");
80 close(state_session_fd);
81
82 ksft_print_msg("\n--- SIMPLE KEXEC TEST PASSED ---\n");
83}
84
85int main(int argc, char *argv[])
86{
87 return luo_test(argc, argv, STATE_SESSION_NAME,
88 run_stage_1, run_stage_2);
89}
tools/testing/selftests/liveupdate/luo_multi_session.c+162−0
@@ -0,0 +1,162 @@
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 *
7 * A selftest to validate the end-to-end lifecycle of multiple LUO sessions
8 * across a kexec reboot, including empty sessions and sessions with multiple
9 * files.
10 */
11
12#include "luo_test_utils.h"
13
14#define SESSION_EMPTY_1 "multi-test-empty-1"
15#define SESSION_EMPTY_2 "multi-test-empty-2"
16#define SESSION_FILES_1 "multi-test-files-1"
17#define SESSION_FILES_2 "multi-test-files-2"
18
19#define MFD1_TOKEN 0x1001
20#define MFD2_TOKEN 0x2002
21#define MFD3_TOKEN 0x3003
22
23#define MFD1_DATA "Data for session files 1"
24#define MFD2_DATA "First file for session files 2"
25#define MFD3_DATA "Second file for session files 2"
26
27#define STATE_SESSION_NAME "kexec_multi_state"
28#define STATE_MEMFD_TOKEN 998
29
30/* Stage 1: Executed before the kexec reboot. */
31static void run_stage_1(int luo_fd)
32{
33 int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd;
34
35 ksft_print_msg("[STAGE 1] Starting pre-kexec setup for multi-session test...\n");
36
37 ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n");
38 create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2);
39
40 ksft_print_msg("[STAGE 1] Creating empty sessions '%s' and '%s'...\n",
41 SESSION_EMPTY_1, SESSION_EMPTY_2);
42 s_empty1_fd = luo_create_session(luo_fd, SESSION_EMPTY_1);
43 if (s_empty1_fd < 0)
44 fail_exit("luo_create_session for '%s'", SESSION_EMPTY_1);
45
46 s_empty2_fd = luo_create_session(luo_fd, SESSION_EMPTY_2);
47 if (s_empty2_fd < 0)
48 fail_exit("luo_create_session for '%s'", SESSION_EMPTY_2);
49
50 ksft_print_msg("[STAGE 1] Creating session '%s' with one memfd...\n",
51 SESSION_FILES_1);
52
53 s_files1_fd = luo_create_session(luo_fd, SESSION_FILES_1);
54 if (s_files1_fd < 0)
55 fail_exit("luo_create_session for '%s'", SESSION_FILES_1);
56 if (create_and_preserve_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA) < 0) {
57 fail_exit("create_and_preserve_memfd for token %#x",
58 MFD1_TOKEN);
59 }
60
61 ksft_print_msg("[STAGE 1] Creating session '%s' with two memfds...\n",
62 SESSION_FILES_2);
63
64 s_files2_fd = luo_create_session(luo_fd, SESSION_FILES_2);
65 if (s_files2_fd < 0)
66 fail_exit("luo_create_session for '%s'", SESSION_FILES_2);
67 if (create_and_preserve_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA) < 0) {
68 fail_exit("create_and_preserve_memfd for token %#x",
69 MFD2_TOKEN);
70 }
71 if (create_and_preserve_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA) < 0) {
72 fail_exit("create_and_preserve_memfd for token %#x",
73 MFD3_TOKEN);
74 }
75
76 close(luo_fd);
77 daemonize_and_wait();
78}
79
80/* Stage 2: Executed after the kexec reboot. */
81static void run_stage_2(int luo_fd, int state_session_fd)
82{
83 int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd;
84 int mfd1, mfd2, mfd3, stage;
85
86 ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n");
87
88 restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage);
89 if (stage != 2) {
90 fail_exit("Expected stage 2, but state file contains %d",
91 stage);
92 }
93
94 ksft_print_msg("[STAGE 2] Retrieving all sessions...\n");
95 s_empty1_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_1);
96 if (s_empty1_fd < 0)
97 fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_1);
98
99 s_empty2_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_2);
100 if (s_empty2_fd < 0)
101 fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_2);
102
103 s_files1_fd = luo_retrieve_session(luo_fd, SESSION_FILES_1);
104 if (s_files1_fd < 0)
105 fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_1);
106
107 s_files2_fd = luo_retrieve_session(luo_fd, SESSION_FILES_2);
108 if (s_files2_fd < 0)
109 fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_2);
110
111 ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n",
112 SESSION_FILES_1);
113 mfd1 = restore_and_verify_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA);
114 if (mfd1 < 0)
115 fail_exit("restore_and_verify_memfd for token %#x", MFD1_TOKEN);
116 close(mfd1);
117
118 ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n",
119 SESSION_FILES_2);
120
121 mfd2 = restore_and_verify_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA);
122 if (mfd2 < 0)
123 fail_exit("restore_and_verify_memfd for token %#x", MFD2_TOKEN);
124 close(mfd2);
125
126 mfd3 = restore_and_verify_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA);
127 if (mfd3 < 0)
128 fail_exit("restore_and_verify_memfd for token %#x", MFD3_TOKEN);
129 close(mfd3);
130
131 ksft_print_msg("[STAGE 2] Test data verified successfully.\n");
132
133 ksft_print_msg("[STAGE 2] Finalizing all test sessions...\n");
134 if (luo_session_finish(s_empty1_fd) < 0)
135 fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_1);
136 close(s_empty1_fd);
137
138 if (luo_session_finish(s_empty2_fd) < 0)
139 fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_2);
140 close(s_empty2_fd);
141
142 if (luo_session_finish(s_files1_fd) < 0)
143 fail_exit("luo_session_finish for '%s'", SESSION_FILES_1);
144 close(s_files1_fd);
145
146 if (luo_session_finish(s_files2_fd) < 0)
147 fail_exit("luo_session_finish for '%s'", SESSION_FILES_2);
148 close(s_files2_fd);
149
150 ksft_print_msg("[STAGE 2] Finalizing state session...\n");
151 if (luo_session_finish(state_session_fd) < 0)
152 fail_exit("luo_session_finish for state session");
153 close(state_session_fd);
154
155 ksft_print_msg("\n--- MULTI-SESSION KEXEC TEST PASSED ---\n");
156}
157
158int main(int argc, char *argv[])
159{
160 return luo_test(argc, argv, STATE_SESSION_NAME,
161 run_stage_1, run_stage_2);
162}
tools/testing/selftests/liveupdate/luo_test_utils.c+266−0
@@ -0,0 +1,266 @@
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8#define _GNU_SOURCE
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <getopt.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <sys/ioctl.h>
17#include <sys/syscall.h>
18#include <sys/mman.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <errno.h>
22#include <stdarg.h>
23
24#include "luo_test_utils.h"
25
26int luo_open_device(void)
27{
28 return open(LUO_DEVICE, O_RDWR);
29}
30
31int luo_create_session(int luo_fd, const char *name)
32{
33 struct liveupdate_ioctl_create_session arg = { .size = sizeof(arg) };
34
35 snprintf((char *)arg.name, LIVEUPDATE_SESSION_NAME_LENGTH, "%.*s",
36 LIVEUPDATE_SESSION_NAME_LENGTH - 1, name);
37
38 if (ioctl(luo_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &arg) < 0)
39 return -errno;
40
41 return arg.fd;
42}
43
44int luo_retrieve_session(int luo_fd, const char *name)
45{
46 struct liveupdate_ioctl_retrieve_session arg = { .size = sizeof(arg) };
47
48 snprintf((char *)arg.name, LIVEUPDATE_SESSION_NAME_LENGTH, "%.*s",
49 LIVEUPDATE_SESSION_NAME_LENGTH - 1, name);
50
51 if (ioctl(luo_fd, LIVEUPDATE_IOCTL_RETRIEVE_SESSION, &arg) < 0)
52 return -errno;
53
54 return arg.fd;
55}
56
57int create_and_preserve_memfd(int session_fd, int token, const char *data)
58{
59 struct liveupdate_session_preserve_fd arg = { .size = sizeof(arg) };
60 long page_size = sysconf(_SC_PAGE_SIZE);
61 void *map = MAP_FAILED;
62 int mfd = -1, ret = -1;
63
64 mfd = memfd_create("test_mfd", 0);
65 if (mfd < 0)
66 return -errno;
67
68 if (ftruncate(mfd, page_size) != 0)
69 goto out;
70
71 map = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, mfd, 0);
72 if (map == MAP_FAILED)
73 goto out;
74
75 snprintf(map, page_size, "%s", data);
76 munmap(map, page_size);
77
78 arg.fd = mfd;
79 arg.token = token;
80 if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg) < 0)
81 goto out;
82
83 ret = 0;
84out:
85 if (ret != 0 && errno != 0)
86 ret = -errno;
87 if (mfd >= 0)
88 close(mfd);
89 return ret;
90}
91
92int restore_and_verify_memfd(int session_fd, int token,
93 const char *expected_data)
94{
95 struct liveupdate_session_retrieve_fd arg = { .size = sizeof(arg) };
96 long page_size = sysconf(_SC_PAGE_SIZE);
97 void *map = MAP_FAILED;
98 int mfd = -1, ret = -1;
99
100 arg.token = token;
101 if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg) < 0)
102 return -errno;
103 mfd = arg.fd;
104
105 map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, mfd, 0);
106 if (map == MAP_FAILED)
107 goto out;
108
109 if (expected_data && strcmp(expected_data, map) != 0) {
110 ksft_print_msg("Data mismatch! Expected '%s', Got '%s'\n",
111 expected_data, (char *)map);
112 ret = -EINVAL;
113 goto out_munmap;
114 }
115
116 ret = mfd;
117out_munmap:
118 munmap(map, page_size);
119out:
120 if (ret < 0 && errno != 0)
121 ret = -errno;
122 if (ret < 0 && mfd >= 0)
123 close(mfd);
124 return ret;
125}
126
127int luo_session_finish(int session_fd)
128{
129 struct liveupdate_session_finish arg = { .size = sizeof(arg) };
130
131 if (ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, &arg) < 0)
132 return -errno;
133
134 return 0;
135}
136
137void create_state_file(int luo_fd, const char *session_name, int token,
138 int next_stage)
139{
140 char buf[32];
141 int state_session_fd;
142
143 state_session_fd = luo_create_session(luo_fd, session_name);
144 if (state_session_fd < 0)
145 fail_exit("luo_create_session for state tracking");
146
147 snprintf(buf, sizeof(buf), "%d", next_stage);
148 if (create_and_preserve_memfd(state_session_fd, token, buf) < 0)
149 fail_exit("create_and_preserve_memfd for state tracking");
150
151 /*
152 * DO NOT close session FD, otherwise it is going to be unpreserved
153 */
154}
155
156void restore_and_read_stage(int state_session_fd, int token, int *stage)
157{
158 char buf[32] = {0};
159 int mfd;
160
161 mfd = restore_and_verify_memfd(state_session_fd, token, NULL);
162 if (mfd < 0)
163 fail_exit("failed to restore state memfd");
164
165 if (read(mfd, buf, sizeof(buf) - 1) < 0)
166 fail_exit("failed to read state mfd");
167
168 *stage = atoi(buf);
169
170 close(mfd);
171}
172
173void daemonize_and_wait(void)
174{
175 pid_t pid;
176
177 ksft_print_msg("[STAGE 1] Forking persistent child to hold sessions...\n");
178
179 pid = fork();
180 if (pid < 0)
181 fail_exit("fork failed");
182
183 if (pid > 0) {
184 ksft_print_msg("[STAGE 1] Child PID: %d. Resources are pinned.\n", pid);
185 ksft_print_msg("[STAGE 1] You may now perform kexec reboot.\n");
186 exit(EXIT_SUCCESS);
187 }
188
189 /* Detach from terminal so closing the window doesn't kill us */
190 if (setsid() < 0)
191 fail_exit("setsid failed");
192
193 close(STDIN_FILENO);
194 close(STDOUT_FILENO);
195 close(STDERR_FILENO);
196
197 /* Change dir to root to avoid locking filesystems */
198 if (chdir("/") < 0)
199 exit(EXIT_FAILURE);
200
201 while (1)
202 sleep(60);
203}
204
205static int parse_stage_args(int argc, char *argv[])
206{
207 static struct option long_options[] = {
208 {"stage", required_argument, 0, 's'},
209 {0, 0, 0, 0}
210 };
211 int option_index = 0;
212 int stage = 1;
213 int opt;
214
215 optind = 1;
216 while ((opt = getopt_long(argc, argv, "s:", long_options, &option_index)) != -1) {
217 switch (opt) {
218 case 's':
219 stage = atoi(optarg);
220 if (stage != 1 && stage != 2)
221 fail_exit("Invalid stage argument");
222 break;
223 default:
224 fail_exit("Unknown argument");
225 }
226 }
227 return stage;
228}
229
230int luo_test(int argc, char *argv[],
231 const char *state_session_name,
232 luo_test_stage1_fn stage1,
233 luo_test_stage2_fn stage2)
234{
235 int target_stage = parse_stage_args(argc, argv);
236 int luo_fd = luo_open_device();
237 int state_session_fd;
238 int detected_stage;
239
240 if (luo_fd < 0) {
241 ksft_exit_skip("Failed to open %s. Is the luo module loaded?\n",
242 LUO_DEVICE);
243 }
244
245 state_session_fd = luo_retrieve_session(luo_fd, state_session_name);
246 if (state_session_fd == -ENOENT)
247 detected_stage = 1;
248 else if (state_session_fd >= 0)
249 detected_stage = 2;
250 else
251 fail_exit("Failed to check for state session");
252
253 if (target_stage != detected_stage) {
254 ksft_exit_fail_msg("Stage mismatch Requested --stage %d, but system is in stage %d.\n"
255 "(State session %s: %s)\n",
256 target_stage, detected_stage, state_session_name,
257 (detected_stage == 2) ? "EXISTS" : "MISSING");
258 }
259
260 if (target_stage == 1)
261 stage1(luo_fd);
262 else
263 stage2(luo_fd, state_session_fd);
264
265 return 0;
266}
tools/testing/selftests/liveupdate/luo_test_utils.h+44−0
@@ -0,0 +1,44 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 *
7 * Utility functions for LUO kselftests.
8 */
9
10#ifndef LUO_TEST_UTILS_H
11#define LUO_TEST_UTILS_H
12
13#include <errno.h>
14#include <string.h>
15#include <linux/liveupdate.h>
16#include "../kselftest.h"
17
18#define LUO_DEVICE "/dev/liveupdate"
19
20#define fail_exit(fmt, ...) \
21 ksft_exit_fail_msg("[%s:%d] " fmt " (errno: %s)\n", \
22 __func__, __LINE__, ##__VA_ARGS__, strerror(errno))
23
24int luo_open_device(void);
25int luo_create_session(int luo_fd, const char *name);
26int luo_retrieve_session(int luo_fd, const char *name);
27int luo_session_finish(int session_fd);
28
29int create_and_preserve_memfd(int session_fd, int token, const char *data);
30int restore_and_verify_memfd(int session_fd, int token, const char *expected_data);
31
32void create_state_file(int luo_fd, const char *session_name, int token,
33 int next_stage);
34void restore_and_read_stage(int state_session_fd, int token, int *stage);
35
36void daemonize_and_wait(void);
37
38typedef void (*luo_test_stage1_fn)(int luo_fd);
39typedef void (*luo_test_stage2_fn)(int luo_fd, int state_session_fd);
40
41int luo_test(int argc, char *argv[], const char *state_session_name,
42 luo_test_stage1_fn stage1, luo_test_stage2_fn stage2);
43
44#endif /* LUO_TEST_UTILS_H */
tools/testing/selftests/lsm/lsm_get_self_attr_test.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <stdio.h>13#include <stdio.h>
14#include <unistd.h>14#include <unistd.h>
15#include <sys/types.h>15#include <sys/types.h>
16#include "../kselftest_harness.h"16#include "kselftest_harness.h"
17#include "common.h"17#include "common.h"
18 18
19static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp)19static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp)
tools/testing/selftests/lsm/lsm_list_modules_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <stdio.h>12#include <stdio.h>
13#include <unistd.h>13#include <unistd.h>
14#include <sys/types.h>14#include <sys/types.h>
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16#include "common.h"16#include "common.h"
17 17
18TEST(size_null_lsm_list_modules)18TEST(size_null_lsm_list_modules)
tools/testing/selftests/lsm/lsm_set_self_attr_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <stdio.h>12#include <stdio.h>
13#include <unistd.h>13#include <unistd.h>
14#include <sys/types.h>14#include <sys/types.h>
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16#include "common.h"16#include "common.h"
17 17
18TEST(ctx_null_lsm_set_self_attr)18TEST(ctx_null_lsm_set_self_attr)
tools/testing/selftests/media_tests/media_device_open.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <sys/stat.h>34#include <sys/stat.h>
35#include <linux/media.h>35#include <linux/media.h>
36 36
37#include "../kselftest.h"37#include "kselftest.h"
38 38
39int main(int argc, char **argv)39int main(int argc, char **argv)
40{40{
tools/testing/selftests/media_tests/media_device_test.c+1−1
@@ -39,7 +39,7 @@ · 38 unmodified lines
39#include <time.h>39#include <time.h>
40#include <linux/media.h>40#include <linux/media.h>
41 41
42#include "../kselftest.h"42#include "kselftest.h"
43 43
44int main(int argc, char **argv)44int main(int argc, char **argv)
45{45{
tools/testing/selftests/membarrier/membarrier_test_impl.h+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <string.h>7#include <string.h>
8#include <pthread.h>8#include <pthread.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12static int registrations;12static int registrations;
13 13
tools/testing/selftests/mincore/mincore_selftest.c+2−2
@@ -15,8 +15,8 @@ · 14 unmodified lines
15#include <string.h>15#include <string.h>
16#include <fcntl.h>16#include <fcntl.h>
17 17
18#include "../kselftest.h"18#include "kselftest.h"
19#include "../kselftest_harness.h"19#include "kselftest_harness.h"
20 20
21/* Default test file size: 4MB */21/* Default test file size: 4MB */
22#define MB (1UL << 20)22#define MB (1UL << 20)
tools/testing/selftests/mm/compaction_test.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <unistd.h>16#include <unistd.h>
17#include <string.h>17#include <string.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21#define MAP_SIZE_MB 10021#define MAP_SIZE_MB 100
22#define MAP_SIZE (MAP_SIZE_MB * 1024 * 1024)22#define MAP_SIZE (MAP_SIZE_MB * 1024 * 1024)
tools/testing/selftests/mm/cow.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27#endif /* LOCAL_CONFIG_HAVE_LIBURING */27#endif /* LOCAL_CONFIG_HAVE_LIBURING */
28 28
29#include "../../../../mm/gup_test.h"29#include "../../../../mm/gup_test.h"
30#include "../kselftest.h"30#include "kselftest.h"
31#include "vm_util.h"31#include "vm_util.h"
32#include "thp_settings.h"32#include "thp_settings.h"
33 33
tools/testing/selftests/mm/droppable.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <sys/mman.h>13#include <sys/mman.h>
14#include <linux/mman.h>14#include <linux/mman.h>
15 15
16#include "../kselftest.h"16#include "kselftest.h"
17 17
18int main(int argc, char *argv[])18int main(int argc, char *argv[])
19{19{
tools/testing/selftests/mm/guard-regions.c+1−1
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0-or-later1// SPDX-License-Identifier: GPL-2.0-or-later
2 2
3#define _GNU_SOURCE3#define _GNU_SOURCE
4#include "../kselftest_harness.h"4#include "kselftest_harness.h"
5#include <asm-generic/mman.h> /* Force the import of the tools version. */5#include <asm-generic/mman.h> /* Force the import of the tools version. */
6#include <assert.h>6#include <assert.h>
7#include <errno.h>7#include <errno.h>
tools/testing/selftests/mm/gup_longterm.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27#endif /* LOCAL_CONFIG_HAVE_LIBURING */27#endif /* LOCAL_CONFIG_HAVE_LIBURING */
28 28
29#include "../../../../mm/gup_test.h"29#include "../../../../mm/gup_test.h"
30#include "../kselftest.h"30#include "kselftest.h"
31#include "vm_util.h"31#include "vm_util.h"
32 32
33static size_t pagesize;33static size_t pagesize;
tools/testing/selftests/mm/gup_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <pthread.h>12#include <pthread.h>
13#include <assert.h>13#include <assert.h>
14#include <mm/gup_test.h>14#include <mm/gup_test.h>
15#include "../kselftest.h"15#include "kselftest.h"
16#include "vm_util.h"16#include "vm_util.h"
17 17
18#define MB (1UL << 20)18#define MB (1UL << 20)
tools/testing/selftests/mm/hmm-tests.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10 * bugs.10 * bugs.
11 */11 */
12 12
13#include "../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15#include <errno.h>15#include <errno.h>
16#include <fcntl.h>16#include <fcntl.h>
tools/testing/selftests/mm/hugepage-mmap.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <unistd.h>15#include <unistd.h>
16#include <sys/mman.h>16#include <sys/mman.h>
17#include <fcntl.h>17#include <fcntl.h>
18#include "../kselftest.h"18#include "kselftest.h"
19 19
20#define LENGTH (256UL*1024*1024)20#define LENGTH (256UL*1024*1024)
21#define PROTECTION (PROT_READ | PROT_WRITE)21#define PROTECTION (PROT_READ | PROT_WRITE)
tools/testing/selftests/mm/hugepage-mremap.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <sys/ioctl.h>24#include <sys/ioctl.h>
25#include <string.h>25#include <string.h>
26#include <stdbool.h>26#include <stdbool.h>
27#include "../kselftest.h"27#include "kselftest.h"
28#include "vm_util.h"28#include "vm_util.h"
29 29
30#define DEFAULT_LENGTH_MB 10UL30#define DEFAULT_LENGTH_MB 10UL
tools/testing/selftests/mm/hugetlb-madvise.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <sys/mman.h>19#include <sys/mman.h>
20#include <fcntl.h>20#include <fcntl.h>
21#include "vm_util.h"21#include "vm_util.h"
22#include "../kselftest.h"22#include "kselftest.h"
23 23
24#define MIN_FREE_PAGES 2024#define MIN_FREE_PAGES 20
25#define NR_HUGE_PAGES 10 /* common number of pages to map/allocate */25#define NR_HUGE_PAGES 10 /* common number of pages to map/allocate */
tools/testing/selftests/mm/hugetlb-read-hwpoison.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <errno.h>11#include <errno.h>
12#include <stdbool.h>12#include <stdbool.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15 15
16#define PREFIX " ... "16#define PREFIX " ... "
17#define ERROR_PREFIX " !!! "17#define ERROR_PREFIX " !!! "
tools/testing/selftests/mm/hugetlb-soft-offline.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <sys/statfs.h>24#include <sys/statfs.h>
25#include <sys/types.h>25#include <sys/types.h>
26 26
27#include "../kselftest.h"27#include "kselftest.h"
28 28
29#ifndef MADV_SOFT_OFFLINE29#ifndef MADV_SOFT_OFFLINE
30#define MADV_SOFT_OFFLINE 10130#define MADV_SOFT_OFFLINE 101
tools/testing/selftests/mm/hugetlb_dio.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <string.h>18#include <string.h>
19#include <sys/mman.h>19#include <sys/mman.h>
20#include "vm_util.h"20#include "vm_util.h"
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off)23void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off)
24{24{
tools/testing/selftests/mm/hugetlb_fault_after_madv.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <signal.h>9#include <signal.h>
10 10
11#include "vm_util.h"11#include "vm_util.h"
12#include "../kselftest.h"12#include "kselftest.h"
13 13
14#define INLOOP_ITER 10014#define INLOOP_ITER 100
15 15
tools/testing/selftests/mm/hugetlb_madv_vs_map.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <unistd.h>25#include <unistd.h>
26 26
27#include "vm_util.h"27#include "vm_util.h"
28#include "../kselftest.h"28#include "kselftest.h"
29 29
30#define INLOOP_ITER 10030#define INLOOP_ITER 100
31 31
tools/testing/selftests/mm/ksm_functional_tests.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <sys/wait.h>21#include <sys/wait.h>
22#include <linux/userfaultfd.h>22#include <linux/userfaultfd.h>
23 23
24#include "../kselftest.h"24#include "kselftest.h"
25#include "vm_util.h"25#include "vm_util.h"
26 26
27#define KiB 1024u27#define KiB 1024u
tools/testing/selftests/mm/ksm_tests.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <stdint.h>12#include <stdint.h>
13#include <err.h>13#include <err.h>
14 14
15#include "../kselftest.h"15#include "kselftest.h"
16#include <include/vdso/time64.h>16#include <include/vdso/time64.h>
17#include "vm_util.h"17#include "vm_util.h"
18#include "thp_settings.h"18#include "thp_settings.h"
tools/testing/selftests/mm/madv_populate.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <linux/mman.h>17#include <linux/mman.h>
18#include <sys/mman.h>18#include <sys/mman.h>
19 19
20#include "../kselftest.h"20#include "kselftest.h"
21#include "vm_util.h"21#include "vm_util.h"
22 22
23/*23/*
tools/testing/selftests/mm/map_fixed_noreplace.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <stdio.h>12#include <stdio.h>
13#include <stdlib.h>13#include <stdlib.h>
14#include <unistd.h>14#include <unistd.h>
15#include "../kselftest.h"15#include "kselftest.h"
16 16
17static void dump_maps(void)17static void dump_maps(void)
18{18{
tools/testing/selftests/mm/map_hugetlb.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <sys/mman.h>11#include <sys/mman.h>
12#include <fcntl.h>12#include <fcntl.h>
13#include "vm_util.h"13#include "vm_util.h"
14#include "../kselftest.h"14#include "kselftest.h"
15 15
16#define LENGTH (256UL*1024*1024)16#define LENGTH (256UL*1024*1024)
17#define PROTECTION (PROT_READ | PROT_WRITE)17#define PROTECTION (PROT_READ | PROT_WRITE)
tools/testing/selftests/mm/map_populate.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <stdlib.h>16#include <stdlib.h>
17#include <string.h>17#include <string.h>
18#include <unistd.h>18#include <unistd.h>
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21#include "vm_util.h"21#include "vm_util.h"
22 22
tools/testing/selftests/mm/mdwe_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/wait.h>14#include <sys/wait.h>
15#include <unistd.h>15#include <unistd.h>
16 16
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#ifndef __aarch64__19#ifndef __aarch64__
20# define PROT_BTI 020# define PROT_BTI 0
tools/testing/selftests/mm/memfd_secret.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <stdio.h>22#include <stdio.h>
23#include <fcntl.h>23#include <fcntl.h>
24 24
25#include "../kselftest.h"25#include "kselftest.h"
26 26
27#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__)27#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__)
28#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__)28#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__)
tools/testing/selftests/mm/merge.c+1−1
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0-or-later1// SPDX-License-Identifier: GPL-2.0-or-later
2 2
3#define _GNU_SOURCE3#define _GNU_SOURCE
4#include "../kselftest_harness.h"4#include "kselftest_harness.h"
5#include <linux/prctl.h>5#include <linux/prctl.h>
6#include <fcntl.h>6#include <fcntl.h>
7#include <stdio.h>7#include <stdio.h>
tools/testing/selftests/mm/migration.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 * paths in the kernel.4 * paths in the kernel.
5 */5 */
6 6
7#include "../kselftest_harness.h"7#include "kselftest_harness.h"
8#include "thp_settings.h"8#include "thp_settings.h"
9 9
10#include <strings.h>10#include <strings.h>
tools/testing/selftests/mm/mkdirty.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <linux/userfaultfd.h>22#include <linux/userfaultfd.h>
23#include <linux/mempolicy.h>23#include <linux/mempolicy.h>
24 24
25#include "../kselftest.h"25#include "kselftest.h"
26#include "vm_util.h"26#include "vm_util.h"
27 27
28static size_t pagesize;28static size_t pagesize;
tools/testing/selftests/mm/mlock-random-test.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <sys/ipc.h>13#include <sys/ipc.h>
14#include <sys/shm.h>14#include <sys/shm.h>
15#include <time.h>15#include <time.h>
16#include "../kselftest.h"16#include "kselftest.h"
17#include "mlock2.h"17#include "mlock2.h"
18 18
19#define CHUNK_UNIT (128 * 1024)19#define CHUNK_UNIT (128 * 1024)
tools/testing/selftests/mm/mlock2-tests.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/time.h>7#include <sys/time.h>
8#include <sys/resource.h>8#include <sys/resource.h>
9#include <stdbool.h>9#include <stdbool.h>
10#include "../kselftest.h"10#include "kselftest.h"
11#include "mlock2.h"11#include "mlock2.h"
12 12
13struct vm_boundaries {13struct vm_boundaries {
tools/testing/selftests/mm/mrelease_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <unistd.h>12#include <unistd.h>
13#include <asm-generic/unistd.h>13#include <asm-generic/unistd.h>
14#include "vm_util.h"14#include "vm_util.h"
15#include "../kselftest.h"15#include "kselftest.h"
16 16
17#define MB(x) (x << 20)17#define MB(x) (x << 20)
18#define MAX_SIZE_MB 102418#define MAX_SIZE_MB 1024
tools/testing/selftests/mm/mremap_dontunmap.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <string.h>14#include <string.h>
15#include <unistd.h>15#include <unistd.h>
16 16
17#include "../kselftest.h"17#include "kselftest.h"
18 18
19unsigned long page_size;19unsigned long page_size;
20char *page_buffer;20char *page_buffer;
tools/testing/selftests/mm/mremap_test.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <time.h>16#include <time.h>
17#include <stdbool.h>17#include <stdbool.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21#define EXPECT_SUCCESS 021#define EXPECT_SUCCESS 0
22#define EXPECT_FAILURE 122#define EXPECT_FAILURE 1
tools/testing/selftests/mm/mseal_test.c+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
8#include <sys/time.h>8#include <sys/time.h>
9#include <sys/resource.h>9#include <sys/resource.h>
10#include <stdbool.h>10#include <stdbool.h>
11#include "../kselftest.h"11#include "kselftest.h"
12#include <syscall.h>12#include <syscall.h>
13#include <errno.h>13#include <errno.h>
14#include <stdio.h>14#include <stdio.h>
tools/testing/selftests/mm/on-fault-limit.c+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
5#include <string.h>5#include <string.h>
6#include <sys/time.h>6#include <sys/time.h>
7#include <sys/resource.h>7#include <sys/resource.h>
8#include "../kselftest.h"8#include "kselftest.h"
9 9
10static void test_limit(void)10static void test_limit(void)
11{11{
tools/testing/selftests/mm/pagemap_ioctl.c+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
8#include <errno.h>8#include <errno.h>
9#include <malloc.h>9#include <malloc.h>
10#include "vm_util.h"10#include "vm_util.h"
11#include "../kselftest.h"11#include "kselftest.h"
12#include <linux/types.h>12#include <linux/types.h>
13#include <linux/memfd.h>13#include <linux/memfd.h>
14#include <linux/userfaultfd.h>14#include <linux/userfaultfd.h>
tools/testing/selftests/mm/pfnmap.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <sys/mman.h>22#include <sys/mman.h>
23#include <sys/wait.h>23#include <sys/wait.h>
24 24
25#include "../kselftest_harness.h"25#include "kselftest_harness.h"
26#include "vm_util.h"26#include "vm_util.h"
27 27
28static sigjmp_buf sigjmp_buf_env;28static sigjmp_buf sigjmp_buf_env;
tools/testing/selftests/mm/pkey-helpers.h+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <linux/mman.h>16#include <linux/mman.h>
17#include <linux/types.h>17#include <linux/types.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21/* Define some kernel-like types */21/* Define some kernel-like types */
22typedef __u8 u8;22typedef __u8 u8;
tools/testing/selftests/mm/prctl_thp_disable.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <sys/prctl.h>13#include <sys/prctl.h>
14#include <sys/wait.h>14#include <sys/wait.h>
15 15
16#include "../kselftest_harness.h"16#include "kselftest_harness.h"
17#include "thp_settings.h"17#include "thp_settings.h"
18#include "vm_util.h"18#include "vm_util.h"
19 19
tools/testing/selftests/mm/process_madv.c+1−1
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0-or-later1// SPDX-License-Identifier: GPL-2.0-or-later
2 2
3#define _GNU_SOURCE3#define _GNU_SOURCE
4#include "../kselftest_harness.h"4#include "kselftest_harness.h"
5#include <errno.h>5#include <errno.h>
6#include <setjmp.h>6#include <setjmp.h>
7#include <signal.h>7#include <signal.h>
tools/testing/selftests/mm/rmap.c+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
5 * Author(s): Wei Yang <richard.weiyang@gmail.com>5 * Author(s): Wei Yang <richard.weiyang@gmail.com>
6 */6 */
7 7
8#include "../kselftest_harness.h"8#include "kselftest_harness.h"
9#include <strings.h>9#include <strings.h>
10#include <pthread.h>10#include <pthread.h>
11#include <numa.h>11#include <numa.h>
tools/testing/selftests/mm/soft-dirty.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <malloc.h>7#include <malloc.h>
8#include <sys/mman.h>8#include <sys/mman.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11#include "vm_util.h"11#include "vm_util.h"
12#include "thp_settings.h"12#include "thp_settings.h"
13 13
tools/testing/selftests/mm/split_huge_page_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <stdbool.h>20#include <stdbool.h>
21#include <time.h>21#include <time.h>
22#include "vm_util.h"22#include "vm_util.h"
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25uint64_t pagesize;25uint64_t pagesize;
26unsigned int pageshift;26unsigned int pageshift;
tools/testing/selftests/mm/thuge-gen.c+1−1
@@ -27,7 +27,7 @@ · 26 unmodified lines
27#include <stdarg.h>27#include <stdarg.h>
28#include <string.h>28#include <string.h>
29#include "vm_util.h"29#include "vm_util.h"
30#include "../kselftest.h"30#include "kselftest.h"
31 31
32#if !defined(MAP_HUGETLB)32#if !defined(MAP_HUGETLB)
33#define MAP_HUGETLB 0x4000033#define MAP_HUGETLB 0x40000
tools/testing/selftests/mm/transhuge-stress.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <string.h>16#include <string.h>
17#include <sys/mman.h>17#include <sys/mman.h>
18#include "vm_util.h"18#include "vm_util.h"
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21int backing_fd = -1;21int backing_fd = -1;
22int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE;22int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE;
tools/testing/selftests/mm/uffd-common.h+1−1
@@ -35,7 +35,7 @@ · 34 unmodified lines
35#include <sys/random.h>35#include <sys/random.h>
36#include <stdatomic.h>36#include <stdatomic.h>
37 37
38#include "../kselftest.h"38#include "kselftest.h"
39#include "vm_util.h"39#include "vm_util.h"
40 40
41#define UFFD_FLAGS (O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY)41#define UFFD_FLAGS (O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY)
tools/testing/selftests/mm/uffd-wp-mremap.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <assert.h>7#include <assert.h>
8#include <linux/mman.h>8#include <linux/mman.h>
9#include <sys/mman.h>9#include <sys/mman.h>
10#include "../kselftest.h"10#include "kselftest.h"
11#include "thp_settings.h"11#include "thp_settings.h"
12#include "uffd-common.h"12#include "uffd-common.h"
13 13
tools/testing/selftests/mm/va_high_addr_switch.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <string.h>10#include <string.h>
11 11
12#include "vm_util.h"12#include "vm_util.h"
13#include "../kselftest.h"13#include "kselftest.h"
14 14
15/*15/*
16 * The hint addr value is used to allocate addresses16 * The hint addr value is used to allocate addresses
tools/testing/selftests/mm/virtual_address_range.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <fcntl.h>16#include <fcntl.h>
17 17
18#include "vm_util.h"18#include "vm_util.h"
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21/*21/*
22 * Maximum address range mapped with a single mmap()22 * Maximum address range mapped with a single mmap()
tools/testing/selftests/mm/vm_util.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <linux/fs.h>9#include <linux/fs.h>
10#include <sys/syscall.h>10#include <sys/syscall.h>
11#include <unistd.h>11#include <unistd.h>
12#include "../kselftest.h"12#include "kselftest.h"
13#include "vm_util.h"13#include "vm_util.h"
14 14
15#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"15#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
tools/testing/selftests/mm/vm_util.h+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <stdarg.h>6#include <stdarg.h>
7#include <strings.h> /* ffsl() */7#include <strings.h> /* ffsl() */
8#include <unistd.h> /* _SC_PAGESIZE */8#include <unistd.h> /* _SC_PAGESIZE */
9#include "../kselftest.h"9#include "kselftest.h"
10#include <linux/fs.h>10#include <linux/fs.h>
11 11
12#define BIT_ULL(nr) (1ULL << (nr))12#define BIT_ULL(nr) (1ULL << (nr))
tools/testing/selftests/mount_setattr/mount_setattr_test.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <linux/mount.h>21#include <linux/mount.h>
22 22
23#include "../filesystems/wrappers.h"23#include "../filesystems/wrappers.h"
24#include "../kselftest_harness.h"24#include "kselftest_harness.h"
25 25
26#ifndef CLONE_NEWNS26#ifndef CLONE_NEWNS
27#define CLONE_NEWNS 0x0002000027#define CLONE_NEWNS 0x00020000
tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <stdarg.h>15#include <stdarg.h>
16#include <sys/syscall.h>16#include <sys/syscall.h>
17 17
18#include "../kselftest_harness.h"18#include "kselftest_harness.h"
19 19
20#ifndef CLONE_NEWNS20#ifndef CLONE_NEWNS
21#define CLONE_NEWNS 0x0002000021#define CLONE_NEWNS 0x00020000
tools/testing/selftests/mqueue/mq_open_tests.c+1−1
@@ -33,7 +33,7 @@ · 32 unmodified lines
33#include <mqueue.h>33#include <mqueue.h>
34#include <error.h>34#include <error.h>
35 35
36#include "../kselftest.h"36#include "kselftest.h"
37 37
38static char *usage =38static char *usage =
39"Usage:\n"39"Usage:\n"
tools/testing/selftests/mqueue/mq_perf_tests.c+1−1
@@ -40,7 +40,7 @@ · 39 unmodified lines
40#include <popt.h>40#include <popt.h>
41#include <error.h>41#include <error.h>
42 42
43#include "../kselftest.h"43#include "kselftest.h"
44 44
45static char *usage =45static char *usage =
46"Usage:\n"46"Usage:\n"
tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c+2−2
@@ -11,8 +11,8 @@ · 10 unmodified lines
11#include <string.h>11#include <string.h>
12#include <stdbool.h>12#include <stdbool.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17#define VMFLAGS "VmFlags:"17#define VMFLAGS "VmFlags:"
18#define MSEAL_FLAGS "sl"18#define MSEAL_FLAGS "sl"
tools/testing/selftests/namespaces/file_handle_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/wait.h>14#include <sys/wait.h>
15#include <unistd.h>15#include <unistd.h>
16#include <linux/unistd.h>16#include <linux/unistd.h>
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#ifndef FD_NSFS_ROOT19#ifndef FD_NSFS_ROOT
20#define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */20#define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */
tools/testing/selftests/namespaces/init_ino_test.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <string.h>11#include <string.h>
12#include <linux/nsfs.h>12#include <linux/nsfs.h>
13 13
14#include "../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16struct ns_info {16struct ns_info {
17 const char *name;17 const char *name;
tools/testing/selftests/namespaces/nsid_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <linux/fs.h>20#include <linux/fs.h>
21#include <linux/limits.h>21#include <linux/limits.h>
22#include <linux/nsfs.h>22#include <linux/nsfs.h>
23#include "../kselftest_harness.h"23#include "kselftest_harness.h"
24 24
25/* Fixture for tests that create child processes */25/* Fixture for tests that create child processes */
26FIXTURE(nsid) {26FIXTURE(nsid) {
tools/testing/selftests/nci/nci_dev.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/socket.h>16#include <sys/socket.h>
17#include <linux/nfc.h>17#include <linux/nfc.h>
18 18
19#include "../kselftest_harness.h"19#include "kselftest_harness.h"
20 20
21#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))21#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
22#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)22#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
tools/testing/selftests/net/af_unix/diag_uid.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/types.h>14#include <sys/types.h>
15#include <sys/un.h>15#include <sys/un.h>
16 16
17#include "../../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19FIXTURE(diag_uid)19FIXTURE(diag_uid)
20{20{
tools/testing/selftests/net/af_unix/msg_oob.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <sys/signalfd.h>11#include <sys/signalfd.h>
12#include <sys/socket.h>12#include <sys/socket.h>
13 13
14#include "../../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16#define BUF_SZ 3216#define BUF_SZ 32
17 17
tools/testing/selftests/net/af_unix/scm_inq.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <sys/socket.h>6#include <sys/socket.h>
7#include <sys/types.h>7#include <sys/types.h>
8 8
9#include "../../kselftest_harness.h"9#include "kselftest_harness.h"
10 10
11#define NR_CHUNKS 10011#define NR_CHUNKS 100
12#define MSG_LEN 25612#define MSG_LEN 256
tools/testing/selftests/net/af_unix/scm_pidfd.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/wait.h>16#include <sys/wait.h>
17 17
18#include "../../pidfd/pidfd.h"18#include "../../pidfd/pidfd.h"
19#include "../../kselftest_harness.h"19#include "kselftest_harness.h"
20 20
21#define clean_errno() (errno == 0 ? "None" : strerror(errno))21#define clean_errno() (errno == 0 ? "None" : strerror(errno))
22#define log_err(MSG, ...) \22#define log_err(MSG, ...) \
tools/testing/selftests/net/af_unix/scm_rights.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <sys/socket.h>10#include <sys/socket.h>
11#include <sys/un.h>11#include <sys/un.h>
12 12
13#include "../../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15FIXTURE(scm_rights)15FIXTURE(scm_rights)
16{16{
tools/testing/selftests/net/af_unix/unix_connect.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <sys/socket.h>10#include <sys/socket.h>
11#include <sys/un.h>11#include <sys/un.h>
12 12
13#include "../../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15FIXTURE(unix_connect)15FIXTURE(unix_connect)
16{16{
tools/testing/selftests/net/bind_timewait.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4#include <sys/socket.h>4#include <sys/socket.h>
5#include <netinet/in.h>5#include <netinet/in.h>
6 6
7#include "../kselftest_harness.h"7#include "kselftest_harness.h"
8 8
9FIXTURE(bind_timewait)9FIXTURE(bind_timewait)
10{10{
tools/testing/selftests/net/bind_wildcard.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4#include <sys/socket.h>4#include <sys/socket.h>
5#include <netinet/in.h>5#include <netinet/in.h>
6 6
7#include "../kselftest_harness.h"7#include "kselftest_harness.h"
8 8
9static const __u32 in4addr_any = INADDR_ANY;9static const __u32 in4addr_any = INADDR_ANY;
10static const __u32 in4addr_loopback = INADDR_LOOPBACK;10static const __u32 in4addr_loopback = INADDR_LOOPBACK;
tools/testing/selftests/net/can/test_raw_filter.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <linux/can.h>19#include <linux/can.h>
20#include <linux/can/raw.h>20#include <linux/can/raw.h>
21 21
22#include "../../kselftest_harness.h"22#include "kselftest_harness.h"
23 23
24#define ID 0x12324#define ID 0x123
25 25
tools/testing/selftests/net/cmsg_sender.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <linux/udp.h>16#include <linux/udp.h>
17#include <sys/socket.h>17#include <sys/socket.h>
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21enum {21enum {
22 ERN_SUCCESS = 0,22 ERN_SUCCESS = 0,
tools/testing/selftests/net/epoll_busy_poll.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <sys/ioctl.h>23#include <sys/ioctl.h>
24#include <sys/socket.h>24#include <sys/socket.h>
25 25
26#include "../kselftest_harness.h"26#include "kselftest_harness.h"
27 27
28/* if the headers haven't been updated, we need to define some things */28/* if the headers haven't been updated, we need to define some things */
29#if !defined(EPOLL_IOC_TYPE)29#if !defined(EPOLL_IOC_TYPE)
tools/testing/selftests/net/ip_local_port_range.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <fcntl.h>10#include <fcntl.h>
11#include <netinet/ip.h>11#include <netinet/ip.h>
12 12
13#include "../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15#ifndef IP_LOCAL_PORT_RANGE15#ifndef IP_LOCAL_PORT_RANGE
16#define IP_LOCAL_PORT_RANGE 5116#define IP_LOCAL_PORT_RANGE 51
tools/testing/selftests/net/ipsec.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <time.h>34#include <time.h>
35#include <unistd.h>35#include <unistd.h>
36 36
37#include "../kselftest.h"37#include "kselftest.h"
38 38
39#define printk(fmt, ...) \39#define printk(fmt, ...) \
40 ksft_print_msg("%d[%u] " fmt "\n", getpid(), __LINE__, ##__VA_ARGS__)40 ksft_print_msg("%d[%u] " fmt "\n", getpid(), __LINE__, ##__VA_ARGS__)
tools/testing/selftests/net/ipv6_fragmentation.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <sys/ioctl.h>34#include <sys/ioctl.h>
35#include <sys/socket.h>35#include <sys/socket.h>
36#include <unistd.h>36#include <unistd.h>
37#include "../kselftest.h"37#include "kselftest.h"
38 38
39#define MTU 150039#define MTU 1500
40#define LARGER_THAN_MTU 819240#define LARGER_THAN_MTU 8192
tools/testing/selftests/net/netfilter/conntrack_dump_flush.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <linux/netfilter/nfnetlink.h>10#include <linux/netfilter/nfnetlink.h>
11#include <linux/netfilter/nfnetlink_conntrack.h>11#include <linux/netfilter/nfnetlink_conntrack.h>
12#include <linux/netfilter/nf_conntrack_tcp.h>12#include <linux/netfilter/nf_conntrack_tcp.h>
13#include "../../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15#define TEST_ZONE_ID 12315#define TEST_ZONE_ID 123
16#define NF_CT_DEFAULT_ZONE_ID 016#define NF_CT_DEFAULT_ZONE_ID 0
tools/testing/selftests/net/netlink-dumps.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <linux/mqueue.h>18#include <linux/mqueue.h>
19#include <linux/rtnetlink.h>19#include <linux/rtnetlink.h>
20 20
21#include "../kselftest_harness.h"21#include "kselftest_harness.h"
22 22
23#include <ynl.h>23#include <ynl.h>
24 24
tools/testing/selftests/net/ovpn/ovpn-cli.c+1−1
@@ -32,7 +32,7 @@ · 31 unmodified lines
32 32
33#include <sys/socket.h>33#include <sys/socket.h>
34 34
35#include "../../kselftest.h"35#include "kselftest.h"
36 36
37/* defines to make checkpatch happy */37/* defines to make checkpatch happy */
38#define strscpy strncpy38#define strscpy strncpy
tools/testing/selftests/net/proc_net_pktgen.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <stdlib.h>10#include <stdlib.h>
11#include <unistd.h>11#include <unistd.h>
12 12
13#include "../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15static const char ctrl_cmd_stop[] = "stop";15static const char ctrl_cmd_stop[] = "stop";
16static const char ctrl_cmd_start[] = "start";16static const char ctrl_cmd_start[] = "start";
tools/testing/selftests/net/psock_fanout.c+1−1
@@ -54,7 +54,7 @@ · 53 unmodified lines
54#include <unistd.h>54#include <unistd.h>
55 55
56#include "psock_lib.h"56#include "psock_lib.h"
57#include "../kselftest.h"57#include "kselftest.h"
58 58
59#define RING_NUM_FRAMES 2059#define RING_NUM_FRAMES 20
60 60
tools/testing/selftests/net/psock_tpacket.c+1−1
@@ -46,7 +46,7 @@ · 45 unmodified lines
46 46
47#include "psock_lib.h"47#include "psock_lib.h"
48 48
49#include "../kselftest.h"49#include "kselftest.h"
50 50
51#ifndef bug_on51#ifndef bug_on
52# define bug_on(cond) assert(!(cond))52# define bug_on(cond) assert(!(cond))
tools/testing/selftests/net/reuseaddr_ports_exhausted.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <sys/socket.h>22#include <sys/socket.h>
23#include <sys/types.h>23#include <sys/types.h>
24#include <unistd.h>24#include <unistd.h>
25#include "../kselftest_harness.h"25#include "kselftest_harness.h"
26 26
27struct reuse_opts {27struct reuse_opts {
28 int reuseaddr[2];28 int reuseaddr[2];
tools/testing/selftests/net/reuseport_bpf.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <sys/resource.h>24#include <sys/resource.h>
25#include <unistd.h>25#include <unistd.h>
26 26
27#include "../kselftest.h"27#include "kselftest.h"
28 28
29struct test_params {29struct test_params {
30 int recv_family;30 int recv_family;
tools/testing/selftests/net/reuseport_bpf_numa.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <unistd.h>23#include <unistd.h>
24#include <numa.h>24#include <numa.h>
25 25
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28static const int PORT = 8888;28static const int PORT = 8888;
29 29
tools/testing/selftests/net/rxtimestamp.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <linux/net_tstamp.h>18#include <linux/net_tstamp.h>
19#include <linux/errqueue.h>19#include <linux/errqueue.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23struct options {23struct options {
24 int so_timestamp;24 int so_timestamp;
tools/testing/selftests/net/sk_so_peek_off.c+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
8#include <sys/types.h>8#include <sys/types.h>
9#include <netinet/in.h>9#include <netinet/in.h>
10#include <arpa/inet.h>10#include <arpa/inet.h>
11#include "../kselftest.h"11#include "kselftest.h"
12 12
13static char *afstr(int af, int proto)13static char *afstr(int af, int proto)
14{14{
tools/testing/selftests/net/so_incoming_cpu.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <sys/socket.h>9#include <sys/socket.h>
10#include <sys/sysinfo.h>10#include <sys/sysinfo.h>
11 11
12#include "../kselftest_harness.h"12#include "kselftest_harness.h"
13 13
14FIXTURE(so_incoming_cpu)14FIXTURE(so_incoming_cpu)
15{15{
tools/testing/selftests/net/socket.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/socket.h>7#include <sys/socket.h>
8#include <netinet/in.h>8#include <netinet/in.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12struct socket_testcase {12struct socket_testcase {
13 int domain;13 int domain;
tools/testing/selftests/net/tap.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <linux/virtio_net.h>17#include <linux/virtio_net.h>
18#include <netinet/ip.h>18#include <netinet/ip.h>
19#include <netinet/udp.h>19#include <netinet/udp.h>
20#include "../kselftest_harness.h"20#include "kselftest_harness.h"
21 21
22static const char param_dev_tap_name[] = "xmacvtap0";22static const char param_dev_tap_name[] = "xmacvtap0";
23static const char param_dev_dummy_name[] = "xdummy0";23static const char param_dev_dummy_name[] = "xdummy0";
tools/testing/selftests/net/tcp_ao/lib/setup.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9 * Can't be included in the header: it defines static variables which9 * Can't be included in the header: it defines static variables which
10 * will be unique to every object. Let's include it only once here.10 * will be unique to every object. Let's include it only once here.
11 */11 */
12#include "../../../kselftest.h"12#include "kselftest.h"
13 13
14/* Prevent overriding of one thread's output by another */14/* Prevent overriding of one thread's output by another */
15static pthread_mutex_t ksft_print_lock = PTHREAD_MUTEX_INITIALIZER;15static pthread_mutex_t ksft_print_lock = PTHREAD_MUTEX_INITIALIZER;
tools/testing/selftests/net/tcp_fastopen_backup_key.c+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#include <fcntl.h>26#include <fcntl.h>
27#include <time.h>27#include <time.h>
28 28
29#include "../kselftest.h"29#include "kselftest.h"
30 30
31#ifndef TCP_FASTOPEN_KEY31#ifndef TCP_FASTOPEN_KEY
32#define TCP_FASTOPEN_KEY 3332#define TCP_FASTOPEN_KEY 33
tools/testing/selftests/net/tcp_port_share.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <sched.h>10#include <sched.h>
11#include <stdlib.h>11#include <stdlib.h>
12 12
13#include "../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15#define DST_PORT 3000015#define DST_PORT 30000
16#define SRC_PORT 4000016#define SRC_PORT 40000
tools/testing/selftests/net/tls.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <sys/socket.h>21#include <sys/socket.h>
22#include <sys/stat.h>22#include <sys/stat.h>
23 23
24#include "../kselftest_harness.h"24#include "kselftest_harness.h"
25 25
26#define TLS_PAYLOAD_MAX_LEN 1638426#define TLS_PAYLOAD_MAX_LEN 16384
27#define SOL_TLS 28227#define SOL_TLS 282
tools/testing/selftests/net/tun.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <sys/ioctl.h>15#include <sys/ioctl.h>
16#include <sys/socket.h>16#include <sys/socket.h>
17 17
18#include "../kselftest_harness.h"18#include "kselftest_harness.h"
19 19
20static int tun_attach(int fd, char *dev)20static int tun_attach(int fd, char *dev)
21{21{
tools/testing/selftests/net/udpgso_bench_tx.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <sys/types.h>25#include <sys/types.h>
26#include <unistd.h>26#include <unistd.h>
27 27
28#include "../kselftest.h"28#include "kselftest.h"
29 29
30#ifndef ETH_MAX_MTU30#ifndef ETH_MAX_MTU
31#define ETH_MAX_MTU 0xFFFFU31#define ETH_MAX_MTU 0xFFFFU
tools/testing/selftests/openat2/helpers.h+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12#include <stdbool.h>12#include <stdbool.h>
13#include <errno.h>13#include <errno.h>
14#include <linux/types.h>14#include <linux/types.h>
15#include "../kselftest.h"15#include "kselftest.h"
16 16
17#define ARRAY_LEN(X) (sizeof (X) / sizeof (*(X)))17#define ARRAY_LEN(X) (sizeof (X) / sizeof (*(X)))
18#define BUILD_BUG_ON(e) ((void)(sizeof(struct { int:(-!!(e)); })))18#define BUILD_BUG_ON(e) ((void)(sizeof(struct { int:(-!!(e)); })))
tools/testing/selftests/openat2/openat2_test.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <stdbool.h>15#include <stdbool.h>
16#include <string.h>16#include <string.h>
17 17
18#include "../kselftest.h"18#include "kselftest.h"
19#include "helpers.h"19#include "helpers.h"
20 20
21/*21/*
tools/testing/selftests/openat2/rename_attack_test.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <limits.h>22#include <limits.h>
23#include <unistd.h>23#include <unistd.h>
24 24
25#include "../kselftest.h"25#include "kselftest.h"
26#include "helpers.h"26#include "helpers.h"
27 27
28/* Construct a test directory with the following structure:28/* Construct a test directory with the following structure:
tools/testing/selftests/openat2/resolve_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <stdbool.h>14#include <stdbool.h>
15#include <string.h>15#include <string.h>
16 16
17#include "../kselftest.h"17#include "kselftest.h"
18#include "helpers.h"18#include "helpers.h"
19 19
20/*20/*
tools/testing/selftests/pci_endpoint/pci_endpoint_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20 20
21#include "../../../../include/uapi/linux/pcitest.h"21#include "../../../../include/uapi/linux/pcitest.h"
22 22
23#include "../kselftest_harness.h"23#include "kselftest_harness.h"
24 24
25#define pci_ep_ioctl(cmd, arg) \25#define pci_ep_ioctl(cmd, arg) \
26({ \26({ \
tools/testing/selftests/perf_events/mmap.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14 14
15#include <linux/perf_event.h>15#include <linux/perf_event.h>
16 16
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#define RB_SIZE 0x300019#define RB_SIZE 0x3000
20#define AUX_SIZE 0x1000020#define AUX_SIZE 0x10000
tools/testing/selftests/perf_events/remove_on_exec.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include <sys/syscall.h>30#include <sys/syscall.h>
31#include <unistd.h>31#include <unistd.h>
32 32
33#include "../kselftest_harness.h"33#include "kselftest_harness.h"
34 34
35static volatile int signal_count;35static volatile int signal_count;
36 36
tools/testing/selftests/perf_events/sigtrap_threads.c+1−1
@@ -31,7 +31,7 @@ · 30 unmodified lines
31#include <sys/syscall.h>31#include <sys/syscall.h>
32#include <unistd.h>32#include <unistd.h>
33 33
34#include "../kselftest_harness.h"34#include "kselftest_harness.h"
35 35
36#define NUM_THREADS 536#define NUM_THREADS 5
37 37
tools/testing/selftests/perf_events/watermark_signal.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <sys/wait.h>15#include <sys/wait.h>
16#include <unistd.h>16#include <unistd.h>
17 17
18#include "../kselftest_harness.h"18#include "kselftest_harness.h"
19 19
20static int sigio_count;20static int sigio_count;
21 21
tools/testing/selftests/pid_namespace/pid_max.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <sys/mount.h>13#include <sys/mount.h>
14#include <sys/wait.h>14#include <sys/wait.h>
15 15
16#include "../kselftest_harness.h"16#include "kselftest_harness.h"
17#include "../pidfd/pidfd.h"17#include "../pidfd/pidfd.h"
18 18
19#define __STACK_SIZE (8 * 1024 * 1024)19#define __STACK_SIZE (8 * 1024 * 1024)
tools/testing/selftests/pid_namespace/regression_enomem.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <syscall.h>11#include <syscall.h>
12#include <sys/wait.h>12#include <sys/wait.h>
13 13
14#include "../kselftest_harness.h"14#include "kselftest_harness.h"
15#include "../pidfd/pidfd.h"15#include "../pidfd/pidfd.h"
16 16
17/*17/*
tools/testing/selftests/pidfd/pidfd.h+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#undef SCHED_FLAG_KEEP_ALL25#undef SCHED_FLAG_KEEP_ALL
26#undef SCHED_FLAG_UTIL_CLAMP26#undef SCHED_FLAG_UTIL_CLAMP
27 27
28#include "../kselftest.h"28#include "kselftest.h"
29#include "../clone3/clone3_selftests.h"29#include "../clone3/clone3_selftests.h"
30 30
31#ifndef FD_PIDFS_ROOT31#ifndef FD_PIDFS_ROOT
tools/testing/selftests/pidfd/pidfd_bind_mount.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <unistd.h>14#include <unistd.h>
15 15
16#include "pidfd.h"16#include "pidfd.h"
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18#include "../filesystems/wrappers.h"18#include "../filesystems/wrappers.h"
19 19
20FIXTURE(pidfd_bind_mount) {20FIXTURE(pidfd_bind_mount) {
tools/testing/selftests/pidfd/pidfd_fdinfo_test.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/mount.h>16#include <sys/mount.h>
17 17
18#include "pidfd.h"18#include "pidfd.h"
19#include "../kselftest.h"19#include "kselftest.h"
20 20
21struct error {21struct error {
22 int code;22 int code;
tools/testing/selftests/pidfd/pidfd_file_handle_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <sys/stat.h>20#include <sys/stat.h>
21 21
22#include "pidfd.h"22#include "pidfd.h"
23#include "../kselftest_harness.h"23#include "kselftest_harness.h"
24 24
25FIXTURE(file_handle)25FIXTURE(file_handle)
26{26{
tools/testing/selftests/pidfd/pidfd_getfd_test.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <linux/kcmp.h>19#include <linux/kcmp.h>
20 20
21#include "pidfd.h"21#include "pidfd.h"
22#include "../kselftest_harness.h"22#include "kselftest_harness.h"
23 23
24/*24/*
25 * UNKNOWN_FD is an fd number that should never exist in the child, as it is25 * UNKNOWN_FD is an fd number that should never exist in the child, as it is
tools/testing/selftests/pidfd/pidfd_info_test.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <sys/stat.h>21#include <sys/stat.h>
22 22
23#include "pidfd.h"23#include "pidfd.h"
24#include "../kselftest_harness.h"24#include "kselftest_harness.h"
25 25
26FIXTURE(pidfd_info)26FIXTURE(pidfd_info)
27{27{
tools/testing/selftests/pidfd/pidfd_open_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <unistd.h>20#include <unistd.h>
21 21
22#include "pidfd.h"22#include "pidfd.h"
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25static int safe_int(const char *numstr, int *converted)25static int safe_int(const char *numstr, int *converted)
26{26{
tools/testing/selftests/pidfd/pidfd_poll_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <unistd.h>14#include <unistd.h>
15 15
16#include "pidfd.h"16#include "pidfd.h"
17#include "../kselftest.h"17#include "kselftest.h"
18 18
19static bool timeout;19static bool timeout;
20 20
tools/testing/selftests/pidfd/pidfd_setattr_test.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <sys/xattr.h>22#include <sys/xattr.h>
23 23
24#include "pidfd.h"24#include "pidfd.h"
25#include "../kselftest_harness.h"25#include "kselftest_harness.h"
26 26
27FIXTURE(pidfs_setattr)27FIXTURE(pidfs_setattr)
28{28{
tools/testing/selftests/pidfd/pidfd_setns_test.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <sys/stat.h>18#include <sys/stat.h>
19 19
20#include "pidfd.h"20#include "pidfd.h"
21#include "../kselftest_harness.h"21#include "kselftest_harness.h"
22 22
23enum {23enum {
24 PIDFD_NS_USER,24 PIDFD_NS_USER,
tools/testing/selftests/pidfd/pidfd_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <unistd.h>20#include <unistd.h>
21 21
22#include "pidfd.h"22#include "pidfd.h"
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25#define str(s) _str(s)25#define str(s) _str(s)
26#define _str(s) #s26#define _str(s) #s
tools/testing/selftests/pidfd/pidfd_wait.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <unistd.h>17#include <unistd.h>
18 18
19#include "pidfd.h"19#include "pidfd.h"
20#include "../kselftest_harness.h"20#include "kselftest_harness.h"
21 21
22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
23 23
tools/testing/selftests/pidfd/pidfd_xattr_test.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <sys/xattr.h>22#include <sys/xattr.h>
23 23
24#include "pidfd.h"24#include "pidfd.h"
25#include "../kselftest_harness.h"25#include "kselftest_harness.h"
26 26
27FIXTURE(pidfs_xattr)27FIXTURE(pidfs_xattr)
28{28{
tools/testing/selftests/prctl/set-anon-vma-name-test.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <sys/mman.h>10#include <sys/mman.h>
11#include <string.h>11#include <string.h>
12 12
13#include "../kselftest_harness.h"13#include "kselftest_harness.h"
14 14
15#define AREA_SIZE 102415#define AREA_SIZE 1024
16 16
tools/testing/selftests/prctl/set-process-name.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <sys/prctl.h>7#include <sys/prctl.h>
8#include <string.h>8#include <string.h>
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11 11
12#define CHANGE_NAME "changename"12#define CHANGE_NAME "changename"
13#define EMPTY_NAME ""13#define EMPTY_NAME ""
tools/testing/selftests/proc/proc-maps-race.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23 *23 *
24 */24 */
25#define _GNU_SOURCE25#define _GNU_SOURCE
26#include "../kselftest_harness.h"26#include "kselftest_harness.h"
27#include <errno.h>27#include <errno.h>
28#include <fcntl.h>28#include <fcntl.h>
29#include <pthread.h>29#include <pthread.h>
tools/testing/selftests/proc/proc-pid-vm.c+1−1
@@ -51,7 +51,7 @@ · 50 unmodified lines
51#define __maybe_unused __attribute__((__unused__))51#define __maybe_unused __attribute__((__unused__))
52#endif52#endif
53 53
54#include "../kselftest.h"54#include "kselftest.h"
55 55
56static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags)56static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags)
57{57{
tools/testing/selftests/proc/proc-pidns.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/stat.h>16#include <sys/stat.h>
17#include <sys/prctl.h>17#include <sys/prctl.h>
18 18
19#include "../kselftest_harness.h"19#include "kselftest_harness.h"
20 20
21#define ASSERT_ERRNO(expected, _t, seen) \21#define ASSERT_ERRNO(expected, _t, seen) \
22 __EXPECT(expected, #expected, \22 __EXPECT(expected, #expected, \
tools/testing/selftests/ptrace/get_set_sud.c+1−1
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2#define _GNU_SOURCE2#define _GNU_SOURCE
3#include "../kselftest_harness.h"3#include "kselftest_harness.h"
4#include <stdio.h>4#include <stdio.h>
5#include <string.h>5#include <string.h>
6#include <errno.h>6#include <errno.h>
tools/testing/selftests/ptrace/get_syscall_info.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 * matches userspace expectations.7 * matches userspace expectations.
8 */8 */
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11#include <err.h>11#include <err.h>
12#include <signal.h>12#include <signal.h>
13#include <asm/unistd.h>13#include <asm/unistd.h>
tools/testing/selftests/ptrace/set_syscall_info.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 * matches userspace expectations.7 * matches userspace expectations.
8 */8 */
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11#include <err.h>11#include <err.h>
12#include <fcntl.h>12#include <fcntl.h>
13#include <signal.h>13#include <signal.h>
tools/testing/selftests/ptrace/vmaccess.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 * when de_thread is blocked with ->cred_guard_mutex held.7 * when de_thread is blocked with ->cred_guard_mutex held.
8 */8 */
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11#include <stdio.h>11#include <stdio.h>
12#include <fcntl.h>12#include <fcntl.h>
13#include <pthread.h>13#include <pthread.h>
tools/testing/selftests/resctrl/resctrl.h+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <asm/unistd.h>23#include <asm/unistd.h>
24#include <linux/perf_event.h>24#include <linux/perf_event.h>
25#include <linux/compiler.h>25#include <linux/compiler.h>
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28#define MB (1024 * 1024)28#define MB (1024 * 1024)
29#define RESCTRL_PATH "/sys/fs/resctrl"29#define RESCTRL_PATH "/sys/fs/resctrl"
tools/testing/selftests/ring-buffer/map_test.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <sys/ioctl.h>17#include <sys/ioctl.h>
18 18
19#include "../user_events/user_events_selftests.h" /* share tracefs setup */19#include "../user_events/user_events_selftests.h" /* share tracefs setup */
20#include "../kselftest_harness.h"20#include "kselftest_harness.h"
21 21
22#define TRACEFS_ROOT "/sys/kernel/tracing"22#define TRACEFS_ROOT "/sys/kernel/tracing"
23 23
tools/testing/selftests/riscv/abi/pointer_masking.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <sys/wait.h>9#include <sys/wait.h>
10#include <unistd.h>10#include <unistd.h>
11 11
12#include "../../kselftest.h"12#include "kselftest.h"
13 13
14#ifndef PR_PMLEN_SHIFT14#ifndef PR_PMLEN_SHIFT
15#define PR_PMLEN_SHIFT 2415#define PR_PMLEN_SHIFT 24
tools/testing/selftests/riscv/hwprobe/cbo.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <getopt.h>18#include <getopt.h>
19 19
20#include "hwprobe.h"20#include "hwprobe.h"
21#include "../../kselftest.h"21#include "kselftest.h"
22 22
23#define MK_CBO(fn) le32_bswap((uint32_t)(fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15)23#define MK_CBO(fn) le32_bswap((uint32_t)(fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15)
24#define MK_PREFETCH(fn) \24#define MK_PREFETCH(fn) \
tools/testing/selftests/riscv/hwprobe/hwprobe.c+1−1
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.0-only1// SPDX-License-Identifier: GPL-2.0-only
2#include "hwprobe.h"2#include "hwprobe.h"
3#include "../../kselftest.h"3#include "kselftest.h"
4 4
5int main(int argc, char **argv)5int main(int argc, char **argv)
6{6{
tools/testing/selftests/riscv/hwprobe/which-cpus.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <assert.h>14#include <assert.h>
15 15
16#include "hwprobe.h"16#include "hwprobe.h"
17#include "../../kselftest.h"17#include "kselftest.h"
18 18
19static void help(void)19static void help(void)
20{20{
tools/testing/selftests/riscv/mm/mmap_bottomup.c+1−1
@@ -2,7 +2,7 @@ · 1 unmodified line
2#include <sys/mman.h>2#include <sys/mman.h>
3#include <mmap_test.h>3#include <mmap_test.h>
4 4
5#include "../../kselftest_harness.h"5#include "kselftest_harness.h"
6 6
7TEST(infinite_rlimit)7TEST(infinite_rlimit)
8{8{
tools/testing/selftests/riscv/mm/mmap_default.c+1−1
@@ -2,7 +2,7 @@ · 1 unmodified line
2#include <sys/mman.h>2#include <sys/mman.h>
3#include <mmap_test.h>3#include <mmap_test.h>
4 4
5#include "../../kselftest_harness.h"5#include "kselftest_harness.h"
6 6
7TEST(default_rlimit)7TEST(default_rlimit)
8{8{
tools/testing/selftests/riscv/mm/mmap_test.h+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
5#include <sys/resource.h>5#include <sys/resource.h>
6#include <stddef.h>6#include <stddef.h>
7#include <strings.h>7#include <strings.h>
8#include "../../kselftest_harness.h"8#include "kselftest_harness.h"
9 9
10#define TOP_DOWN 010#define TOP_DOWN 0
11#define BOTTOM_UP 111#define BOTTOM_UP 1
tools/testing/selftests/riscv/sigreturn/sigreturn.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4#include <stdlib.h>4#include <stdlib.h>
5#include <ucontext.h>5#include <ucontext.h>
6#include <linux/ptrace.h>6#include <linux/ptrace.h>
7#include "../../kselftest_harness.h"7#include "kselftest_harness.h"
8 8
9#define RISCV_V_MAGIC 0x534654579#define RISCV_V_MAGIC 0x53465457
10#define DEFAULT_VALUE 210#define DEFAULT_VALUE 2
tools/testing/selftests/riscv/vector/v_initval.c+1−1
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.0-only1// SPDX-License-Identifier: GPL-2.0-only
2 2
3#include "../../kselftest_harness.h"3#include "kselftest_harness.h"
4#include "v_helpers.h"4#include "v_helpers.h"
5 5
6#define NEXT_PROGRAM "./v_exec_initval_nolibc"6#define NEXT_PROGRAM "./v_exec_initval_nolibc"
tools/testing/selftests/riscv/vector/vstate_prctl.c+1−1
@@ -6,7 +6,7 @@ · 5 unmodified lines
6#include <sys/types.h>6#include <sys/types.h>
7#include <stdlib.h>7#include <stdlib.h>
8 8
9#include "../../kselftest_harness.h"9#include "kselftest_harness.h"
10#include "v_helpers.h"10#include "v_helpers.h"
11 11
12#define NEXT_PROGRAM "./vstate_exec_nolibc"12#define NEXT_PROGRAM "./vstate_exec_nolibc"
tools/testing/selftests/rseq/basic_percpu_ops_test.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <string.h>9#include <string.h>
10#include <stddef.h>10#include <stddef.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13#include "rseq.h"13#include "rseq.h"
14 14
15#ifdef BUILDOPT_RSEQ_PERCPU_MM_CID15#ifdef BUILDOPT_RSEQ_PERCPU_MM_CID
tools/testing/selftests/rseq/rseq.c+1−1
@@ -33,7 +33,7 @@ · 32 unmodified lines
33 33
34#include <linux/compiler.h>34#include <linux/compiler.h>
35 35
36#include "../kselftest.h"36#include "kselftest.h"
37#include "rseq.h"37#include "rseq.h"
38 38
39/*39/*
tools/testing/selftests/rtc/rtctest.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <time.h>16#include <time.h>
17#include <unistd.h>17#include <unistd.h>
18 18
19#include "../kselftest_harness.h"19#include "kselftest_harness.h"
20 20
21#define NUM_UIE 321#define NUM_UIE 3
22#define ALARM_DELTA 322#define ALARM_DELTA 3
tools/testing/selftests/seccomp/seccomp_benchmark.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <sys/syscall.h>20#include <sys/syscall.h>
21#include <sys/types.h>21#include <sys/types.h>
22 22
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25unsigned long long timing(clockid_t clk_id, unsigned long long samples)25unsigned long long timing(clockid_t clk_id, unsigned long long samples)
26{26{
tools/testing/selftests/seccomp/seccomp_bpf.c+1−1
@@ -54,7 +54,7 @@ · 53 unmodified lines
54#include <sys/syscall.h>54#include <sys/syscall.h>
55#include <poll.h>55#include <poll.h>
56 56
57#include "../kselftest_harness.h"57#include "kselftest_harness.h"
58#include "../clone3/clone3_selftests.h"58#include "../clone3/clone3_selftests.h"
59 59
60/* Attempt to de-conflict with the selftests tree. */60/* Attempt to de-conflict with the selftests tree. */
tools/testing/selftests/sgx/main.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <sys/types.h>18#include <sys/types.h>
19#include <sys/auxv.h>19#include <sys/auxv.h>
20#include "defines.h"20#include "defines.h"
21#include "../kselftest_harness.h"21#include "kselftest_harness.h"
22#include "main.h"22#include "main.h"
23 23
24static const uint64_t MAGIC = 0x1122334455667788ULL;24static const uint64_t MAGIC = 0x1122334455667788ULL;
tools/testing/selftests/signal/mangle_uc_sigmask.c+1−1
@@ -39,7 +39,7 @@ · 38 unmodified lines
39#include <signal.h>39#include <signal.h>
40#include <ucontext.h>40#include <ucontext.h>
41 41
42#include "../kselftest.h"42#include "kselftest.h"
43 43
44void handler_verify_ucontext(int signo, siginfo_t *info, void *uc)44void handler_verify_ucontext(int signo, siginfo_t *info, void *uc)
45{45{
tools/testing/selftests/signal/sas.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <errno.h>19#include <errno.h>
20#include <sys/auxv.h>20#include <sys/auxv.h>
21 21
22#include "../kselftest.h"22#include "kselftest.h"
23#include "current_stack_pointer.h"23#include "current_stack_pointer.h"
24 24
25#ifndef SS_AUTODISARM25#ifndef SS_AUTODISARM
tools/testing/selftests/sparc64/drivers/adi-test.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/stat.h>16#include <sys/stat.h>
17#include <unistd.h>17#include <unistd.h>
18 18
19#include "../../kselftest.h"19#include "kselftest.h"
20 20
21#define DEBUG_LEVEL_1_BIT (0x0001)21#define DEBUG_LEVEL_1_BIT (0x0001)
22#define DEBUG_LEVEL_2_BIT (0x0002)22#define DEBUG_LEVEL_2_BIT (0x0002)
tools/testing/selftests/sync/sync_test.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <errno.h>34#include <errno.h>
35#include <string.h>35#include <string.h>
36 36
37#include "../kselftest.h"37#include "kselftest.h"
38#include "synctest.h"38#include "synctest.h"
39 39
40static int run_test(int (*test)(void), char *name)40static int run_test(int (*test)(void), char *name)
tools/testing/selftests/syscall_user_dispatch/sud_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <stdlib.h>14#include <stdlib.h>
15 15
16#include <asm/unistd.h>16#include <asm/unistd.h>
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18 18
19#ifndef PR_SET_SYSCALL_USER_DISPATCH19#ifndef PR_SET_SYSCALL_USER_DISPATCH
20# define PR_SET_SYSCALL_USER_DISPATCH 5920# define PR_SET_SYSCALL_USER_DISPATCH 59
tools/testing/selftests/tdx/tdx_guest_test.c+1−1
@@ -13,7 +13,7 @@ · 12 unmodified lines
13#include <fcntl.h>13#include <fcntl.h>
14 14
15#include <linux/tdx-guest.h>15#include <linux/tdx-guest.h>
16#include "../kselftest_harness.h"16#include "kselftest_harness.h"
17 17
18#define TDX_GUEST_DEVNAME "/dev/tdx_guest"18#define TDX_GUEST_DEVNAME "/dev/tdx_guest"
19#define HEX_DUMP_SIZE 819#define HEX_DUMP_SIZE 8
tools/testing/selftests/timens/timens.h+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7#include <stdlib.h>7#include <stdlib.h>
8#include <stdbool.h>8#include <stdbool.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12#ifndef CLONE_NEWTIME12#ifndef CLONE_NEWTIME
13# define CLONE_NEWTIME 0x0000008013# define CLONE_NEWTIME 0x00000080
tools/testing/selftests/timers/adjtick.c+1−1
@@ -24,7 +24,7 @@ · 23 unmodified lines
24#include <time.h>24#include <time.h>
25#include <include/vdso/time64.h>25#include <include/vdso/time64.h>
26 26
27#include "../kselftest.h"27#include "kselftest.h"
28 28
29#define MILLION 100000029#define MILLION 1000000
30 30
tools/testing/selftests/timers/alarmtimer-suspend.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include <pthread.h>30#include <pthread.h>
31#include <include/vdso/time64.h>31#include <include/vdso/time64.h>
32#include <errno.h>32#include <errno.h>
33#include "../kselftest.h"33#include "kselftest.h"
34 34
35#define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */35#define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */
36 36
tools/testing/selftests/timers/change_skew.c+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
28#include <sys/time.h>28#include <sys/time.h>
29#include <sys/timex.h>29#include <sys/timex.h>
30#include <time.h>30#include <time.h>
31#include "../kselftest.h"31#include "kselftest.h"
32 32
33int change_skew_test(int ppm)33int change_skew_test(int ppm)
34{34{
tools/testing/selftests/timers/clocksource-switch.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <sys/wait.h>34#include <sys/wait.h>
35#include <time.h>35#include <time.h>
36#include <unistd.h>36#include <unistd.h>
37#include "../kselftest.h"37#include "kselftest.h"
38 38
39 39
40int get_clocksources(char list[][30])40int get_clocksources(char list[][30])
tools/testing/selftests/timers/freq-step.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <time.h>15#include <time.h>
16#include <unistd.h>16#include <unistd.h>
17 17
18#include "../kselftest.h"18#include "kselftest.h"
19 19
20#define SAMPLES 10020#define SAMPLES 100
21#define SAMPLE_READINGS 1021#define SAMPLE_READINGS 10
tools/testing/selftests/timers/inconsistency-check.c+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29#include <string.h>29#include <string.h>
30#include <signal.h>30#include <signal.h>
31#include <include/vdso/time64.h>31#include <include/vdso/time64.h>
32#include "../kselftest.h"32#include "kselftest.h"
33 33
34/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */34/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
35#define CLOCK_HWSPECIFIC 1035#define CLOCK_HWSPECIFIC 10
tools/testing/selftests/timers/leap-a-day.c+1−1
@@ -49,7 +49,7 @@ · 48 unmodified lines
49#include <signal.h>49#include <signal.h>
50#include <unistd.h>50#include <unistd.h>
51#include <include/vdso/time64.h>51#include <include/vdso/time64.h>
52#include "../kselftest.h"52#include "kselftest.h"
53 53
54#define CLOCK_TAI 1154#define CLOCK_TAI 11
55 55
tools/testing/selftests/timers/leapcrash.c+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <sys/timex.h>22#include <sys/timex.h>
23#include <string.h>23#include <string.h>
24#include <signal.h>24#include <signal.h>
25#include "../kselftest.h"25#include "kselftest.h"
26 26
27/* clear NTP time_status & time_state */27/* clear NTP time_status & time_state */
28int clear_time_state(void)28int clear_time_state(void)
tools/testing/selftests/timers/mqueue-lat.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include <errno.h>30#include <errno.h>
31#include <mqueue.h>31#include <mqueue.h>
32#include <include/vdso/time64.h>32#include <include/vdso/time64.h>
33#include "../kselftest.h"33#include "kselftest.h"
34 34
35 35
36#define TARGET_TIMEOUT 100000000 /* 100ms in nanoseconds */36#define TARGET_TIMEOUT 100000000 /* 100ms in nanoseconds */
tools/testing/selftests/timers/nanosleep.c+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
28#include <string.h>28#include <string.h>
29#include <signal.h>29#include <signal.h>
30#include <include/vdso/time64.h>30#include <include/vdso/time64.h>
31#include "../kselftest.h"31#include "kselftest.h"
32 32
33/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */33/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
34#define CLOCK_HWSPECIFIC 1034#define CLOCK_HWSPECIFIC 10
tools/testing/selftests/timers/nsleep-lat.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <string.h>25#include <string.h>
26#include <signal.h>26#include <signal.h>
27#include <include/vdso/time64.h>27#include <include/vdso/time64.h>
28#include "../kselftest.h"28#include "kselftest.h"
29 29
30#define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */30#define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
31 31
tools/testing/selftests/timers/posix_timers.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <pthread.h>20#include <pthread.h>
21#include <stdbool.h>21#include <stdbool.h>
22 22
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25#define DELAY 225#define DELAY 2
26 26
tools/testing/selftests/timers/raw_skew.c+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#include <sys/timex.h>26#include <sys/timex.h>
27#include <time.h>27#include <time.h>
28#include <include/vdso/time64.h>28#include <include/vdso/time64.h>
29#include "../kselftest.h"29#include "kselftest.h"
30 30
31#define shift_right(x, s) ({ \31#define shift_right(x, s) ({ \
32 __typeof__(x) __x = (x); \32 __typeof__(x) __x = (x); \
tools/testing/selftests/timers/rtcpie.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <stdlib.h>18#include <stdlib.h>
19#include <errno.h>19#include <errno.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23/*23/*
24 * This expects the new RTC class driver framework, working with24 * This expects the new RTC class driver framework, working with
tools/testing/selftests/timers/set-2038.c+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
28#include <time.h>28#include <time.h>
29#include <sys/time.h>29#include <sys/time.h>
30#include <include/vdso/time64.h>30#include <include/vdso/time64.h>
31#include "../kselftest.h"31#include "kselftest.h"
32 32
33#define KTIME_MAX ((long long)~((unsigned long long)1 << 63))33#define KTIME_MAX ((long long)~((unsigned long long)1 << 63))
34#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)34#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
tools/testing/selftests/timers/set-tai.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <string.h>23#include <string.h>
24#include <signal.h>24#include <signal.h>
25#include <unistd.h>25#include <unistd.h>
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28int set_tai(int offset)28int set_tai(int offset)
29{29{
tools/testing/selftests/timers/set-timer-lat.c+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29#include <stdlib.h>29#include <stdlib.h>
30#include <pthread.h>30#include <pthread.h>
31#include <include/vdso/time64.h>31#include <include/vdso/time64.h>
32#include "../kselftest.h"32#include "kselftest.h"
33 33
34/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */34/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
35#define CLOCK_HWSPECIFIC 1035#define CLOCK_HWSPECIFIC 10
tools/testing/selftests/timers/set-tz.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <string.h>23#include <string.h>
24#include <signal.h>24#include <signal.h>
25#include <unistd.h>25#include <unistd.h>
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28int set_tz(int min, int dst)28int set_tz(int min, int dst)
29{29{
tools/testing/selftests/timers/skew_consistency.c+1−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
34#include <fcntl.h>34#include <fcntl.h>
35#include <string.h>35#include <string.h>
36#include <sys/wait.h>36#include <sys/wait.h>
37#include "../kselftest.h"37#include "kselftest.h"
38 38
39int main(int argc, char **argv)39int main(int argc, char **argv)
40{40{
tools/testing/selftests/timers/threadtest.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <stdlib.h>21#include <stdlib.h>
22#include <sys/time.h>22#include <sys/time.h>
23#include <pthread.h>23#include <pthread.h>
24#include "../kselftest.h"24#include "kselftest.h"
25 25
26/* serializes shared list access */26/* serializes shared list access */
27pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;27pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
tools/testing/selftests/timers/valid-adjtimex.c+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include <signal.h>30#include <signal.h>
31#include <unistd.h>31#include <unistd.h>
32#include <include/vdso/time64.h>32#include <include/vdso/time64.h>
33#include "../kselftest.h"33#include "kselftest.h"
34 34
35#define ADJ_SETOFFSET 0x010035#define ADJ_SETOFFSET 0x0100
36 36
tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <sys/mount.h>23#include <sys/mount.h>
24#include <unistd.h>24#include <unistd.h>
25 25
26#include "../kselftest.h"26#include "kselftest.h"
27 27
28int main(void)28int main(void)
29{29{
tools/testing/selftests/tty/tty_tstamp_update.c+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <unistd.h>9#include <unistd.h>
10#include <linux/limits.h>10#include <linux/limits.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13 13
14#define MIN_TTY_PATH_LEN 814#define MIN_TTY_PATH_LEN 8
15 15
tools/testing/selftests/uevent/uevent_filtering.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <sys/wait.h>19#include <sys/wait.h>
20#include <unistd.h>20#include <unistd.h>
21 21
22#include "../kselftest_harness.h"22#include "kselftest_harness.h"
23 23
24#define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"24#define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
25#define __UEVENT_BUFFER_SIZE (2048 * 2)25#define __UEVENT_BUFFER_SIZE (2048 * 2)
tools/testing/selftests/user_events/abi_test.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <string.h>20#include <string.h>
21#include <asm/unistd.h>21#include <asm/unistd.h>
22 22
23#include "../kselftest_harness.h"23#include "kselftest_harness.h"
24#include "user_events_selftests.h"24#include "user_events_selftests.h"
25 25
26const char *data_file = "/sys/kernel/tracing/user_events_data";26const char *data_file = "/sys/kernel/tracing/user_events_data";
tools/testing/selftests/user_events/dyn_test.c+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <sys/stat.h>14#include <sys/stat.h>
15#include <unistd.h>15#include <unistd.h>
16 16
17#include "../kselftest_harness.h"17#include "kselftest_harness.h"
18#include "user_events_selftests.h"18#include "user_events_selftests.h"
19 19
20const char *dyn_file = "/sys/kernel/tracing/dynamic_events";20const char *dyn_file = "/sys/kernel/tracing/dynamic_events";
tools/testing/selftests/user_events/ftrace_test.c+1−1
@@ -15,7 +15,7 @@ · 14 unmodified lines
15#include <sys/uio.h>15#include <sys/uio.h>
16#include <unistd.h>16#include <unistd.h>
17 17
18#include "../kselftest_harness.h"18#include "kselftest_harness.h"
19#include "user_events_selftests.h"19#include "user_events_selftests.h"
20 20
21const char *data_file = "/sys/kernel/tracing/user_events_data";21const char *data_file = "/sys/kernel/tracing/user_events_data";
tools/testing/selftests/user_events/perf_test.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <unistd.h>16#include <unistd.h>
17#include <asm/unistd.h>17#include <asm/unistd.h>
18 18
19#include "../kselftest_harness.h"19#include "kselftest_harness.h"
20#include "user_events_selftests.h"20#include "user_events_selftests.h"
21 21
22const char *data_file = "/sys/kernel/tracing/user_events_data";22const char *data_file = "/sys/kernel/tracing/user_events_data";
tools/testing/selftests/user_events/user_events_selftests.h+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9#include <unistd.h>9#include <unistd.h>
10#include <errno.h>10#include <errno.h>
11 11
12#include "../kselftest.h"12#include "kselftest.h"
13 13
14static inline void tracefs_unmount(void)14static inline void tracefs_unmount(void)
15{15{
tools/testing/selftests/vDSO/vdso_test_abi.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18#include <unistd.h>18#include <unistd.h>
19#include <sys/syscall.h>19#include <sys/syscall.h>
20 20
21#include "../kselftest.h"21#include "kselftest.h"
22#include "vdso_config.h"22#include "vdso_config.h"
23#include "vdso_call.h"23#include "vdso_call.h"
24#include "parse_vdso.h"24#include "parse_vdso.h"
tools/testing/selftests/vDSO/vdso_test_chacha.c+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10#include <string.h>10#include <string.h>
11#include <stdint.h>11#include <stdint.h>
12#include <stdbool.h>12#include <stdbool.h>
13#include "../kselftest.h"13#include "kselftest.h"
14 14
15#if defined(__aarch64__)15#if defined(__aarch64__)
16static bool cpu_has_capabilities(void)16static bool cpu_has_capabilities(void)
tools/testing/selftests/vDSO/vdso_test_correctness.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21 21
22#include "vdso_config.h"22#include "vdso_config.h"
23#include "vdso_call.h"23#include "vdso_call.h"
24#include "../kselftest.h"24#include "kselftest.h"
25 25
26static const char **name;26static const char **name;
27 27
tools/testing/selftests/vDSO/vdso_test_getcpu.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <sys/auxv.h>11#include <sys/auxv.h>
12#include <sys/time.h>12#include <sys/time.h>
13 13
14#include "../kselftest.h"14#include "kselftest.h"
15#include "parse_vdso.h"15#include "parse_vdso.h"
16#include "vdso_config.h"16#include "vdso_config.h"
17#include "vdso_call.h"17#include "vdso_call.h"
tools/testing/selftests/vDSO/vdso_test_getrandom.c+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#include <linux/random.h>23#include <linux/random.h>
24#include <linux/ptrace.h>24#include <linux/ptrace.h>
25 25
26#include "../kselftest.h"26#include "kselftest.h"
27#include "parse_vdso.h"27#include "parse_vdso.h"
28#include "vdso_config.h"28#include "vdso_config.h"
29#include "vdso_call.h"29#include "vdso_call.h"
tools/testing/selftests/vDSO/vdso_test_gettimeofday.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include <sys/time.h>16#include <sys/time.h>
17#endif17#endif
18 18
19#include "../kselftest.h"19#include "kselftest.h"
20#include "parse_vdso.h"20#include "parse_vdso.h"
21#include "vdso_config.h"21#include "vdso_config.h"
22#include "vdso_call.h"22#include "vdso_call.h"
tools/testing/selftests/vfio/lib/vfio_pci_device.c+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19#include <linux/types.h>19#include <linux/types.h>
20#include <linux/vfio.h>20#include <linux/vfio.h>
21 21
22#include "../../../kselftest.h"22#include "kselftest.h"
23#include <libvfio.h>23#include <libvfio.h>
24 24
25#define PCI_SYSFS_PATH "/sys/bus/pci/devices"25#define PCI_SYSFS_PATH "/sys/bus/pci/devices"
tools/testing/selftests/vfio/lib/vfio_pci_driver.c+1−1
@@ -1,5 +1,5 @@
1// SPDX-License-Identifier: GPL-2.0-only1// SPDX-License-Identifier: GPL-2.0-only
2#include "../../../kselftest.h"2#include "kselftest.h"
3#include <libvfio.h>3#include <libvfio.h>
4 4
5#ifdef __x86_64__5#ifdef __x86_64__
tools/testing/selftests/vfio/vfio_dma_mapping_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12 12
13#include <libvfio.h>13#include <libvfio.h>
14 14
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17static const char *device_bdf;17static const char *device_bdf;
18 18
tools/testing/selftests/vfio/vfio_iommufd_setup_test.c+1−1
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <unistd.h>11#include <unistd.h>
12 12
13#include <libvfio.h>13#include <libvfio.h>
14#include "../kselftest_harness.h"14#include "kselftest_harness.h"
15 15
16static const char iommu_dev_path[] = "/dev/iommu";16static const char iommu_dev_path[] = "/dev/iommu";
17static const char *cdev_path;17static const char *cdev_path;
tools/testing/selftests/vfio/vfio_pci_device_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12 12
13#include <libvfio.h>13#include <libvfio.h>
14 14
15#include "../kselftest_harness.h"15#include "kselftest_harness.h"
16 16
17static const char *device_bdf;17static const char *device_bdf;
18 18
tools/testing/selftests/vfio/vfio_pci_driver_test.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 7
8#include <libvfio.h>8#include <libvfio.h>
9 9
10#include "../kselftest_harness.h"10#include "kselftest_harness.h"
11 11
12static const char *device_bdf;12static const char *device_bdf;
13 13
tools/testing/selftests/wireguard/qemu/kernel.config+1−1
@@ -81,7 +81,7 @@ CONFIG_WQ_WATCHDOG=y · 80 unmodified lines
81CONFIG_DETECT_HUNG_TASK=y81CONFIG_DETECT_HUNG_TASK=y
82CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y82CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
83CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y83CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
84CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y84CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1
85CONFIG_PANIC_TIMEOUT=-185CONFIG_PANIC_TIMEOUT=-1
86CONFIG_STACKTRACE=y86CONFIG_STACKTRACE=y
87CONFIG_EARLY_PRINTK=y87CONFIG_EARLY_PRINTK=y
tools/testing/selftests/x86/corrupt_xstate_header.c+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17#include <stdint.h>17#include <stdint.h>
18#include <sys/wait.h>18#include <sys/wait.h>
19 19
20#include "../kselftest.h" /* For __cpuid_count() */20#include "kselftest.h" /* For __cpuid_count() */
21#include "helpers.h"21#include "helpers.h"
22 22
23static inline int xsave_enabled(void)23static inline int xsave_enabled(void)
tools/testing/selftests/x86/helpers.h+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7 7
8#include <asm/processor-flags.h>8#include <asm/processor-flags.h>
9 9
10#include "../kselftest.h"10#include "kselftest.h"
11 11
12static inline unsigned long get_eflags(void)12static inline unsigned long get_eflags(void)
13{13{
tools/testing/selftests/x86/lam.c+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
18 18
19#include <sys/uio.h>19#include <sys/uio.h>
20#include <linux/io_uring.h>20#include <linux/io_uring.h>
21#include "../kselftest.h"21#include "kselftest.h"
22 22
23#ifndef __x86_64__23#ifndef __x86_64__
24# error This test is 64-bit only24# error This test is 64-bit only
tools/testing/selftests/x86/syscall_numbering.c+1−1
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include <sys/mman.h>25#include <sys/mman.h>
26 26
27#include <linux/ptrace.h>27#include <linux/ptrace.h>
28#include "../kselftest.h"28#include "kselftest.h"
29 29
30/* Common system call numbers */30/* Common system call numbers */
31#define SYS_READ 031#define SYS_READ 0
tools/testing/selftests/x86/test_mremap_vdso.c+1−1
@@ -20,7 +20,7 @@ · 19 unmodified lines
20#include <sys/auxv.h>20#include <sys/auxv.h>
21#include <sys/syscall.h>21#include <sys/syscall.h>
22#include <sys/wait.h>22#include <sys/wait.h>
23#include "../kselftest.h"23#include "kselftest.h"
24 24
25#define PAGE_SIZE 409625#define PAGE_SIZE 4096
26 26
tools/testing/selftests/x86/test_vsyscall.c+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
21#include <sys/uio.h>21#include <sys/uio.h>
22 22
23#include "helpers.h"23#include "helpers.h"
24#include "../kselftest.h"24#include "kselftest.h"
25 25
26#ifdef __x86_64__26#ifdef __x86_64__
27#define TOTAL_TESTS 1327#define TOTAL_TESTS 13
tools/testing/selftests/x86/xstate.h+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5#include <stdint.h>5#include <stdint.h>
6 6
7#include "../kselftest.h"7#include "kselftest.h"
8 8
9#define XSAVE_HDR_OFFSET 5129#define XSAVE_HDR_OFFSET 512
10#define XSAVE_HDR_SIZE 6410#define XSAVE_HDR_SIZE 64