From f5cd997d273c821426a747eff97b78e5342716da Mon Sep 17 00:00:00 2001 From: Wizzard Date: Mon, 26 Feb 2024 12:01:57 -0500 Subject: [PATCH] Update for 6.7.6, update NTSync patches and remaster build files --- SOURCES/.config | 31 ++- ...sync_driver_and_character\n_device..patch" | 31 ++- SOURCES/0001-NTPatch.patch | 68 ----- ...nc:_Introduce_NTSYNC_IOC_CREATE_SEM..patch | 228 +++++++++++++++ SOURCES/0002-NTPatch.patch | 191 ------------- ...sync:_Introduce_NTSYNC_IOC_SEM_POST..patch | 147 ++++++++++ SOURCES/0003-NTPatch.patch | 147 ---------- ...ync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch} | 210 ++++++++------ ...ync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch} | 158 ++++++----- ..._Introduce_NTSYNC_IOC_CREATE_MUTEX..patch} | 85 +++--- ..._Introduce_NTSYNC_IOC_MUTEX_UNLOCK..patch} | 66 ++--- ...nc:_Introduce_NTSYNC_IOC_MUTEX_KILL..patch | 166 +++++++++++ SOURCES/0008-NTPatch.patch | 170 ------------ ...:_Introduce_NTSYNC_IOC_CREATE_EVENT..patch | 165 +++++++++++ ...ync:_Introduce_NTSYNC_IOC_EVENT_SET..patch | 78 ++++++ ...c:_Introduce_NTSYNC_IOC_EVENT_RESET..patch | 63 +++++ ...c:_Introduce_NTSYNC_IOC_EVENT_PULSE..patch | 70 +++++ ...sync:_Introduce_NTSYNC_IOC_SEM_READ..patch | 62 +++++ ...nc:_Introduce_NTSYNC_IOC_MUTEX_READ..patch | 64 +++++ ...nc:_Introduce_NTSYNC_IOC_EVENT_READ..patch | 62 +++++ ...]_ntsync:_Introduce_alertable_waits..patch | 184 +++++++++++++ ...low_waits_to_use_the_REALTIME_clock..patch | 79 ++++++ ...d_some_tests_for_semaphore\n_state..patch" | 208 ++++++++++++++ ...:_Add_some_tests_for_mutex\n_state..patch" | 222 +++++++++++++++ ...me_tests_for\n_NTSYNC_IOC_WAIT_ANY..patch" | 139 ++++++++++ ...me_tests_for\n_NTSYNC_IOC_WAIT_ALL..patch" | 136 +++++++++ ...gnaling_with_WINESYNC_IOC_WAIT_ANY..patch" | 169 ++++++++++++ ...gnaling_with_WINESYNC_IOC_WAIT_ALL..patch" | 118 ++++++++ ...sts_for\n_manual-reset_event_state..patch" | 118 ++++++++ ...tests_for_auto-reset\n_event_state..patch" | 81 ++++++ ...for_wakeup\n_signaling_with_events..patch" | 259 ++++++++++++++++++ ...sync:_Add_tests_for_alertable_waits..patch | 223 +++++++++++++++ ..._for_wakeup\n_signaling_via_alerts..patch" | 110 ++++++++ ..._stress_test_for\n_contended_waits..patch" | 97 +++++++ ...aintainers:_Add_an_entry_for_ntsync..patch | 29 ++ SOURCES/gpl_patch.patch | 19 ++ SPECS/linux-zen.spec | 38 +-- build-helper.sh | 3 +- run-after-install.sh | 4 +- 39 files changed, 3631 insertions(+), 867 deletions(-) rename SOURCES/0000-NTPatch.patch => "SOURCES/0000-[PATCH_v2_1_31]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" (82%) delete mode 100644 SOURCES/0001-NTPatch.patch create mode 100644 SOURCES/0001-[PATCH_v2_2_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM..patch delete mode 100644 SOURCES/0002-NTPatch.patch create mode 100644 SOURCES/0002-[PATCH_v2_3_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_POST..patch delete mode 100644 SOURCES/0003-NTPatch.patch rename SOURCES/{0004-NTPatch.patch => 0003-[PATCH_v2_4_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch} (54%) rename SOURCES/{0005-NTPatch.patch => 0004-[PATCH_v2_5_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch} (70%) rename SOURCES/{0006-NTPatch.patch => 0005-[PATCH_v2_6_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch} (58%) rename SOURCES/{0007-NTPatch.patch => 0006-[PATCH_v2_7_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_UNLOCK..patch} (50%) create mode 100644 SOURCES/0007-[PATCH_v2_8_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_KILL..patch delete mode 100644 SOURCES/0008-NTPatch.patch create mode 100644 SOURCES/0008-[PATCH_v2_9_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_EVENT..patch create mode 100644 SOURCES/0009-[PATCH_v2_10_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_SET..patch create mode 100644 SOURCES/0010-[PATCH_v2_11_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_RESET..patch create mode 100644 SOURCES/0011-[PATCH_v2_12_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_PULSE..patch create mode 100644 SOURCES/0012-[PATCH_v2_13_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_READ..patch create mode 100644 SOURCES/0013-[PATCH_v2_14_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_READ..patch create mode 100644 SOURCES/0014-[PATCH_v2_15_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_READ..patch create mode 100644 SOURCES/0015-[PATCH_v2_16_31]_ntsync:_Introduce_alertable_waits..patch create mode 100644 SOURCES/0016-[PATCH_v2_17_31]_ntsync:_Allow_waits_to_use_the_REALTIME_clock..patch create mode 100644 "SOURCES/0017-[PATCH_v2_18_31]_selftests:_ntsync:_Add_some_tests_for_semaphore\n_state..patch" create mode 100644 "SOURCES/0018-[PATCH_v2_19_31]_selftests:_ntsync:_Add_some_tests_for_mutex\n_state..patch" create mode 100644 "SOURCES/0019-[PATCH_v2_20_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ANY..patch" create mode 100644 "SOURCES/0020-[PATCH_v2_21_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ALL..patch" create mode 100644 "SOURCES/0021-[PATCH_v2_22_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ANY..patch" create mode 100644 "SOURCES/0022-[PATCH_v2_23_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ALL..patch" create mode 100644 "SOURCES/0023-[PATCH_v2_24_31]_selftests:_ntsync:_Add_some_tests_for\n_manual-reset_event_state..patch" create mode 100644 "SOURCES/0024-[PATCH_v2_25_31]_selftests:_ntsync:_Add_some_tests_for_auto-reset\n_event_state..patch" create mode 100644 "SOURCES/0025-[PATCH_v2_26_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_events..patch" create mode 100644 SOURCES/0026-[PATCH_v2_27_31]_selftests:_ntsync:_Add_tests_for_alertable_waits..patch create mode 100644 "SOURCES/0027-[PATCH_v2_28_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_via_alerts..patch" create mode 100644 "SOURCES/0028-[PATCH_v2_29_31]_selftests:_ntsync:_Add_a_stress_test_for\n_contended_waits..patch" create mode 100644 SOURCES/0029-[PATCH_v2_30_31]_maintainers:_Add_an_entry_for_ntsync..patch create mode 100644 SOURCES/gpl_patch.patch diff --git a/SOURCES/.config b/SOURCES/.config index a90fa49..ee64e2c 100644 --- a/SOURCES/.config +++ b/SOURCES/.config @@ -1,24 +1,24 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.7.0-zen1 Kernel Configuration +# Linux/x86 6.7.6-zen1 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.0" +CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20231205 (Red Hat 13.2.1-6)" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=120200 +CONFIG_GCC_VERSION=130201 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=23900 +CONFIG_AS_VERSION=24000 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=23900 +CONFIG_LD_VERSION=24000 CONFIG_LLD_VERSION=0 CONFIG_CC_CAN_LINK=y -CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y +CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=0 +CONFIG_PAHOLE_VERSION=125 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -400,6 +400,7 @@ CONFIG_INTEL_TDX_GUEST=y # CONFIG_MZEN is not set # CONFIG_MZEN2 is not set # CONFIG_MZEN3 is not set +# CONFIG_MZEN4 is not set # CONFIG_MPSC is not set # CONFIG_MCORE2 is not set # CONFIG_MATOM is not set @@ -422,6 +423,9 @@ CONFIG_INTEL_TDX_GUEST=y # CONFIG_MSAPPHIRERAPIDS is not set # CONFIG_MROCKETLAKE is not set # CONFIG_MALDERLAKE is not set +# CONFIG_MRAPTORLAKE is not set +# CONFIG_MMETEORLAKE is not set +# CONFIG_MEMERALDRAPIDS is not set # CONFIG_GENERIC_CPU is not set # CONFIG_GENERIC_CPU2 is not set # CONFIG_GENERIC_CPU3 is not set @@ -899,9 +903,9 @@ CONFIG_SOFTIRQ_ON_OWN_STACK=y CONFIG_ARCH_HAS_ELF_RANDOMIZE=y CONFIG_HAVE_ARCH_MMAP_RND_BITS=y CONFIG_HAVE_EXIT_THREAD=y -CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_ARCH_MMAP_RND_BITS=32 CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y -CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y @@ -950,7 +954,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling CONFIG_HAVE_GCC_PLUGINS=y -# CONFIG_GCC_PLUGINS is not set CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT_16B=y CONFIG_FUNCTION_ALIGNMENT=16 @@ -4235,7 +4238,6 @@ CONFIG_TOUCHSCREEN_PENMOUNT=m CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_TOUCHSCREEN_TOUCHRIGHT=m CONFIG_TOUCHSCREEN_TOUCHWIN=m -CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m CONFIG_TOUCHSCREEN_PIXCIR=m CONFIG_TOUCHSCREEN_WDT87XX_I2C=m # CONFIG_TOUCHSCREEN_WM831X is not set @@ -5491,7 +5493,6 @@ CONFIG_MFD_SM501=m CONFIG_MFD_SM501_GPIO=y CONFIG_MFD_SKY81452=m CONFIG_MFD_SYSCON=y -CONFIG_MFD_TI_AM335X_TSCADC=m CONFIG_MFD_LP3943=m # CONFIG_MFD_LP8788 is not set # CONFIG_MFD_TI_LMU is not set @@ -7081,7 +7082,6 @@ CONFIG_SND_SOC_FSL_AUDMIX=m CONFIG_SND_SOC_FSL_MICFIL=m # CONFIG_SND_SOC_FSL_XCVR is not set CONFIG_SND_SOC_FSL_UTILS=m -CONFIG_SND_SOC_FSL_RPMSG=m # CONFIG_SND_SOC_IMX_AUDMUX is not set # end of SoC Audio for Freescale CPUs @@ -9382,7 +9382,6 @@ CONFIG_TI_ADS8344=m CONFIG_TI_ADS8688=m CONFIG_TI_ADS124S08=m CONFIG_TI_ADS131E08=m -CONFIG_TI_AM335X_ADC=m # CONFIG_TI_LMP92064 is not set CONFIG_TI_TLC4541=m CONFIG_TI_TSC2046=m @@ -10972,6 +10971,10 @@ CONFIG_DEBUG_INFO_COMPRESSED_NONE=y # CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set # CONFIG_DEBUG_INFO_SPLIT is not set CONFIG_DEBUG_INFO_BTF=y +CONFIG_PAHOLE_HAS_SPLIT_BTF=y +CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y +CONFIG_DEBUG_INFO_BTF_MODULES=y +# CONFIG_MODULE_ALLOW_BTF_MISMATCH is not set # CONFIG_GDB_SCRIPTS is not set CONFIG_FRAME_WARN=1024 CONFIG_STRIP_ASM_SYMS=y diff --git a/SOURCES/0000-NTPatch.patch "b/SOURCES/0000-[PATCH_v2_1_31]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" similarity index 82% rename from SOURCES/0000-NTPatch.patch rename to "SOURCES/0000-[PATCH_v2_1_31]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" index 580a595..5193a8c 100644 --- a/SOURCES/0000-NTPatch.patch +++ "b/SOURCES/0000-[PATCH_v2_1_31]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" @@ -5,19 +5,19 @@ to correspond to a single NT virtual machine. Signed-off-by: Elizabeth Figura --- - drivers/misc/Kconfig | 9 ++++++++ + drivers/misc/Kconfig | 11 +++++++++ drivers/misc/Makefile | 1 + - drivers/misc/ntsync.c | 53 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 63 insertions(+) + drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 64 insertions(+) create mode 100644 drivers/misc/ntsync.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 4fb291f0bf7c..bdd8a71bd853 100644 +index 4fb291f0bf7c..801ed229ed7d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -504,6 +504,15 @@ config OPEN_DICE - measured boot flow. Userspace can use CDIs for remote attestation - and sealing. +@@ -506,6 +506,17 @@ config OPEN_DICE + + If unsure, say N. +config NTSYNC + tristate "NT synchronization primitive emulation" @@ -28,9 +28,11 @@ index 4fb291f0bf7c..bdd8a71bd853 100644 + To compile this driver as a module, choose M here: the + module will be called ntsync. + - If unsure, say N. - ++ If unsure, say N. ++ config VCPU_STALL_DETECTOR + tristate "Guest vCPU stall detector" + depends on OF && HAS_IOMEM diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ea6ea5bbbc9c..153a3f4837e8 100644 --- a/drivers/misc/Makefile @@ -45,15 +47,15 @@ index ea6ea5bbbc9c..153a3f4837e8 100644 obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..9424c6210e51 +index 000000000000..bd76e653d83e --- /dev/null +++ b/drivers/misc/ntsync.c -@@ -0,0 +1,53 @@ +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives + * -+ * Copyright (C) 2021-2022 Elizabeth Figura ++ * Copyright (C) 2024 Elizabeth Figura + */ + +#include @@ -86,7 +88,7 @@ index 000000000000..9424c6210e51 + .open = ntsync_char_open, + .release = ntsync_char_release, + .unlocked_ioctl = ntsync_char_ioctl, -+ .compat_ioctl = ntsync_char_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, +}; + @@ -98,9 +100,8 @@ index 000000000000..9424c6210e51 + +module_misc_device(ntsync_misc); + -+MODULE_AUTHOR("Elizabeth Figura"); ++MODULE_AUTHOR("Elizabeth Figura "); +MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); -+MODULE_ALIAS("devname:" NTSYNC_NAME); -- 2.43.0 diff --git a/SOURCES/0001-NTPatch.patch b/SOURCES/0001-NTPatch.patch deleted file mode 100644 index 0e03db0..0000000 --- a/SOURCES/0001-NTPatch.patch +++ /dev/null @@ -1,68 +0,0 @@ -Signed-off-by: Elizabeth Figura ---- - Documentation/admin-guide/devices.txt | 3 ++- - Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ - drivers/misc/ntsync.c | 3 ++- - include/linux/miscdevice.h | 1 + - 4 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt -index 94c98be1329a..041404397ee5 100644 ---- a/Documentation/admin-guide/devices.txt -+++ b/Documentation/admin-guide/devices.txt -@@ -376,8 +376,9 @@ - 240 = /dev/userio Serio driver testing device - 241 = /dev/vhost-vsock Host kernel driver for virtio vsock - 242 = /dev/rfkill Turning off radio transmissions (rfkill) -+ 243 = /dev/ntsync NT synchronization primitive device - -- 243-254 Reserved for local use -+ 244-254 Reserved for local use - 255 Reserved for MISC_DYNAMIC_MINOR - - 11 char Raw keyboard device (Linux/SPARC only) -diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst -index 457e16f06e04..a1326a5bc2e0 100644 ---- a/Documentation/userspace-api/ioctl/ioctl-number.rst -+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst -@@ -378,6 +378,8 @@ Code Seq# Include File Comments - - 0xF6 all LTTng Linux Trace Toolkit Next Generation - -+0xF7 00-1F uapi/linux/ntsync.h NT synchronization primitives -+ - 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver - - 0xFD all linux/dm-ioctl.h -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 9424c6210e51..84b498e2b2d5 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -40,7 +40,7 @@ static const struct file_operations ntsync_fops = { - }; - - static struct miscdevice ntsync_misc = { -- .minor = MISC_DYNAMIC_MINOR, -+ .minor = NTSYNC_MINOR, - .name = NTSYNC_NAME, - .fops = &ntsync_fops, - }; -@@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura"); - MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); - MODULE_LICENSE("GPL"); - MODULE_ALIAS("devname:" NTSYNC_NAME); -+MODULE_ALIAS_MISCDEV(NTSYNC_MINOR); -diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h -index c0fea6ca5076..fe5d9366fdf7 100644 ---- a/include/linux/miscdevice.h -+++ b/include/linux/miscdevice.h -@@ -71,6 +71,7 @@ - #define USERIO_MINOR 240 - #define VHOST_VSOCK_MINOR 241 - #define RFKILL_MINOR 242 -+#define NTSYNC_MINOR 243 - #define MISC_DYNAMIC_MINOR 255 - - struct device; --- -2.43.0 diff --git a/SOURCES/0001-[PATCH_v2_2_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM..patch b/SOURCES/0001-[PATCH_v2_2_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM..patch new file mode 100644 index 0000000..6d223a2 --- /dev/null +++ b/SOURCES/0001-[PATCH_v2_2_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM..patch @@ -0,0 +1,228 @@ +This corresponds to the NT syscall NtCreateSemaphore(). + +Semaphores are one of three types of object to be implemented in this driver, +the others being mutexes and events. + +An NT semaphore contains a 32-bit counter, and is signaled and can be acquired +when the counter is nonzero. The counter has a maximum value which is specified +at creation time. The initial value of the semaphore is also specified at +creation time. There are no restrictions on the maximum and initial value. + +Each object is exposed as an file, to which any number of fds may be opened. +When all fds are closed, the object is deleted. + +Objects hold a pointer to the ntsync_device that created them. The device's +reference count is driven by struct file. + +Signed-off-by: Elizabeth Figura +--- + .../userspace-api/ioctl/ioctl-number.rst | 2 + + drivers/misc/ntsync.c | 131 ++++++++++++++++++ + include/uapi/linux/ntsync.h | 21 +++ + 3 files changed, 154 insertions(+) + create mode 100644 include/uapi/linux/ntsync.h + +diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst +index 457e16f06e04..2f5c6994f042 100644 +--- a/Documentation/userspace-api/ioctl/ioctl-number.rst ++++ b/Documentation/userspace-api/ioctl/ioctl-number.rst +@@ -173,6 +173,8 @@ Code Seq# Include File Comments + 'M' 00-0F drivers/video/fsl-diu-fb.h conflict! + 'N' 00-1F drivers/usb/scanner.h + 'N' 40-7F drivers/block/nvme.c ++'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives ++ + 'O' 00-06 mtd/ubi-user.h UBI + 'P' all linux/soundcard.h conflict! + 'P' 60-6F sound/sscape_ioctl.h conflict! +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index bd76e653d83e..20158ec148bc 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -5,26 +5,157 @@ + * Copyright (C) 2024 Elizabeth Figura + */ + ++#include ++#include + #include + #include + #include ++#include ++#include + + #define NTSYNC_NAME "ntsync" + ++enum ntsync_type { ++ NTSYNC_TYPE_SEM, ++}; ++ ++/* ++ * Individual synchronization primitives are represented by ++ * struct ntsync_obj, and each primitive is backed by a file. ++ * ++ * The whole namespace is represented by a struct ntsync_device also ++ * backed by a file. ++ * ++ * Both rely on struct file for reference counting. Individual ++ * ntsync_obj objects take a reference to the device when created. ++ */ ++ ++struct ntsync_obj { ++ enum ntsync_type type; ++ ++ union { ++ struct { ++ __u32 count; ++ __u32 max; ++ } sem; ++ } u; ++ ++ struct file *file; ++ struct ntsync_device *dev; ++}; ++ ++struct ntsync_device { ++ struct file *file; ++}; ++ ++static int ntsync_obj_release(struct inode *inode, struct file *file) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ ++ fput(obj->dev->file); ++ kfree(obj); ++ ++ return 0; ++} ++ ++static const struct file_operations ntsync_obj_fops = { ++ .owner = THIS_MODULE, ++ .release = ntsync_obj_release, ++ .llseek = no_llseek, ++}; ++ ++static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, ++ enum ntsync_type type) ++{ ++ struct ntsync_obj *obj; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return NULL; ++ obj->type = type; ++ obj->dev = dev; ++ get_file(dev->file); ++ ++ return obj; ++} ++ ++static int ntsync_obj_get_fd(struct ntsync_obj *obj) ++{ ++ struct file *file; ++ int fd; ++ ++ fd = get_unused_fd_flags(O_CLOEXEC); ++ if (fd < 0) ++ return fd; ++ file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR); ++ if (IS_ERR(file)) { ++ put_unused_fd(fd); ++ return PTR_ERR(file); ++ } ++ obj->file = file; ++ fd_install(fd, file); ++ ++ return fd; ++} ++ ++static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ struct ntsync_obj *sem; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (args.count > args.max) ++ return -EINVAL; ++ ++ sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM); ++ if (!sem) ++ return -ENOMEM; ++ sem->u.sem.count = args.count; ++ sem->u.sem.max = args.max; ++ fd = ntsync_obj_get_fd(sem); ++ if (fd < 0) { ++ kfree(sem); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->sem); ++} ++ + static int ntsync_char_open(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ file->private_data = dev; ++ dev->file = file; + return nonseekable_open(inode, file); + } + + static int ntsync_char_release(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev = file->private_data; ++ ++ kfree(dev); ++ + return 0; + } + + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) + { ++ struct ntsync_device *dev = file->private_data; ++ void __user *argp = (void __user *)parm; ++ + switch (cmd) { ++ case NTSYNC_IOC_CREATE_SEM: ++ return ntsync_create_sem(dev, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +new file mode 100644 +index 000000000000..6a4867a6c97b +--- /dev/null ++++ b/include/uapi/linux/ntsync.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Kernel support for NT synchronization primitive emulation ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#ifndef __LINUX_NTSYNC_H ++#define __LINUX_NTSYNC_H ++ ++#include ++ ++struct ntsync_sem_args { ++ __u32 sem; ++ __u32 count; ++ __u32 max; ++}; ++ ++#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++ ++#endif +-- +2.43.0 diff --git a/SOURCES/0002-NTPatch.patch b/SOURCES/0002-NTPatch.patch deleted file mode 100644 index c233e43..0000000 --- a/SOURCES/0002-NTPatch.patch +++ /dev/null @@ -1,191 +0,0 @@ -These correspond to the NT syscalls NtCreateSemaphore() and NtClose(). -Unlike those functions, however, these ioctls do not handle object names, or -lookup of existing objects, or handle reference counting, but simply create the -underlying primitive. The user space emulator is expected to implement those -functions if they are required. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 25 ++++++++ - 2 files changed, 142 insertions(+) - create mode 100644 include/uapi/linux/ntsync.h - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 84b498e2b2d5..3287b94be351 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -8,23 +8,140 @@ - #include - #include - #include -+#include -+#include -+#include - - #define NTSYNC_NAME "ntsync" - -+enum ntsync_type { -+ NTSYNC_TYPE_SEM, -+}; -+ -+struct ntsync_obj { -+ struct rcu_head rhead; -+ struct kref refcount; -+ -+ enum ntsync_type type; -+ -+ union { -+ struct { -+ __u32 count; -+ __u32 max; -+ } sem; -+ } u; -+}; -+ -+struct ntsync_device { -+ struct xarray objects; -+}; -+ -+static void destroy_obj(struct kref *ref) -+{ -+ struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -+ -+ kfree_rcu(obj, rhead); -+} -+ -+static void put_obj(struct ntsync_obj *obj) -+{ -+ kref_put(&obj->refcount, destroy_obj); -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); -+ -+ file->private_data = dev; - return nonseekable_open(inode, file); - } - - static int ntsync_char_release(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev = file->private_data; -+ struct ntsync_obj *obj; -+ unsigned long id; -+ -+ xa_for_each(&dev->objects, id, obj) -+ put_obj(obj); -+ -+ xa_destroy(&dev->objects); -+ -+ kfree(dev); -+ -+ return 0; -+} -+ -+static void init_obj(struct ntsync_obj *obj) -+{ -+ kref_init(&obj->refcount); -+} -+ -+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 id; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ if (args.count > args.max) -+ return -EINVAL; -+ -+ sem = kzalloc(sizeof(*sem), GFP_KERNEL); -+ if (!sem) -+ return -ENOMEM; -+ -+ init_obj(sem); -+ sem->type = NTSYNC_TYPE_SEM; -+ sem->u.sem.count = args.count; -+ sem->u.sem.max = args.max; -+ -+ ret = xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { -+ kfree(sem); -+ return ret; -+ } -+ -+ return put_user(id, &user_args->sem); -+} -+ -+static int ntsync_delete(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ __u32 id; -+ -+ if (get_user(id, (__u32 __user *)argp)) -+ return -EFAULT; -+ -+ obj = xa_erase(&dev->objects, id); -+ if (!obj) -+ return -EINVAL; -+ -+ put_obj(obj); - return 0; - } - - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -+ struct ntsync_device *dev = file->private_data; -+ void __user *argp = (void __user *)parm; -+ - switch (cmd) { -+ case NTSYNC_IOC_CREATE_SEM: -+ return ntsync_create_sem(dev, argp); -+ case NTSYNC_IOC_DELETE: -+ return ntsync_delete(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -new file mode 100644 -index 000000000000..d97afc138dcc ---- /dev/null -+++ b/include/uapi/linux/ntsync.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * Kernel support for NT synchronization primitive emulation -+ * -+ * Copyright (C) 2021-2022 Elizabeth Figura -+ */ -+ -+#ifndef __LINUX_NTSYNC_H -+#define __LINUX_NTSYNC_H -+ -+#include -+ -+struct ntsync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+}; -+ -+#define NTSYNC_IOC_BASE 0xf7 -+ -+#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -+ struct ntsync_sem_args) -+#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+ -+#endif --- -2.43.0 diff --git a/SOURCES/0002-[PATCH_v2_3_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_POST..patch b/SOURCES/0002-[PATCH_v2_3_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_POST..patch new file mode 100644 index 0000000..78fdffc --- /dev/null +++ b/SOURCES/0002-[PATCH_v2_3_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_POST..patch @@ -0,0 +1,147 @@ +This corresponds to the NT syscall NtReleaseSemaphore(). + +This increases the semaphore's internal counter by the given value, and returns +the previous value. If the counter would overflow the defined maximum, the +function instead fails and returns -EOVERFLOW. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 71 insertions(+), 3 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 20158ec148bc..3c2f743c58b0 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -10,7 +10,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + #define NTSYNC_NAME "ntsync" +@@ -31,23 +33,70 @@ enum ntsync_type { + */ + + struct ntsync_obj { ++ spinlock_t lock; ++ + enum ntsync_type type; + ++ struct file *file; ++ struct ntsync_device *dev; ++ ++ /* The following fields are protected by the object lock. */ + union { + struct { + __u32 count; + __u32 max; + } sem; + } u; +- +- struct file *file; +- struct ntsync_device *dev; + }; + + struct ntsync_device { + struct file *file; + }; + ++/* ++ * Actually change the semaphore state, returning -EOVERFLOW if it is made ++ * invalid. ++ */ ++static int post_sem_state(struct ntsync_obj *sem, __u32 count) ++{ ++ __u32 sum; ++ ++ lockdep_assert_held(&sem->lock); ++ ++ if (check_add_overflow(sem->u.sem.count, count, &sum) || ++ sum > sem->u.sem.max) ++ return -EOVERFLOW; ++ ++ sem->u.sem.count = sum; ++ return 0; ++} ++ ++static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) ++{ ++ __u32 __user *user_args = argp; ++ __u32 prev_count; ++ __u32 args; ++ int ret; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ spin_lock(&sem->lock); ++ ++ prev_count = sem->u.sem.count; ++ ret = post_sem_state(sem, args); ++ ++ spin_unlock(&sem->lock); ++ ++ if (!ret && put_user(prev_count, user_args)) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -58,9 +107,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file) + return 0; + } + ++static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, ++ unsigned long parm) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ void __user *argp = (void __user *)parm; ++ ++ switch (cmd) { ++ case NTSYNC_IOC_SEM_POST: ++ return ntsync_sem_post(obj, argp); ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++ + static const struct file_operations ntsync_obj_fops = { + .owner = THIS_MODULE, + .release = ntsync_obj_release, ++ .unlocked_ioctl = ntsync_obj_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, + }; + +@@ -75,6 +140,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->type = type; + obj->dev = dev; + get_file(dev->file); ++ spin_lock_init(&obj->lock); + + return obj; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 6a4867a6c97b..dcfa38fdc93c 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -18,4 +18,6 @@ struct ntsync_sem_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + ++#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++ + #endif +-- +2.43.0 diff --git a/SOURCES/0003-NTPatch.patch b/SOURCES/0003-NTPatch.patch deleted file mode 100644 index f5f30ce..0000000 --- a/SOURCES/0003-NTPatch.patch +++ /dev/null @@ -1,147 +0,0 @@ -This corresponds to the NT syscall NtReleaseSemaphore(). - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 + - 2 files changed, 78 insertions(+) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 3287b94be351..d1c91c2a4f1a 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -21,9 +21,11 @@ enum ntsync_type { - struct ntsync_obj { - struct rcu_head rhead; - struct kref refcount; -+ spinlock_t lock; - - enum ntsync_type type; - -+ /* The following fields are protected by the object lock. */ - union { - struct { - __u32 count; -@@ -36,6 +38,19 @@ struct ntsync_device { - struct xarray objects; - }; - -+static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id) -+{ -+ struct ntsync_obj *obj; -+ -+ rcu_read_lock(); -+ obj = xa_load(&dev->objects, id); -+ if (obj && !kref_get_unless_zero(&obj->refcount)) -+ obj = NULL; -+ rcu_read_unlock(); -+ -+ return obj; -+} -+ - static void destroy_obj(struct kref *ref) - { - struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -@@ -48,6 +63,18 @@ static void put_obj(struct ntsync_obj *obj) - kref_put(&obj->refcount, destroy_obj); - } - -+static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 id, -+ enum ntsync_type type) -+{ -+ struct ntsync_obj *obj = get_obj(dev, id); -+ -+ if (obj && obj->type != type) { -+ put_obj(obj); -+ return NULL; -+ } -+ return obj; -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { - struct ntsync_device *dev; -@@ -81,6 +108,7 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ spin_lock_init(&obj->lock); - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -131,6 +159,52 @@ static int ntsync_delete(struct ntsync_device *dev, void __user *argp) - return 0; - } - -+/* -+ * Actually change the semaphore state, returning -EOVERFLOW if it is made -+ * invalid. -+ */ -+static int put_sem_state(struct ntsync_obj *sem, __u32 count) -+{ -+ lockdep_assert_held(&sem->lock); -+ -+ if (sem->u.sem.count + count < sem->u.sem.count || -+ sem->u.sem.count + count > sem->u.sem.max) -+ return -EOVERFLOW; -+ -+ sem->u.sem.count += count; -+ return 0; -+} -+ -+static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ sem = get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM); -+ if (!sem) -+ return -EINVAL; -+ -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); -+ -+ spin_unlock(&sem->lock); -+ -+ put_obj(sem); -+ -+ if (!ret && put_user(prev_count, &user_args->count)) -+ ret = -EFAULT; -+ -+ return ret; -+} -+ - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -142,6 +216,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_SEM: -+ return ntsync_put_sem(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index d97afc138dcc..8c610d65f8ef 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -21,5 +21,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ - struct ntsync_sem_args) - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ -+ struct ntsync_sem_args) - - #endif --- -2.43.0 diff --git a/SOURCES/0004-NTPatch.patch b/SOURCES/0003-[PATCH_v2_4_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch similarity index 54% rename from SOURCES/0004-NTPatch.patch rename to SOURCES/0003-[PATCH_v2_4_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch index 8aa8f46..6d57657 100644 --- a/SOURCES/0004-NTPatch.patch +++ b/SOURCES/0003-[PATCH_v2_4_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch @@ -3,29 +3,70 @@ NtWaitForMultipleObjects(). Specifically, it implements the behaviour where the third argument (wait_any) is TRUE, and it does not handle alertable waits. Those features have been split out into separate patches to ease review. +NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike +poll(), it "consumes" objects when they are signaled. For semaphores, this means +decreasing one from the internal counter. At most one object can be consumed by +this function. + +Up to 64 objects can be waited on at once. As soon as one is signaled, the +object with the lowest index is consumed, and that index is returned via the +"index" field. + +A timeout is supported. The timeout is passed as a u64 nanosecond value, which +represents absolute time measured against the MONOTONIC clock. If U64_MAX is +passed, the ioctl waits indefinitely. + +This ioctl validates that all objects belong to the relevant device. This is not +necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be +necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch. + +Wait ioctls need to take a temporary reference to each object being waited on. +As with the device, the reference count of struct file is used for ntsync_obj. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 13 ++ - 2 files changed, 242 insertions(+) + drivers/misc/ntsync.c | 239 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 12 ++ + 2 files changed, 251 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d1c91c2a4f1a..2e8d3c2d51a4 100644 +index 3c2f743c58b0..ad93ca0f8b84 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,6 +23,8 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; +@@ -6,11 +6,16 @@ + */ -+ struct list_head any_waiters; -+ - enum ntsync_type type; + #include ++#include + #include + #include ++#include ++#include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -30,6 +35,8 @@ enum ntsync_type { + * + * Both rely on struct file for reference counting. Individual + * ntsync_obj objects take a reference to the device when created. ++ * Wait operations take a reference to each object being waited on for ++ * the duration of the wait. + */ - /* The following fields are protected by the object lock. */ -@@ -34,6 +36,28 @@ struct ntsync_obj { + struct ntsync_obj { +@@ -47,12 +54,55 @@ struct ntsync_obj { + __u32 max; + } sem; } u; - }; - ++ ++ struct list_head any_waiters; ++}; ++ +struct ntsync_q_entry { + struct list_head node; + struct ntsync_q *q; @@ -46,18 +87,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + __u32 count; + struct ntsync_q_entry entries[]; -+}; -+ - struct ntsync_device { - struct xarray objects; }; -@@ -109,6 +133,26 @@ static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); - spin_lock_init(&obj->lock); -+ INIT_LIST_HEAD(&obj->any_waiters); -+} -+ + + struct ntsync_device { + struct file *file; + }; + +static void try_wake_any_sem(struct ntsync_obj *sem) +{ + struct ntsync_q_entry *entry; @@ -75,26 +110,64 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + wake_up_process(q->task); + } + } - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -194,6 +238,8 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -88,6 +138,8 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) prev_count = sem->u.sem.count; - ret = put_sem_state(sem, args.count); + ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); spin_unlock(&sem->lock); -@@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - return ret; +@@ -141,6 +193,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->dev = dev; + get_file(dev->file); + spin_lock_init(&obj->lock); ++ INIT_LIST_HEAD(&obj->any_waiters); + + return obj; + } +@@ -191,6 +244,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } -+static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) ++static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) +{ ++ struct file *file = fget(fd); ++ struct ntsync_obj *obj; ++ ++ if (file->f_op != &ntsync_obj_fops) { ++ fput(file); ++ return NULL; ++ } ++ ++ obj = file->private_data; ++ if (obj->dev != dev) { ++ fput(file); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++static void put_obj(struct ntsync_obj *obj) ++{ ++ fput(obj->file); ++} ++ ++static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_args *args) ++{ ++ ktime_t timeout = ns_to_ktime(args->timeout); ++ ktime_t *timeout_ptr; + int ret = 0; + ++ timeout_ptr = (args->timeout == U64_MAX ? NULL : &timeout); ++ + do { + if (signal_pending(current)) { + ret = -ERESTARTSYS; @@ -106,7 +179,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + ret = 0; + break; + } -+ ret = schedule_hrtimeout(timeout, HRTIMER_MODE_ABS); ++ ret = schedule_hrtimeout(timeout_ptr, HRTIMER_MODE_ABS); + } while (ret < 0); + __set_current_state(TASK_RUNNING); + @@ -115,16 +188,14 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + +/* + * Allocate and initialize the ntsync_q structure, but do not queue us yet. -+ * Also, calculate the relative timeout. + */ +static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, -+ ktime_t *ret_timeout, struct ntsync_q **ret_q) ++ struct ntsync_q **ret_q) +{ + const __u32 count = args->count; ++ int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; -+ ktime_t timeout = 0; -+ __u32 *ids; + __u32 i, j; + + if (!args->owner || args->pad) @@ -133,31 +204,13 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + -+ if (args->timeout) { -+ struct timespec64 to; -+ -+ if (get_timespec64(&to, u64_to_user_ptr(args->timeout))) -+ return -EFAULT; -+ if (!timespec64_valid(&to)) -+ return -EINVAL; -+ -+ timeout = timespec64_to_ns(&to); -+ } -+ -+ ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL); -+ if (!ids) -+ return -ENOMEM; -+ if (copy_from_user(ids, u64_to_user_ptr(args->objs), -+ array_size(count, sizeof(*ids)))) { -+ kfree(ids); ++ if (copy_from_user(fds, u64_to_user_ptr(args->objs), ++ array_size(count, sizeof(*fds)))) + return -EFAULT; -+ } + + q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); -+ if (!q) { -+ kfree(ids); ++ if (!q) + return -ENOMEM; -+ } + q->task = current; + q->owner = args->owner; + atomic_set(&q->signaled, -1); @@ -165,7 +218,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + for (i = 0; i < count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; -+ struct ntsync_obj *obj = get_obj(dev, ids[i]); ++ struct ntsync_obj *obj = get_obj(dev, fds[i]); + + if (!obj) + goto err; @@ -175,16 +228,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + entry->index = i; + } + -+ kfree(ids); -+ + *ret_q = q; -+ *ret_timeout = timeout; + return 0; + +err: + for (j = 0; j < i; j++) + put_obj(q->entries[j].obj); -+ kfree(ids); + kfree(q); + return -EINVAL; +} @@ -202,7 +251,6 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 +{ + struct ntsync_wait_args args; + struct ntsync_q *q; -+ ktime_t timeout; + int signaled; + __u32 i; + int ret; @@ -210,7 +258,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, &timeout, &q); ++ ret = setup_wait(dev, &args, &q); + if (ret < 0) + return ret; + @@ -240,7 +288,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ ret = ntsync_schedule(q, &args); + + /* and finally, unqueue */ + @@ -272,23 +320,23 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -218,6 +445,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -222,6 +459,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ANY: + return ntsync_wait_any(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 8c610d65f8ef..10f07da7864e 100644 +index dcfa38fdc93c..56b643fab611 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -16,6 +16,17 @@ struct ntsync_sem_args { +@@ -16,7 +16,19 @@ struct ntsync_sem_args { __u32 max; }; @@ -303,16 +351,10 @@ index 8c610d65f8ef..10f07da7864e 100644 + +#define NTSYNC_MAX_WAIT_COUNT 64 + - #define NTSYNC_IOC_BASE 0xf7 + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -@@ -23,5 +34,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) - #define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ - struct ntsync_sem_args) -+#define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ -+ struct ntsync_wait_args) + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 diff --git a/SOURCES/0005-NTPatch.patch b/SOURCES/0004-[PATCH_v2_5_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch similarity index 70% rename from SOURCES/0005-NTPatch.patch rename to SOURCES/0004-[PATCH_v2_5_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch index c63ef03..7d2c890 100644 --- a/SOURCES/0005-NTPatch.patch +++ b/SOURCES/0004-[PATCH_v2_5_31]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch @@ -1,21 +1,20 @@ -This corresponds to part of the functionality of the NT syscall -NtWaitForMultipleObjects(). Specifically, it implements the behaviour where -the third argument (wait_any) is FALSE, and it does not yet handle alertable -waits. +This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are +simultaneously signaled, and then acquires all of them as a single atomic +operation. Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++-- - include/uapi/linux/ntsync.h | 2 + + drivers/misc/ntsync.c | 242 ++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + 2 files changed, 235 insertions(+), 8 deletions(-) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2e8d3c2d51a4..2685363fae9e 100644 +index ad93ca0f8b84..d5759e9a3a8e 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,7 +23,34 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; +@@ -55,7 +55,34 @@ struct ntsync_obj { + } sem; + } u; + /* + * any_waiters is protected by the object lock, but all_waiters is @@ -33,22 +32,22 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + * lock all of the objects, and that means grabbing the wait_all_lock + * below (and, due to lock ordering rules, before locking this object). + * However, wait-all is a rare operation, and grabbing the wait-all -+ * lock for every wake would create unnecessary contention. Therefore we -+ * first check whether all_hint is zero, and, if it is, we skip trying -+ * to wake "all" waiters. ++ * lock for every wake would create unnecessary contention. ++ * Therefore we first check whether all_hint is zero, and, if it is, ++ * we skip trying to wake "all" waiters. + * + * This hint isn't protected by any lock. It might change during the + * course of a wake, but there's no meaningful race there; it's only a + * hint. + * + * Since wait requests must originate from user-space threads, we're -+ * limited here by PID_MAX_LIMIT, so there's no risk of saturation. ++ * limited here by PID_MAX_LIMIT, so there's no risk of overflow. + */ + atomic_t all_hint; + }; - enum ntsync_type type; - -@@ -54,11 +81,25 @@ struct ntsync_q { + struct ntsync_q_entry { +@@ -76,14 +103,99 @@ struct ntsync_q { */ atomic_t signaled; @@ -60,9 +59,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 struct ntsync_device { + /* + * Wait-all operations must atomically grab all objects, and be totally -+ * ordered with respect to each other and wait-any operations. If one -+ * thread is trying to acquire several objects, another thread cannot -+ * touch the object at the same time. ++ * ordered with respect to each other and wait-any operations. ++ * If one thread is trying to acquire several objects, another thread ++ * cannot touch the object at the same time. + * + * We achieve this by grabbing multiple object locks at the same time. + * However, this creates a lock ordering problem. To solve that problem, @@ -71,28 +70,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + */ + spinlock_t wait_all_lock; + - struct xarray objects; + struct file *file; }; -@@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) - if (!dev) - return -ENOMEM; - -+ spin_lock_init(&dev->wait_all_lock); -+ - xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); - - file->private_data = dev; -@@ -132,8 +175,81 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ atomic_set(&obj->all_hint, 0); - spin_lock_init(&obj->lock); - INIT_LIST_HEAD(&obj->any_waiters); -+ INIT_LIST_HEAD(&obj->all_waiters); -+} -+ +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ + lockdep_assert_held(&obj->lock); @@ -162,11 +142,21 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); - } - ++} ++ static void try_wake_any_sem(struct ntsync_obj *sem) -@@ -234,14 +350,29 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - if (!sem) + { + struct ntsync_q_entry *entry; +@@ -123,6 +235,7 @@ static int post_sem_state(struct ntsync_obj *sem, __u32 count) + + static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + { ++ struct ntsync_device *dev = sem->dev; + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; +@@ -134,14 +247,29 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + if (sem->type != NTSYNC_TYPE_SEM) return -EINVAL; - spin_lock(&sem->lock); @@ -175,11 +165,11 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); - prev_count = sem->u.sem.count; -- ret = put_sem_state(sem, args.count); +- ret = post_sem_state(sem, args); - if (!ret) - try_wake_any_sem(sem); + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) { + try_wake_all_obj(dev, sem); + try_wake_any_sem(sem); @@ -192,25 +182,34 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock(&sem->lock); + + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); + + spin_unlock(&sem->lock); + } - put_obj(sem); + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; +@@ -194,6 +322,8 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + get_file(dev->file); + spin_lock_init(&obj->lock); + INIT_LIST_HEAD(&obj->any_waiters); ++ INIT_LIST_HEAD(&obj->all_waiters); ++ atomic_set(&obj->all_hint, 0); -@@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - * Also, calculate the relative timeout. + return obj; + } +@@ -298,7 +428,7 @@ static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_ar + * Allocate and initialize the ntsync_q structure, but do not queue us yet. */ static int setup_wait(struct ntsync_device *dev, - const struct ntsync_wait_args *args, + const struct ntsync_wait_args *args, bool all, - ktime_t *ret_timeout, struct ntsync_q **ret_q) + struct ntsync_q **ret_q) { const __u32 count = args->count; -@@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, +@@ -322,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, q->task = current; q->owner = args->owner; atomic_set(&q->signaled, -1); @@ -218,7 +217,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 q->count = count; for (i = 0; i < count; i++) { -@@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, +@@ -331,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, if (!obj) goto err; @@ -235,16 +234,16 @@ index 2e8d3c2d51a4..2685363fae9e 100644 entry->obj = obj; entry->q = q; entry->index = i; -@@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -366,7 +507,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; -- ret = setup_wait(dev, &args, &timeout, &q); -+ ret = setup_wait(dev, &args, false, &timeout, &q); +- ret = setup_wait(dev, &args, &q); ++ ret = setup_wait(dev, &args, false, &q); if (ret < 0) return ret; -@@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -428,6 +569,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) return ret; } @@ -252,7 +251,6 @@ index 2e8d3c2d51a4..2685363fae9e 100644 +{ + struct ntsync_wait_args args; + struct ntsync_q *q; -+ ktime_t timeout; + int signaled; + __u32 i; + int ret; @@ -260,7 +258,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, true, &timeout, &q); ++ ret = setup_wait(dev, &args, true, &q); + if (ret < 0) + return ret; + @@ -276,7 +274,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather -+ * than obj->lock, so there is no need to acquire it here. ++ * than obj->lock, so there is no need to acquire obj->lock ++ * here. + */ + list_add_tail(&entry->node, &obj->all_waiters); + } @@ -289,7 +288,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ ret = ntsync_schedule(q, &args); + + /* and finally, unqueue */ + @@ -329,29 +328,38 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -445,6 +668,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -436,6 +658,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) + if (!dev) + return -ENOMEM; + ++ spin_lock_init(&dev->wait_all_lock); ++ + file->private_data = dev; + dev->file = file; + return nonseekable_open(inode, file); +@@ -459,6 +683,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); case NTSYNC_IOC_WAIT_ANY: return ntsync_wait_any(dev, argp); default: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 10f07da7864e..a5bed5a39b21 100644 +index 56b643fab611..19c37e27a4f8 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -36,5 +36,7 @@ struct ntsync_wait_args { - struct ntsync_sem_args) - #define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ -+ struct ntsync_wait_args) +@@ -29,6 +29,7 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) ++#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 diff --git a/SOURCES/0006-NTPatch.patch b/SOURCES/0005-[PATCH_v2_6_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch similarity index 58% rename from SOURCES/0006-NTPatch.patch rename to SOURCES/0005-[PATCH_v2_6_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch index 5ed169a..cfd07ce 100644 --- a/SOURCES/0006-NTPatch.patch +++ b/SOURCES/0005-[PATCH_v2_6_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch @@ -1,24 +1,34 @@ This corresponds to the NT syscall NtCreateMutant(). +An NT mutex is recursive, with a 32-bit recursion counter. When acquired via +NtWaitForMultipleObjects(), the recursion counter is incremented by one. + +The OS records the thread which acquired it. However, in order to keep this +driver self-contained, the owning thread ID is managed by user-space, and passed +as a parameter to all relevant ioctls. + +The initial owner and recursion count, if any, are specified when the mutex is +created. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 8 +++++ - 2 files changed, 80 insertions(+) + drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 ++++ + 2 files changed, 74 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2685363fae9e..d48f2ef41341 100644 +index d5759e9a3a8e..6f7086d0440a 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -16,6 +16,7 @@ +@@ -24,6 +24,7 @@ enum ntsync_type { NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, }; - struct ntsync_obj { -@@ -60,6 +61,10 @@ struct ntsync_obj { + /* +@@ -53,6 +54,10 @@ struct ntsync_obj { __u32 count; __u32 max; } sem; @@ -27,9 +37,9 @@ index 2685363fae9e..d48f2ef41341 100644 + __u32 owner; + } mutex; } u; - }; -@@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + /* +@@ -132,6 +137,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) switch (obj->type) { case NTSYNC_TYPE_SEM: return !!obj->u.sem.count; @@ -40,7 +50,7 @@ index 2685363fae9e..d48f2ef41341 100644 } WARN(1, "bad object type %#x\n", obj->type); -@@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, +@@ -174,6 +183,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, case NTSYNC_TYPE_SEM: obj->u.sem.count--; break; @@ -51,7 +61,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } wake_up_process(q->task); -@@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) +@@ -215,6 +228,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) } } @@ -77,11 +87,11 @@ index 2685363fae9e..d48f2ef41341 100644 + } +} + - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - { - struct ntsync_sem_args __user *user_args = argp; -@@ -303,6 +338,38 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - return put_user(id, &user_args->sem); + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -374,6 +409,33 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } +static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) @@ -89,8 +99,7 @@ index 2685363fae9e..d48f2ef41341 100644 + struct ntsync_mutex_args __user *user_args = argp; + struct ntsync_mutex_args args; + struct ntsync_obj *mutex; -+ __u32 id; -+ int ret; ++ int fd; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; @@ -98,28 +107,24 @@ index 2685363fae9e..d48f2ef41341 100644 + if (!args.owner != !args.count) + return -EINVAL; + -+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL); ++ mutex = ntsync_alloc_obj(dev, NTSYNC_TYPE_MUTEX); + if (!mutex) + return -ENOMEM; -+ -+ init_obj(mutex); -+ mutex->type = NTSYNC_TYPE_MUTEX; + mutex->u.mutex.count = args.count; + mutex->u.mutex.owner = args.owner; -+ -+ ret = xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { ++ fd = ntsync_obj_get_fd(mutex); ++ if (fd < 0) { + kfree(mutex); -+ return ret; ++ return fd; + } + -+ return put_user(id, &user_args->mutex); ++ return put_user(fd, &user_args->mutex); +} + - static int ntsync_delete(struct ntsync_device *dev, void __user *argp) + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) { - struct ntsync_obj *obj; -@@ -497,6 +564,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + struct file *file = fget(fd); +@@ -493,6 +555,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) case NTSYNC_TYPE_SEM: try_wake_any_sem(obj); break; @@ -129,7 +134,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } -@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, +@@ -681,6 +746,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, void __user *argp = (void __user *)parm; switch (cmd) { @@ -137,9 +142,9 @@ index 2685363fae9e..d48f2ef41341 100644 + return ntsync_create_mutex(dev, argp); case NTSYNC_IOC_CREATE_SEM: return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: + case NTSYNC_IOC_WAIT_ALL: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index a5bed5a39b21..26d1b3d4847f 100644 +index 19c37e27a4f8..8ac9d419c360 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h @@ -16,6 +16,12 @@ struct ntsync_sem_args { @@ -155,13 +160,13 @@ index a5bed5a39b21..26d1b3d4847f 100644 struct ntsync_wait_args { __u64 timeout; __u64 objs; -@@ -38,5 +44,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ -+ struct ntsync_mutex_args) +@@ -30,6 +36,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) ++#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 diff --git a/SOURCES/0007-NTPatch.patch b/SOURCES/0006-[PATCH_v2_7_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_UNLOCK..patch similarity index 50% rename from SOURCES/0007-NTPatch.patch rename to SOURCES/0006-[PATCH_v2_7_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_UNLOCK..patch index 5ad77ae..97e5ace 100644 --- a/SOURCES/0007-NTPatch.patch +++ b/SOURCES/0006-[PATCH_v2_7_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_UNLOCK..patch @@ -1,24 +1,28 @@ This corresponds to the NT syscall NtReleaseMutant(). +This syscall decrements the mutex's recursion count by one, and returns the +previous value. If the mutex is not owned by the given owner ID, the function +instead fails and returns -EPERM. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 ++ - 2 files changed, 69 insertions(+) + drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 65 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d48f2ef41341..28f43768d1c3 100644 +index 6f7086d0440a..222ebead8eba 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -449,6 +449,71 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) +@@ -312,6 +312,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) return ret; } +/* + * Actually change the mutex state, returning -EPERM if not the owner. + */ -+static int put_mutex_state(struct ntsync_obj *mutex, -+ const struct ntsync_mutex_args *args) ++static int unlock_mutex_state(struct ntsync_obj *mutex, ++ const struct ntsync_mutex_args *args) +{ + lockdep_assert_held(&mutex->lock); + @@ -30,11 +34,11 @@ index d48f2ef41341..28f43768d1c3 100644 + return 0; +} + -+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) ++static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) +{ + struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_device *dev = mutex->dev; + struct ntsync_mutex_args args; -+ struct ntsync_obj *mutex; + __u32 prev_count; + int ret; + @@ -43,8 +47,7 @@ index d48f2ef41341..28f43768d1c3 100644 + if (!args.owner) + return -EINVAL; + -+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX); -+ if (!mutex) ++ if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + + if (atomic_read(&mutex->all_hint) > 0) { @@ -52,7 +55,7 @@ index d48f2ef41341..28f43768d1c3 100644 + spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); + + prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); ++ ret = unlock_mutex_state(mutex, &args); + if (!ret) { + try_wake_all_obj(dev, mutex); + try_wake_any_mutex(mutex); @@ -64,43 +67,40 @@ index d48f2ef41341..28f43768d1c3 100644 + spin_lock(&mutex->lock); + + prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); ++ ret = unlock_mutex_state(mutex, &args); + if (!ret) + try_wake_any_mutex(mutex); + + spin_unlock(&mutex->lock); + } + -+ put_obj(mutex); -+ + if (!ret && put_user(prev_count, &user_args->count)) + ret = -EFAULT; + + return ret; +} + - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) + static int ntsync_obj_release(struct inode *inode, struct file *file) { - int ret = 0; -@@ -738,6 +803,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_MUTEX: -+ return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); - case NTSYNC_IOC_WAIT_ALL: + struct ntsync_obj *obj = file->private_data; +@@ -331,6 +393,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_MUTEX_UNLOCK: ++ return ntsync_mutex_unlock(obj, argp); + default: + return -ENOIOCTLCMD; + } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 26d1b3d4847f..2e44e7e77776 100644 +index 8ac9d419c360..265503d441b1 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -46,5 +46,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ -+ struct ntsync_mutex_args) +@@ -39,5 +39,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) #endif -- diff --git a/SOURCES/0007-[PATCH_v2_8_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_KILL..patch b/SOURCES/0007-[PATCH_v2_8_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_KILL..patch new file mode 100644 index 0000000..ec55ac0 --- /dev/null +++ b/SOURCES/0007-[PATCH_v2_8_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_KILL..patch @@ -0,0 +1,166 @@ +This does not correspond to any NT syscall. Rather, when a thread dies, it +should be called by the NT emulator for each mutex. + +NT mutexes are robust (in the pthread sense). When an NT thread dies, any +mutexes it owned are immediately released. Acquisition of those mutexes by other +threads will return a special value indicating that the mutex was abandoned, +like EOWNERDEAD returned from pthread_mutex_lock(), and EOWNERDEAD is indeed +used here for that purpose. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 71 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 222ebead8eba..a3466be50c45 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -57,6 +57,7 @@ struct ntsync_obj { + struct { + __u32 count; + __u32 owner; ++ bool ownerdead; + } mutex; + } u; + +@@ -109,6 +110,7 @@ struct ntsync_q { + atomic_t signaled; + + bool all; ++ bool ownerdead; + __u32 count; + struct ntsync_q_entry entries[]; + }; +@@ -184,6 +186,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.sem.count--; + break; + case NTSYNC_TYPE_MUTEX: ++ if (obj->u.mutex.ownerdead) ++ q->ownerdead = true; ++ obj->u.mutex.ownerdead = false; + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; +@@ -243,6 +248,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + continue; + + if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (mutex->u.mutex.ownerdead) ++ q->ownerdead = true; ++ mutex->u.mutex.ownerdead = false; + mutex->u.mutex.count++; + mutex->u.mutex.owner = q->owner; + wake_up_process(q->task); +@@ -374,6 +382,62 @@ static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++/* ++ * Actually change the mutex state to mark its owner as dead, ++ * returning -EPERM if not the owner. ++ */ ++static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner) ++{ ++ lockdep_assert_held(&mutex->lock); ++ ++ if (mutex->u.mutex.owner != owner) ++ return -EPERM; ++ ++ mutex->u.mutex.ownerdead = true; ++ mutex->u.mutex.owner = 0; ++ mutex->u.mutex.count = 0; ++ return 0; ++} ++ ++static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_device *dev = mutex->dev; ++ __u32 owner; ++ int ret; ++ ++ if (get_user(owner, (__u32 __user *)argp)) ++ return -EFAULT; ++ if (!owner) ++ return -EINVAL; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ if (atomic_read(&mutex->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) { ++ try_wake_all_obj(dev, mutex); ++ try_wake_any_mutex(mutex); ++ } ++ ++ spin_unlock(&mutex->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&mutex->lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) ++ try_wake_any_mutex(mutex); ++ ++ spin_unlock(&mutex->lock); ++ } ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -395,6 +459,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_sem_post(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); ++ case NTSYNC_IOC_MUTEX_KILL: ++ return ntsync_mutex_kill(obj, argp); + default: + return -ENOIOCTLCMD; + } +@@ -579,6 +645,7 @@ static int setup_wait(struct ntsync_device *dev, + q->owner = args->owner; + atomic_set(&q->signaled, -1); + q->all = all; ++ q->ownerdead = false; + q->count = count; + + for (i = 0; i < count; i++) { +@@ -686,7 +753,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +@@ -767,7 +834,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 265503d441b1..4800941fcbda 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -40,5 +40,6 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) ++#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + + #endif +-- +2.43.0 diff --git a/SOURCES/0008-NTPatch.patch b/SOURCES/0008-NTPatch.patch deleted file mode 100644 index eedfed0..0000000 --- a/SOURCES/0008-NTPatch.patch +++ /dev/null @@ -1,170 +0,0 @@ -This does not correspond to any NT syscall, but rather should be called by the -user-space NT emulator when a thread dies. It is responsible for marking any -mutexes owned by that thread as abandoned. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++- - include/uapi/linux/ntsync.h | 1 + - 2 files changed, 79 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 28f43768d1c3..1173c750c106 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -64,6 +64,7 @@ struct ntsync_obj { - struct { - __u32 count; - __u32 owner; -+ bool ownerdead; - } mutex; - } u; - }; -@@ -87,6 +88,7 @@ struct ntsync_q { - atomic_t signaled; - - bool all; -+ bool ownerdead; - __u32 count; - struct ntsync_q_entry entries[]; - }; -@@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, - obj->u.sem.count--; - break; - case NTSYNC_TYPE_MUTEX: -+ if (obj->u.mutex.ownerdead) -+ q->ownerdead = true; -+ obj->u.mutex.ownerdead = false; - obj->u.mutex.count++; - obj->u.mutex.owner = q->owner; - break; -@@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) - continue; - - if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -+ if (mutex->u.mutex.ownerdead) -+ q->ownerdead = true; -+ mutex->u.mutex.ownerdead = false; - mutex->u.mutex.count++; - mutex->u.mutex.owner = q->owner; - wake_up_process(q->task); -@@ -514,6 +522,71 @@ static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state to mark its owner as dead. -+ */ -+static void put_mutex_ownerdead_state(struct ntsync_obj *mutex) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ mutex->u.mutex.ownerdead = true; -+ mutex->u.mutex.owner = 0; -+ mutex->u.mutex.count = 0; -+} -+ -+static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ unsigned long id; -+ __u32 owner; -+ -+ if (get_user(owner, (__u32 __user *)argp)) -+ return -EFAULT; -+ if (!owner) -+ return -EINVAL; -+ -+ rcu_read_lock(); -+ -+ xa_for_each(&dev->objects, id, obj) { -+ if (!kref_get_unless_zero(&obj->refcount)) -+ continue; -+ -+ if (obj->type != NTSYNC_TYPE_MUTEX) { -+ put_obj(obj); -+ continue; -+ } -+ -+ if (atomic_read(&obj->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_all_obj(dev, obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&obj->lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ } -+ -+ put_obj(obj); -+ } -+ -+ rcu_read_unlock(); -+ -+ return 0; -+} -+ - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev, - q->owner = args->owner; - atomic_set(&q->signaled, -1); - q->all = all; -+ q->ownerdead = false; - q->count = count; - - for (i = 0; i < count; i++) { -@@ -697,7 +771,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -778,7 +852,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -803,6 +877,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_KILL_OWNER: -+ return ntsync_kill_owner(dev, argp); - case NTSYNC_IOC_PUT_MUTEX: - return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 2e44e7e77776..fec9a3993322 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -48,5 +48,6 @@ struct ntsync_wait_args { - struct ntsync_mutex_args) - #define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_KILL_OWNER _IOW (NTSYNC_IOC_BASE, 7, __u32) - - #endif --- -2.43.0 diff --git a/SOURCES/0008-[PATCH_v2_9_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_EVENT..patch b/SOURCES/0008-[PATCH_v2_9_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_EVENT..patch new file mode 100644 index 0000000..7376a14 --- /dev/null +++ b/SOURCES/0008-[PATCH_v2_9_31]_ntsync:_Introduce_NTSYNC_IOC_CREATE_EVENT..patch @@ -0,0 +1,165 @@ +This correspond to the NT syscall NtCreateEvent(). + +An NT event holds a single bit of state denoting whether it is signaled or +unsignaled. + +There are two types of events: manual-reset and automatic-reset. When an +automatic-reset event is acquired via a wait function, its state is reset to +unsignaled. Manual-reset events are not affected by wait functions. + +Whether the event is manual-reset, and its initial state, are specified at +creation time. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 60 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 +++++ + 2 files changed, 67 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index a3466be50c45..17dd47d06e0a 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -25,6 +25,7 @@ + enum ntsync_type { + NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, ++ NTSYNC_TYPE_EVENT, + }; + + /* +@@ -59,6 +60,10 @@ struct ntsync_obj { + __u32 owner; + bool ownerdead; + } mutex; ++ struct { ++ bool manual; ++ bool signaled; ++ } event; + } u; + + /* +@@ -143,6 +148,8 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + if (obj->u.mutex.owner && obj->u.mutex.owner != owner) + return false; + return obj->u.mutex.count < UINT_MAX; ++ case NTSYNC_TYPE_EVENT: ++ return obj->u.event.signaled; + } + + WARN(1, "bad object type %#x\n", obj->type); +@@ -192,6 +199,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; ++ case NTSYNC_TYPE_EVENT: ++ if (!obj->u.event.manual) ++ obj->u.event.signaled = false; ++ break; + } + } + wake_up_process(q->task); +@@ -258,6 +269,26 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + } + } + ++static void try_wake_any_event(struct ntsync_obj *event) ++{ ++ struct ntsync_q_entry *entry; ++ ++ lockdep_assert_held(&event->lock); ++ ++ list_for_each_entry(entry, &event->any_waiters, node) { ++ struct ntsync_q *q = entry->q; ++ ++ if (!event->u.event.signaled) ++ break; ++ ++ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (!event->u.event.manual) ++ event->u.event.signaled = false; ++ wake_up_process(q->task); ++ } ++ } ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -566,6 +597,30 @@ static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->mutex); + } + ++static int ntsync_create_event(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ struct ntsync_obj *event; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ event = ntsync_alloc_obj(dev, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -ENOMEM; ++ event->u.event.manual = args.manual; ++ event->u.event.signaled = args.signaled; ++ fd = ntsync_obj_get_fd(event); ++ if (fd < 0) { ++ kfree(event); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->event); ++} ++ + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) + { + struct file *file = fget(fd); +@@ -689,6 +744,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + case NTSYNC_TYPE_MUTEX: + try_wake_any_mutex(obj); + break; ++ case NTSYNC_TYPE_EVENT: ++ try_wake_any_event(obj); ++ break; + } + } + +@@ -877,6 +935,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + void __user *argp = (void __user *)parm; + + switch (cmd) { ++ case NTSYNC_IOC_CREATE_EVENT: ++ return ntsync_create_event(dev, argp); + case NTSYNC_IOC_CREATE_MUTEX: + return ntsync_create_mutex(dev, argp); + case NTSYNC_IOC_CREATE_SEM: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 4800941fcbda..040cbdb39033 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -22,6 +22,12 @@ struct ntsync_mutex_args { + __u32 count; + }; + ++struct ntsync_event_args { ++ __u32 event; ++ __u32 manual; ++ __u32 signaled; ++}; ++ + struct ntsync_wait_args { + __u64 timeout; + __u64 objs; +@@ -37,6 +43,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) ++#define NTSYNC_IOC_CREATE_EVENT _IOWR('N', 0x87, struct ntsync_event_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) +-- +2.43.0 diff --git a/SOURCES/0009-[PATCH_v2_10_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_SET..patch b/SOURCES/0009-[PATCH_v2_10_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_SET..patch new file mode 100644 index 0000000..58e9472 --- /dev/null +++ b/SOURCES/0009-[PATCH_v2_10_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_SET..patch @@ -0,0 +1,78 @@ +This corresponds to the NT syscall NtSetEvent(). + +This sets the event to the signaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 37 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 38 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 17dd47d06e0a..edfbf11cafe0 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -469,6 +469,41 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_device *dev = event->dev; ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ if (atomic_read(&event->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_all_obj(dev, event); ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ } ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -492,6 +527,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_EVENT_SET: ++ return ntsync_event_set(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 040cbdb39033..af518530bffd 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -48,5 +48,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) ++#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + + #endif +-- +2.43.0 diff --git a/SOURCES/0010-[PATCH_v2_11_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_RESET..patch b/SOURCES/0010-[PATCH_v2_11_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_RESET..patch new file mode 100644 index 0000000..88cdda0 --- /dev/null +++ b/SOURCES/0010-[PATCH_v2_11_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_RESET..patch @@ -0,0 +1,63 @@ +This corresponds to the NT syscall NtResetEvent(). + +This sets the event to the unsignaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 22 ++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 23 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index edfbf11cafe0..fa4c3fa1e496 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -504,6 +504,26 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) ++{ ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = false; ++ ++ spin_unlock(&event->lock); ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -529,6 +549,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp); ++ case NTSYNC_IOC_EVENT_RESET: ++ return ntsync_event_reset(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index af518530bffd..6963356ee3f7 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -49,5 +49,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) ++#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + + #endif +-- +2.43.0 diff --git a/SOURCES/0011-[PATCH_v2_12_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_PULSE..patch b/SOURCES/0011-[PATCH_v2_12_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_PULSE..patch new file mode 100644 index 0000000..76aa1a7 --- /dev/null +++ b/SOURCES/0011-[PATCH_v2_12_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_PULSE..patch @@ -0,0 +1,70 @@ +This corresponds to the NT syscall NtPulseEvent(). + +This wakes up any waiters as if the event had been set, but does not set the +event, instead resetting it if it had been signalled. Thus, for a manual-reset +event, all waiters are woken, whereas for an auto-reset event, at most one +waiter is woken. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 10 ++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index fa4c3fa1e496..b9b4127a6c9f 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -469,7 +469,7 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + +-static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp, bool pulse) + { + struct ntsync_device *dev = event->dev; + __u32 prev_state; +@@ -485,6 +485,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + event->u.event.signaled = true; + try_wake_all_obj(dev, event); + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + spin_unlock(&dev->wait_all_lock); +@@ -494,6 +496,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + prev_state = event->u.event.signaled; + event->u.event.signaled = true; + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + } +@@ -548,9 +552,11 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: +- return ntsync_event_set(obj, argp); ++ return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: + return ntsync_event_reset(obj, argp); ++ case NTSYNC_IOC_EVENT_PULSE: ++ return ntsync_event_set(obj, argp, true); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 6963356ee3f7..72047f36c45d 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -50,5 +50,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) ++#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + + #endif +-- +2.43.0 diff --git a/SOURCES/0012-[PATCH_v2_13_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_READ..patch b/SOURCES/0012-[PATCH_v2_13_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_READ..patch new file mode 100644 index 0000000..e32f7ef --- /dev/null +++ b/SOURCES/0012-[PATCH_v2_13_31]_ntsync:_Introduce_NTSYNC_IOC_SEM_READ..patch @@ -0,0 +1,62 @@ +This corresponds to the NT syscall NtQuerySemaphore(). + +This returns the current count and maximum count of the semaphore. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index b9b4127a6c9f..0daaeeeba051 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -528,6 +528,25 @@ static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ args.sem = 0; ++ spin_lock(&sem->lock); ++ args.count = sem->u.sem.count; ++ args.max = sem->u.sem.max; ++ spin_unlock(&sem->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -547,6 +566,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_SEM_READ: ++ return ntsync_sem_read(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 72047f36c45d..42f51dc4e57e 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -51,5 +51,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) ++#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + + #endif +-- +2.43.0 diff --git a/SOURCES/0013-[PATCH_v2_14_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_READ..patch b/SOURCES/0013-[PATCH_v2_14_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_READ..patch new file mode 100644 index 0000000..b97bd13 --- /dev/null +++ b/SOURCES/0013-[PATCH_v2_14_31]_ntsync:_Introduce_NTSYNC_IOC_MUTEX_READ..patch @@ -0,0 +1,64 @@ +This corresponds to the NT syscall NtQueryMutant(). + +This returns the recursion count, owner, and abandoned state of the mutex. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 23 +++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 0daaeeeba051..b07510035c1f 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -547,6 +547,27 @@ static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) + return 0; + } + ++static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ args.mutex = 0; ++ spin_lock(&mutex->lock); ++ args.count = mutex->u.mutex.count; ++ args.owner = mutex->u.mutex.owner; ++ ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0; ++ spin_unlock(&mutex->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -572,6 +593,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_MUTEX_READ: ++ return ntsync_mutex_read(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 42f51dc4e57e..25f3296cfabf 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -52,5 +52,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) ++#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) + + #endif +-- +2.43.0 diff --git a/SOURCES/0014-[PATCH_v2_15_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_READ..patch b/SOURCES/0014-[PATCH_v2_15_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_READ..patch new file mode 100644 index 0000000..476ae09 --- /dev/null +++ b/SOURCES/0014-[PATCH_v2_15_31]_ntsync:_Introduce_NTSYNC_IOC_EVENT_READ..patch @@ -0,0 +1,62 @@ +This corresponds to the NT syscall NtQueryEvent(). + +This returns the signaled state of the event and whether it is manual-reset. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index b07510035c1f..981a1545192c 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -568,6 +568,25 @@ static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_read(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ args.event = 0; ++ spin_lock(&event->lock); ++ args.manual = event->u.event.manual; ++ args.signaled = event->u.event.signaled; ++ spin_unlock(&event->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -601,6 +620,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_event_reset(obj, argp); + case NTSYNC_IOC_EVENT_PULSE: + return ntsync_event_set(obj, argp, true); ++ case NTSYNC_IOC_EVENT_READ: ++ return ntsync_event_read(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 25f3296cfabf..03c95e5a398f 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -53,5 +53,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + #define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) ++#define NTSYNC_IOC_EVENT_READ _IOR ('N', 0x8d, struct ntsync_event_args) + + #endif +-- +2.43.0 diff --git a/SOURCES/0015-[PATCH_v2_16_31]_ntsync:_Introduce_alertable_waits..patch b/SOURCES/0015-[PATCH_v2_16_31]_ntsync:_Introduce_alertable_waits..patch new file mode 100644 index 0000000..ce53af5 --- /dev/null +++ b/SOURCES/0015-[PATCH_v2_16_31]_ntsync:_Introduce_alertable_waits..patch @@ -0,0 +1,184 @@ +NT waits can optionally be made "alertable". This is a special channel for +thread wakeup that is mildly similar to SIGIO. A thread has an internal single +bit of "alerted" state, and if a thread is made alerted while an alertable wait, +the wait will return a special value, consume the "alerted" state, and will not +consume any of its objects. + +Alerts are implemented using events; the user-space NT emulator is expected to +create an internal ntsync event for each thread and pass that event to wait +functions. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 68 ++++++++++++++++++++++++++++++++----- + include/uapi/linux/ntsync.h | 2 +- + 2 files changed, 60 insertions(+), 10 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 981a1545192c..0055b4671808 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -808,22 +808,29 @@ static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, bool all, + struct ntsync_q **ret_q) + { ++ int fds[NTSYNC_MAX_WAIT_COUNT + 1]; + const __u32 count = args->count; +- int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; ++ __u32 total_count; + __u32 i, j; + +- if (!args->owner || args->pad) ++ if (!args->owner) + return -EINVAL; + + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + ++ total_count = count; ++ if (args->alert) ++ total_count++; ++ + if (copy_from_user(fds, u64_to_user_ptr(args->objs), + array_size(count, sizeof(*fds)))) + return -EFAULT; ++ if (args->alert) ++ fds[count] = args->alert; + +- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); ++ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL); + if (!q) + return -ENOMEM; + q->task = current; +@@ -833,7 +840,7 @@ static int setup_wait(struct ntsync_device *dev, + q->ownerdead = false; + q->count = count; + +- for (i = 0; i < count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = get_obj(dev, fds[i]); + +@@ -883,9 +890,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_wait_args args; ++ __u32 i, total_count; + struct ntsync_q *q; + int signaled; +- __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) +@@ -895,9 +902,13 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + if (ret < 0) + return ret; + ++ total_count = args.count; ++ if (args.alert) ++ total_count++; ++ + /* queue ourselves */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -906,9 +917,15 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + spin_unlock(&obj->lock); + } + +- /* check if we are already signaled */ ++ /* ++ * Check if we are already signaled. ++ * ++ * Note that the API requires that normal objects are checked before ++ * the alert event. Hence we queue the alert event last, and check ++ * objects in order. ++ */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_obj *obj = q->entries[i].obj; + + if (atomic_read(&q->signaled) != -1) +@@ -925,7 +942,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + + /* and finally, unqueue */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -985,6 +1002,14 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + */ + list_add_tail(&entry->node, &obj->all_waiters); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_add_tail(&entry->node, &obj->any_waiters); ++ spin_unlock(&obj->lock); ++ } + + /* check if we are already signaled */ + +@@ -992,6 +1017,21 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + spin_unlock(&dev->wait_all_lock); + ++ /* ++ * Check if the alert event is signaled, making sure to do so only ++ * after checking if the other objects are signaled. ++ */ ++ ++ if (args.alert) { ++ struct ntsync_obj *obj = q->entries[args.count].obj; ++ ++ if (atomic_read(&q->signaled) == -1) { ++ spin_lock(&obj->lock); ++ try_wake_any_obj(obj); ++ spin_unlock(&obj->lock); ++ } ++ } ++ + /* sleep */ + + ret = ntsync_schedule(q, &args); +@@ -1014,6 +1054,16 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + put_obj(obj); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_del(&entry->node); ++ spin_unlock(&obj->lock); ++ ++ put_obj(obj); ++ } + + spin_unlock(&dev->wait_all_lock); + +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 03c95e5a398f..555ae81b479a 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -34,7 +34,7 @@ struct ntsync_wait_args { + __u32 count; + __u32 owner; + __u32 index; +- __u32 pad; ++ __u32 alert; + }; + + #define NTSYNC_MAX_WAIT_COUNT 64 +-- +2.43.0 diff --git a/SOURCES/0016-[PATCH_v2_17_31]_ntsync:_Allow_waits_to_use_the_REALTIME_clock..patch b/SOURCES/0016-[PATCH_v2_17_31]_ntsync:_Allow_waits_to_use_the_REALTIME_clock..patch new file mode 100644 index 0000000..6e15e88 --- /dev/null +++ b/SOURCES/0016-[PATCH_v2_17_31]_ntsync:_Allow_waits_to_use_the_REALTIME_clock..patch @@ -0,0 +1,79 @@ +NtWaitForMultipleObjects() can receive a timeout in two forms, relative or +absolute. Relative timeouts are unaffected by changes to the system time and do +not count down while the system suspends; for absolute timeouts the opposite is +true. + +In order to make the interface and implementation simpler, the ntsync driver +only deals in absolute timeouts. However, we need to be able to emulate both +behaviours apropos suspension and time adjustment, which is achieved by allowing +either the MONOTONIC or REALTIME clock to be used. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 9 ++++++++- + include/uapi/linux/ntsync.h | 4 ++++ + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 0055b4671808..f54c81dada3d 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -778,11 +778,15 @@ static void put_obj(struct ntsync_obj *obj) + static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_args *args) + { + ktime_t timeout = ns_to_ktime(args->timeout); ++ clockid_t clock = CLOCK_MONOTONIC; + ktime_t *timeout_ptr; + int ret = 0; + + timeout_ptr = (args->timeout == U64_MAX ? NULL : &timeout); + ++ if (args->flags & NTSYNC_WAIT_REALTIME) ++ clock = CLOCK_REALTIME; ++ + do { + if (signal_pending(current)) { + ret = -ERESTARTSYS; +@@ -794,7 +798,7 @@ static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_ar + ret = 0; + break; + } +- ret = schedule_hrtimeout(timeout_ptr, HRTIMER_MODE_ABS); ++ ret = schedule_hrtimeout_range_clock(timeout_ptr, 0, HRTIMER_MODE_ABS, clock); + } while (ret < 0); + __set_current_state(TASK_RUNNING); + +@@ -817,6 +821,9 @@ static int setup_wait(struct ntsync_device *dev, + if (!args->owner) + return -EINVAL; + ++ if (args->pad || (args->flags & ~NTSYNC_WAIT_REALTIME)) ++ return -EINVAL; ++ + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 555ae81b479a..b5e835d8dba8 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -28,6 +28,8 @@ struct ntsync_event_args { + __u32 signaled; + }; + ++#define NTSYNC_WAIT_REALTIME 0x1 ++ + struct ntsync_wait_args { + __u64 timeout; + __u64 objs; +@@ -35,6 +37,8 @@ struct ntsync_wait_args { + __u32 owner; + __u32 index; + __u32 alert; ++ __u32 flags; ++ __u32 pad; + }; + + #define NTSYNC_MAX_WAIT_COUNT 64 +-- +2.43.0 diff --git "a/SOURCES/0017-[PATCH_v2_18_31]_selftests:_ntsync:_Add_some_tests_for_semaphore\n_state..patch" "b/SOURCES/0017-[PATCH_v2_18_31]_selftests:_ntsync:_Add_some_tests_for_semaphore\n_state..patch" new file mode 100644 index 0000000..5d8c716 --- /dev/null +++ "b/SOURCES/0017-[PATCH_v2_18_31]_selftests:_ntsync:_Add_some_tests_for_semaphore\n_state..patch" @@ -0,0 +1,208 @@ +Wine has tests for its synchronization primitives, but these are more accessible +to kernel developers, and also allow us to test some edge cases that Wine does +not care about. + +This patch adds tests for semaphore-specific ioctls NTSYNC_IOC_SEM_POST and +NTSYNC_IOC_SEM_READ, and waiting on semaphores. + +Signed-off-by: Elizabeth Figura +--- + tools/testing/selftests/Makefile | 1 + + .../testing/selftests/drivers/ntsync/Makefile | 8 + + tools/testing/selftests/drivers/ntsync/config | 1 + + .../testing/selftests/drivers/ntsync/ntsync.c | 149 ++++++++++++++++++ + 4 files changed, 159 insertions(+) + create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile + create mode 100644 tools/testing/selftests/drivers/ntsync/config + create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index 15b6a111c3be..6c714a4e6478 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -15,6 +15,7 @@ TARGETS += cpu-hotplug + TARGETS += damon + TARGETS += dmabuf-heaps + TARGETS += drivers/dma-buf ++TARGETS += drivers/ntsync + TARGETS += drivers/s390x/uvdevice + TARGETS += drivers/net/bonding + TARGETS += drivers/net/team +diff --git a/tools/testing/selftests/drivers/ntsync/Makefile b/tools/testing/selftests/drivers/ntsync/Makefile +new file mode 100644 +index 000000000000..a34da5ccacf0 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only ++TEST_GEN_PROGS := ntsync ++ ++top_srcdir =../../../../.. ++CFLAGS += -I$(top_srcdir)/usr/include ++LDLIBS += -lpthread ++ ++include ../../lib.mk +diff --git a/tools/testing/selftests/drivers/ntsync/config b/tools/testing/selftests/drivers/ntsync/config +new file mode 100644 +index 000000000000..60539c826d06 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/config +@@ -0,0 +1 @@ ++CONFIG_WINESYNC=y +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +new file mode 100644 +index 000000000000..1e145c6dfded +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Various unit tests for the "ntsync" synchronization primitive driver. ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kselftest_harness.h" ++ ++static int read_sem_state(int sem, __u32 *count, __u32 *max) ++{ ++ struct ntsync_sem_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args); ++ *count = args.count; ++ *max = args.max; ++ return ret; ++} ++ ++#define check_sem_state(sem, count, max) \ ++ ({ \ ++ __u32 __count, __max; \ ++ int ret = read_sem_state((sem), &__count, &__max); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((max), __max); \ ++ }) ++ ++static int post_sem(int sem, __u32 *count) ++{ ++ return ioctl(sem, NTSYNC_IOC_SEM_POST, count); ++} ++ ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ struct ntsync_wait_args args = {0}; ++ struct timespec timeout; ++ int ret; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec; ++ args.count = count; ++ args.objs = (uintptr_t)objs; ++ args.owner = owner; ++ args.index = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ *index = args.index; ++ return ret; ++} ++ ++TEST(semaphore_state) ++{ ++ struct ntsync_sem_args sem_args; ++ struct timespec timeout; ++ __u32 count, index; ++ int fd, ret, sem; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 3; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ sem = sem_args.sem; ++ check_sem_state(sem, 2, 2); ++ ++ count = 0; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_sem_state(sem, 2, 2); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 1, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 0, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ count = 3; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 0, 2); ++ ++ count = 2; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 1, 2); ++ ++ count = ~0u; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 1, 2); ++ ++ close(sem); ++ ++ close(fd); ++} ++ ++TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0018-[PATCH_v2_19_31]_selftests:_ntsync:_Add_some_tests_for_mutex\n_state..patch" "b/SOURCES/0018-[PATCH_v2_19_31]_selftests:_ntsync:_Add_some_tests_for_mutex\n_state..patch" new file mode 100644 index 0000000..316e7d1 --- /dev/null +++ "b/SOURCES/0018-[PATCH_v2_19_31]_selftests:_ntsync:_Add_some_tests_for_mutex\n_state..patch" @@ -0,0 +1,222 @@ +Test mutex-specific ioctls NTSYNC_IOC_MUTEX_UNLOCK and NTSYNC_IOC_MUTEX_READ, +and waiting on mutexes. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 196 ++++++++++++++++++ + 1 file changed, 196 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 1e145c6dfded..7cd0f40594fd 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -40,6 +40,39 @@ static int post_sem(int sem, __u32 *count) + return ioctl(sem, NTSYNC_IOC_SEM_POST, count); + } + ++static int read_mutex_state(int mutex, __u32 *count, __u32 *owner) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args); ++ *count = args.count; ++ *owner = args.owner; ++ return ret; ++} ++ ++#define check_mutex_state(mutex, count, owner) \ ++ ({ \ ++ __u32 __count, __owner; \ ++ int ret = read_mutex_state((mutex), &__count, &__owner); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((owner), __owner); \ ++ }) ++ ++static int unlock_mutex(int mutex, __u32 owner, __u32 *count) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ args.owner = owner; ++ args.count = 0xdeadbeef; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args); ++ *count = args.count; ++ return ret; ++} ++ + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; +@@ -146,4 +179,167 @@ TEST(semaphore_state) + close(fd); + } + ++TEST(mutex_state) ++{ ++ struct ntsync_mutex_args mutex_args; ++ __u32 owner, count, index; ++ struct timespec timeout; ++ int fd, ret, mutex; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 0; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 2; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 2; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 0, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 2, 456); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 0; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 1, 456); ++ ++ owner = 456; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = ~0u; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, ~0u, 123); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0019-[PATCH_v2_20_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ANY..patch" "b/SOURCES/0019-[PATCH_v2_20_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ANY..patch" new file mode 100644 index 0000000..6484738 --- /dev/null +++ "b/SOURCES/0019-[PATCH_v2_20_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ANY..patch" @@ -0,0 +1,139 @@ +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ANY, when objects are +considered signaled or not signaled, and how they are affected by a successful +wait. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 119 ++++++++++++++++++ + 1 file changed, 119 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 7cd0f40594fd..40ad8cbd3138 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -342,4 +342,123 @@ TEST(mutex_state) + close(fd); + } + ++TEST(test_wait_any) ++{ ++ int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret; ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count, i; ++ struct timespec timeout; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ /* test waiting on the same object twice */ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 0, NULL, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ for (i = 0; i < NTSYNC_MAX_WAIT_COUNT + 1; ++i) ++ objs[i] = sem_args.sem; ++ ++ ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT + 1, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ ret = wait_any(fd, -1, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0020-[PATCH_v2_21_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ALL..patch" "b/SOURCES/0020-[PATCH_v2_21_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ALL..patch" new file mode 100644 index 0000000..ebe93e0 --- /dev/null +++ "b/SOURCES/0020-[PATCH_v2_21_31]_selftests:_ntsync:_Add_some_tests_for\n_NTSYNC_IOC_WAIT_ALL..patch" @@ -0,0 +1,136 @@ +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ALL, and when objects +are considered simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 99 ++++++++++++++++++- + 1 file changed, 97 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 40ad8cbd3138..c0f372167557 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,7 +73,8 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + +-static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++static int wait_objs(int fd, unsigned long request, __u32 count, ++ const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -86,11 +87,21 @@ static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *in + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; +- ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ ret = ioctl(fd, request, &args); + *index = args.index; + return ret; + } + ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++} ++ ++static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++} ++ + TEST(semaphore_state) + { + struct ntsync_sem_args sem_args; +@@ -461,4 +472,88 @@ TEST(test_wait_any) + close(fd); + } + ++TEST(test_wait_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ count = 3; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 2, 3); ++ check_mutex_state(mutex_args.mutex, 3, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ /* test waiting on the same object twice */ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0021-[PATCH_v2_22_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ANY..patch" "b/SOURCES/0021-[PATCH_v2_22_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ANY..patch" new file mode 100644 index 0000000..d813930 --- /dev/null +++ "b/SOURCES/0021-[PATCH_v2_22_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ANY..patch" @@ -0,0 +1,169 @@ +Test contended "wait-for-any" waits, to make sure that scheduling and wakeup +logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 150 ++++++++++++++++++ + 1 file changed, 150 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index c0f372167557..993f5db23768 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -556,4 +556,154 @@ TEST(test_wait_all) + close(fd); + } + ++struct wake_args { ++ int fd; ++ int obj; ++}; ++ ++struct wait_args { ++ int fd; ++ unsigned long request; ++ struct ntsync_wait_args *args; ++ int ret; ++ int err; ++}; ++ ++static void *wait_thread(void *arg) ++{ ++ struct wait_args *args = arg; ++ ++ args->ret = ioctl(args->fd, args->request, args->args); ++ args->err = errno; ++ return NULL; ++} ++ ++static __u64 get_abs_timeout(unsigned int ms) ++{ ++ struct timespec timeout; ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000); ++} ++ ++static int wait_for_thread(pthread_t thread, unsigned int ms) ++{ ++ struct timespec timeout; ++ ++ clock_gettime(CLOCK_REALTIME, &timeout); ++ timeout.tv_nsec += ms * 1000000; ++ timeout.tv_sec += (timeout.tv_nsec / 1000000000); ++ timeout.tv_nsec %= 1000000000; ++ return pthread_timedjoin_np(thread, NULL, &timeout); ++} ++ ++TEST(wake_any) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ /* test waking the semaphore */ ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ wait_args.index = 0xdeadbeef; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 0, 3); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(0, wait_args.index); ++ ++ /* test waking the mutex */ ++ ++ /* first grab it again for owner 123 */ ++ ret = wait_any(fd, 1, &mutex_args.mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.owner = 456; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, mutex_args.count); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0022-[PATCH_v2_23_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ALL..patch" "b/SOURCES/0022-[PATCH_v2_23_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ALL..patch" new file mode 100644 index 0000000..053e2c7 --- /dev/null +++ "b/SOURCES/0022-[PATCH_v2_23_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_WINESYNC_IOC_WAIT_ALL..patch" @@ -0,0 +1,118 @@ +Test contended "wait-for-all" waits, to make sure that scheduling and wakeup +logic works correctly, and that the wait only exits once objects are all +simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 993f5db23768..b77fb0b2c4b1 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -706,4 +706,102 @@ TEST(wake_any) + close(fd); + } + ++TEST(wake_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0023-[PATCH_v2_24_31]_selftests:_ntsync:_Add_some_tests_for\n_manual-reset_event_state..patch" "b/SOURCES/0023-[PATCH_v2_24_31]_selftests:_ntsync:_Add_some_tests_for\n_manual-reset_event_state..patch" new file mode 100644 index 0000000..ace9ac0 --- /dev/null +++ "b/SOURCES/0023-[PATCH_v2_24_31]_selftests:_ntsync:_Add_some_tests_for\n_manual-reset_event_state..patch" @@ -0,0 +1,118 @@ +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for manual-reset events, and +waiting on manual-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 89 +++++++++++++++++++ + 1 file changed, 89 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index b77fb0b2c4b1..b6481c2b85cc 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,6 +73,27 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + ++static int read_event_state(int event, __u32 *signaled, __u32 *manual) ++{ ++ struct ntsync_event_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args); ++ *signaled = args.signaled; ++ *manual = args.manual; ++ return ret; ++} ++ ++#define check_event_state(event, signaled, manual) \ ++ ({ \ ++ __u32 __signaled, __manual; \ ++ int ret = read_event_state((event), &__signaled, &__manual); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((signaled), __signaled); \ ++ EXPECT_EQ((manual), __manual); \ ++ }) ++ + static int wait_objs(int fd, unsigned long request, __u32 count, + const int *objs, __u32 owner, __u32 *index) + { +@@ -353,6 +374,74 @@ TEST(mutex_state) + close(fd); + } + ++TEST(manual_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 1; ++ event_args.signaled = 0; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ check_event_state(event, 0, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 1, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret; +-- +2.43.0 diff --git "a/SOURCES/0024-[PATCH_v2_25_31]_selftests:_ntsync:_Add_some_tests_for_auto-reset\n_event_state..patch" "b/SOURCES/0024-[PATCH_v2_25_31]_selftests:_ntsync:_Add_some_tests_for_auto-reset\n_event_state..patch" new file mode 100644 index 0000000..3989a16 --- /dev/null +++ "b/SOURCES/0024-[PATCH_v2_25_31]_selftests:_ntsync:_Add_some_tests_for_auto-reset\n_event_state..patch" @@ -0,0 +1,81 @@ +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for auto-reset events, and +waiting on auto-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 59 +++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index b6481c2b85cc..12ccb4ec28e4 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -442,6 +442,65 @@ TEST(manual_event_state) + close(fd); + } + ++TEST(auto_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 0; ++ event_args.signaled = 1; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ ++ check_event_state(event, 1, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 0, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret; +-- +2.43.0 diff --git "a/SOURCES/0025-[PATCH_v2_26_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_events..patch" "b/SOURCES/0025-[PATCH_v2_26_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_events..patch" new file mode 100644 index 0000000..832a88f --- /dev/null +++ "b/SOURCES/0025-[PATCH_v2_26_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_with_events..patch" @@ -0,0 +1,259 @@ +Expand the contended wait tests, which previously only covered events and +semaphores, to cover events as well. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 151 +++++++++++++++++- + 1 file changed, 147 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 12ccb4ec28e4..5d17eff6a370 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -622,6 +622,7 @@ TEST(test_wait_any) + + TEST(test_wait_all) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 owner, index, count; +@@ -644,6 +645,11 @@ TEST(test_wait_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; + +@@ -692,6 +698,14 @@ TEST(test_wait_all) + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 123); + ++ objs[0] = sem_args.sem; ++ objs[1] = event_args.event; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_event_state(event_args.event, 1, 1); ++ + /* test waiting on the same object twice */ + objs[0] = objs[1] = sem_args.sem; + ret = wait_all(fd, 2, objs, 123, &index); +@@ -700,6 +714,7 @@ TEST(test_wait_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(event_args.event); + + close(fd); + } +@@ -746,12 +761,13 @@ static int wait_for_thread(pthread_t thread, unsigned int ms) + + TEST(wake_any) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; ++ __u32 count, index, signaled; + int objs[2], fd, ret; +- __u32 count, index; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -833,10 +849,101 @@ TEST(wake_any) + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + ++ /* test waking events */ ++ ++ event_args.manual = false; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ ++ event_args.manual = true; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 1, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ + /* delete an object while it's being waited on */ + + wait_args.timeout = get_abs_timeout(200); + wait_args.owner = 123; ++ objs[1] = mutex_args.mutex; + ret = pthread_create(&thread, NULL, wait_thread, &thread_args); + EXPECT_EQ(0, ret); + +@@ -856,12 +963,14 @@ TEST(wake_any) + + TEST(wake_all) + { ++ struct ntsync_event_args manual_event_args = {0}; ++ struct ntsync_event_args auto_event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; +- int objs[2], fd, ret; +- __u32 count, index; ++ __u32 count, index, signaled; ++ int objs[4], fd, ret; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -881,12 +990,24 @@ TEST(wake_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ manual_event_args.manual = true; ++ manual_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args); ++ EXPECT_EQ(0, ret); ++ ++ auto_event_args.manual = false; ++ auto_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; ++ objs[2] = manual_event_args.event; ++ objs[3] = auto_event_args.event; + + wait_args.timeout = get_abs_timeout(1000); + wait_args.objs = (uintptr_t)objs; +- wait_args.count = 2; ++ wait_args.count = 4; + wait_args.owner = 456; + thread_args.fd = fd; + thread_args.args = &wait_args; +@@ -920,12 +1041,32 @@ TEST(wake_all) + + check_mutex_state(mutex_args.mutex, 0, 0); + ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ + count = 2; + ret = post_sem(sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 2, 3); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 456); ++ check_event_state(manual_event_args.event, 1, 1); ++ check_event_state(auto_event_args.event, 0, 0); + + ret = wait_for_thread(thread, 100); + EXPECT_EQ(0, ret); +@@ -943,6 +1084,8 @@ TEST(wake_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(manual_event_args.event); ++ close(auto_event_args.event); + + ret = wait_for_thread(thread, 200); + EXPECT_EQ(0, ret); +-- +2.43.0 diff --git a/SOURCES/0026-[PATCH_v2_27_31]_selftests:_ntsync:_Add_tests_for_alertable_waits..patch b/SOURCES/0026-[PATCH_v2_27_31]_selftests:_ntsync:_Add_tests_for_alertable_waits..patch new file mode 100644 index 0000000..b8f967b --- /dev/null +++ b/SOURCES/0026-[PATCH_v2_27_31]_selftests:_ntsync:_Add_tests_for_alertable_waits..patch @@ -0,0 +1,223 @@ +Test the "alert" functionality of NTSYNC_IOC_WAIT_ALL and NTSYNC_IOC_WAIT_ANY, +when a wait is woken with an alert and when it is woken by an object. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 179 +++++++++++++++++- + 1 file changed, 176 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 5d17eff6a370..5465a16d38b3 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -95,7 +95,7 @@ static int read_event_state(int event, __u32 *signaled, __u32 *manual) + }) + + static int wait_objs(int fd, unsigned long request, __u32 count, +- const int *objs, __u32 owner, __u32 *index) ++ const int *objs, __u32 owner, int alert, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -108,6 +108,7 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; ++ args.alert = alert; + ret = ioctl(fd, request, &args); + *index = args.index; + return ret; +@@ -115,12 +116,26 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index); + } + + static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index); ++} ++ ++static int wait_any_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, ++ count, objs, owner, alert, index); ++} ++ ++static int wait_all_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, ++ count, objs, owner, alert, index); + } + + TEST(semaphore_state) +@@ -1095,4 +1110,162 @@ TEST(wake_all) + close(fd); + } + ++TEST(alert_any) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(objs[0], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ ++TEST(alert_all) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 2; ++ ret = post_sem(objs[1], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git "a/SOURCES/0027-[PATCH_v2_28_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_via_alerts..patch" "b/SOURCES/0027-[PATCH_v2_28_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_via_alerts..patch" new file mode 100644 index 0000000..5e0734b --- /dev/null +++ "b/SOURCES/0027-[PATCH_v2_28_31]_selftests:_ntsync:_Add_some_tests_for_wakeup\n_signaling_via_alerts..patch" @@ -0,0 +1,110 @@ +Expand the alert tests to cover alerting a thread mid-wait, to test that the +relevant scheduling logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 5465a16d38b3..968874d7e325 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -1113,9 +1113,12 @@ TEST(wake_all) + TEST(alert_any) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 index, count, signaled; ++ struct wait_args thread_args; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1163,6 +1166,34 @@ TEST(alert_any) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +@@ -1199,9 +1230,12 @@ TEST(alert_any) + TEST(alert_all) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; + __u32 index, count, signaled; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1235,6 +1269,34 @@ TEST(alert_all) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +-- +2.43.0 diff --git "a/SOURCES/0028-[PATCH_v2_29_31]_selftests:_ntsync:_Add_a_stress_test_for\n_contended_waits..patch" "b/SOURCES/0028-[PATCH_v2_29_31]_selftests:_ntsync:_Add_a_stress_test_for\n_contended_waits..patch" new file mode 100644 index 0000000..5fcc536 --- /dev/null +++ "b/SOURCES/0028-[PATCH_v2_29_31]_selftests:_ntsync:_Add_a_stress_test_for\n_contended_waits..patch" @@ -0,0 +1,97 @@ +Test a more realistic usage pattern, and one with heavy contention, in order to +actually exercise ntsync's internal synchronization. + +This test has several threads in a tight loop acquiring a mutex, modifying some +shared data, and then releasing the mutex. At the end we check if the data is +consistent. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 74 +++++++++++++++++++ + 1 file changed, 74 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 968874d7e325..5fa2c9a0768c 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -1330,4 +1330,78 @@ TEST(alert_all) + close(fd); + } + ++#define STRESS_LOOPS 10000 ++#define STRESS_THREADS 4 ++ ++static unsigned int stress_counter; ++static int stress_device, stress_start_event, stress_mutex; ++ ++static void *stress_thread(void *arg) ++{ ++ struct ntsync_wait_args wait_args = {0}; ++ __u32 index, count, i; ++ int ret; ++ ++ wait_args.timeout = UINT64_MAX; ++ wait_args.count = 1; ++ wait_args.objs = (uintptr_t)&stress_start_event; ++ wait_args.owner = gettid(); ++ wait_args.index = 0xdeadbeef; ++ ++ ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args); ++ ++ wait_args.objs = (uintptr_t)&stress_mutex; ++ ++ for (i = 0; i < STRESS_LOOPS; ++i) { ++ ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args); ++ ++ ++stress_counter; ++ ++ unlock_mutex(stress_mutex, wait_args.owner, &count); ++ } ++ ++ return NULL; ++} ++ ++TEST(stress_wait) ++{ ++ struct ntsync_event_args event_args; ++ struct ntsync_mutex_args mutex_args; ++ pthread_t threads[STRESS_THREADS]; ++ __u32 signaled, i; ++ int ret; ++ ++ stress_device = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, stress_device); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ ret = ioctl(stress_device, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ stress_mutex = mutex_args.mutex; ++ ++ event_args.manual = 1; ++ event_args.signaled = 0; ++ ret = ioctl(stress_device, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ stress_start_event = event_args.event; ++ ++ for (i = 0; i < STRESS_THREADS; ++i) ++ pthread_create(&threads[i], NULL, stress_thread, NULL); ++ ++ ret = ioctl(stress_start_event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ for (i = 0; i < STRESS_THREADS; ++i) { ++ ret = pthread_join(threads[i], NULL); ++ EXPECT_EQ(0, ret); ++ } ++ ++ EXPECT_EQ(STRESS_LOOPS * STRESS_THREADS, stress_counter); ++ ++ close(stress_start_event); ++ close(stress_mutex); ++ close(stress_device); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 diff --git a/SOURCES/0029-[PATCH_v2_30_31]_maintainers:_Add_an_entry_for_ntsync..patch b/SOURCES/0029-[PATCH_v2_30_31]_maintainers:_Add_an_entry_for_ntsync..patch new file mode 100644 index 0000000..f7e2bd6 --- /dev/null +++ b/SOURCES/0029-[PATCH_v2_30_31]_maintainers:_Add_an_entry_for_ntsync..patch @@ -0,0 +1,29 @@ +Add myself as maintainer, supported by CodeWeavers. + +Signed-off-by: Elizabeth Figura +--- + MAINTAINERS | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 9ed4d3868539..d83dd35d9f73 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15595,6 +15595,15 @@ T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git + F: Documentation/filesystems/ntfs3.rst + F: fs/ntfs3/ + ++NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER ++M: Elizabeth Figura ++L: wine-devel@winehq.org ++S: Supported ++F: Documentation/userspace-api/ntsync.rst ++F: drivers/misc/ntsync.c ++F: include/uapi/linux/ntsync.h ++F: tools/testing/selftests/drivers/ntsync/ ++ + NUBUS SUBSYSTEM + M: Finn Thain + L: linux-m68k@lists.linux-m68k.org +-- +2.43.0 diff --git a/SOURCES/gpl_patch.patch b/SOURCES/gpl_patch.patch new file mode 100644 index 0000000..4b0efa7 --- /dev/null +++ b/SOURCES/gpl_patch.patch @@ -0,0 +1,19 @@ +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 4102108..72474d8 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -406,7 +406,7 @@ void __rcu_read_lock(void) + WRITE_ONCE(current->rcu_read_unlock_special.b.need_qs, true); + barrier(); /* critical section after entry code. */ + } +-EXPORT_SYMBOL_GPL(__rcu_read_lock); ++EXPORT_SYMBOL(__rcu_read_lock); + + /* + * Preemptible RCU implementation for rcu_read_unlock(). +@@ -431,7 +431,7 @@ void __rcu_read_unlock(void) + WARN_ON_ONCE(rrln < 0 || rrln > RCU_NEST_PMAX); + } + } +-EXPORT_SYMBOL_GPL(__rcu_read_unlock); ++EXPORT_SYMBOL(__rcu_read_unlock); diff --git a/SPECS/linux-zen.spec b/SPECS/linux-zen.spec index 4fcc0b3..7809d34 100644 --- a/SPECS/linux-zen.spec +++ b/SPECS/linux-zen.spec @@ -1,22 +1,13 @@ %global debug_package %{nil} %global zen zen1 Name: linux-zen -Version: 6.7.2 +Version: 6.7.6 Release: 1%{?dist} Summary: Linux kernel and modules with Zen patches License: GPL-2.0-only URL: http://www.zen-kernel.org/ Source0: v%{version}-%{zen}.tar.gz -Patch0: 0000-NTPatch.patch -Patch1: 0001-NTPatch.patch -Patch2: 0002-NTPatch.patch -Patch3: 0003-NTPatch.patch -Patch4: 0004-NTPatch.patch -Patch5: 0005-NTPatch.patch -Patch6: 0006-NTPatch.patch -Patch7: 0007-NTPatch.patch -Patch8: 0008-NTPatch.patch BuildRequires: gcc, make, flex, bison, ncurses-devel, elfutils-libelf-devel, openssl-devel @@ -27,15 +18,11 @@ Linux kernel and modules with Zen patches (%{version} series) compiled with Clan %setup -q -n zen-kernel-%{version}-%{zen} cp %{_sourcedir}/.config .config -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 +# Apply all patch files in a shell loop +for patch in %{_sourcedir}/*.patch; do + echo "Applying $patch" + patch -p1 < $patch +done %build # Set environment variables for Clang and LLVM tools @@ -72,22 +59,21 @@ make LLVM=1 %{?_smp_mflags} %install make modules_install INSTALL_MOD_PATH=%{buildroot} -# Define the path for vmlinuz file VMLINUX_PATH=%{buildroot}/boot -# Create the boot directory mkdir -p $VMLINUX_PATH -# Navigate to the directory where vmlinux is located -cd %{_builddir}/zen-kernel-%{version}-%{zen} +cd %{_builddir}/zen-kernel-%{version}-zen1/arch/x86/boot -# Compress vmlinux and move it to the vmlinuz path -gzip -c vmlinux > $VMLINUX_PATH/vmlinuz-%{version}-%{zen}.fc39.x86_64 +cp bzImage $VMLINUX_PATH/vmlinuz-%{version}-%{zen}.fc39.x86_64 + +cd %{_builddir}/zen-kernel-%{version}-zen1 cp %{_sourcedir}/.config $VMLINUX_PATH/config-%{version}-%{zen}.fc39.x86_64 %files -/boot/vmlinuz-%{version}-%{zen} +/boot/vmlinuz-%{version}-%{zen}.fc39.x86_64 +/boot/config-%{version}-%{zen}.fc39.x86_64 /lib/modules/* %changelog diff --git a/build-helper.sh b/build-helper.sh index 7e44051..3040086 100755 --- a/build-helper.sh +++ b/build-helper.sh @@ -1,6 +1,6 @@ #!/bin/bash -kernel_version="6.7.2" +kernel_version="6.7.6" zen_version="zen1" source_url="https://github.com/zen-kernel/zen-kernel/archive/refs/tags/v${kernel_version}-${zen_version}.tar.gz" source_file="v${kernel_version}-${zen_version}.tar.gz" @@ -33,4 +33,3 @@ if [ ! -f "SOURCES/${source_file}" ]; then fi rpmbuild -ba --define "_topdir $PWD" SPECS/linux-zen.spec - diff --git a/run-after-install.sh b/run-after-install.sh index c19f0c2..4d5b86c 100755 --- a/run-after-install.sh +++ b/run-after-install.sh @@ -1,7 +1,7 @@ #!/bin/bash -kernel_version="6.7.2" +kernel_version="6.7.6" zen_version="zen1" revision="1" -sudo dracut /boot/initramfs-${kernel_version}-${zen_version}.img ${zen_version}-zen1_${revision} +sudo dracut /boot/initramfs-${kernel_version}-${zen_version}.fc39.x86_64.img ${kernel_version}-${zen_version}_${revision}