diff options
Diffstat (limited to 'SOURCES')
29 files changed, 2653 insertions, 2541 deletions
diff --git a/SOURCES/0001-amd-pstate.patch b/SOURCES/0001-amd-pstate.patch new file mode 100644 index 0000000..d7fd4b3 --- /dev/null +++ b/SOURCES/0001-amd-pstate.patch @@ -0,0 +1,578 @@ +From 1449b07b2bd2af451bba8ba17f7b01cf30b6471f Mon Sep 17 00:00:00 2001 +From: Peter Jung <admin@ptr1337.dev> +Date: Fri, 23 Feb 2024 17:11:08 +0100 +Subject: [PATCH 1/7] amd-pstate + +Signed-off-by: Peter Jung <admin@ptr1337.dev> +--- + .../admin-guide/kernel-parameters.txt | 5 + + Documentation/admin-guide/pm/amd-pstate.rst | 59 +++++- + arch/x86/Kconfig | 5 +- + drivers/acpi/cppc_acpi.c | 13 ++ + drivers/acpi/processor_driver.c | 6 + + drivers/cpufreq/amd-pstate.c | 179 +++++++++++++++++- + include/acpi/cppc_acpi.h | 5 + + include/linux/amd-pstate.h | 10 + + include/linux/cpufreq.h | 1 + + 9 files changed, 272 insertions(+), 11 deletions(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index b72e2049c487..95164b35f973 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -363,6 +363,11 @@ + selects a performance level in this range and appropriate + to the current workload. + ++ amd_prefcore= ++ [X86] ++ disable ++ Disable amd-pstate preferred core. ++ + amijoy.map= [HW,JOY] Amiga joystick support + Map of devices attached to JOY0DAT and JOY1DAT + Format: <a>,<b> +diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst +index 1cf40f69278c..0b832ff529db 100644 +--- a/Documentation/admin-guide/pm/amd-pstate.rst ++++ b/Documentation/admin-guide/pm/amd-pstate.rst +@@ -300,8 +300,8 @@ platforms. The AMD P-States mechanism is the more performance and energy + efficiency frequency management method on AMD processors. + + +-AMD Pstate Driver Operation Modes +-================================= ++``amd-pstate`` Driver Operation Modes ++====================================== + + ``amd_pstate`` CPPC has 3 operation modes: autonomous (active) mode, + non-autonomous (passive) mode and guided autonomous (guided) mode. +@@ -353,6 +353,48 @@ is activated. In this mode, driver requests minimum and maximum performance + level and the platform autonomously selects a performance level in this range + and appropriate to the current workload. + ++``amd-pstate`` Preferred Core ++================================= ++ ++The core frequency is subjected to the process variation in semiconductors. ++Not all cores are able to reach the maximum frequency respecting the ++infrastructure limits. Consequently, AMD has redefined the concept of ++maximum frequency of a part. This means that a fraction of cores can reach ++maximum frequency. To find the best process scheduling policy for a given ++scenario, OS needs to know the core ordering informed by the platform through ++highest performance capability register of the CPPC interface. ++ ++``amd-pstate`` preferred core enables the scheduler to prefer scheduling on ++cores that can achieve a higher frequency with lower voltage. The preferred ++core rankings can dynamically change based on the workload, platform conditions, ++thermals and ageing. ++ ++The priority metric will be initialized by the ``amd-pstate`` driver. The ``amd-pstate`` ++driver will also determine whether or not ``amd-pstate`` preferred core is ++supported by the platform. ++ ++``amd-pstate`` driver will provide an initial core ordering when the system boots. ++The platform uses the CPPC interfaces to communicate the core ranking to the ++operating system and scheduler to make sure that OS is choosing the cores ++with highest performance firstly for scheduling the process. When ``amd-pstate`` ++driver receives a message with the highest performance change, it will ++update the core ranking and set the cpu's priority. ++ ++``amd-pstate`` Preferred Core Switch ++================================= ++Kernel Parameters ++----------------- ++ ++``amd-pstate`` peferred core`` has two states: enable and disable. ++Enable/disable states can be chosen by different kernel parameters. ++Default enable ``amd-pstate`` preferred core. ++ ++``amd_prefcore=disable`` ++ ++For systems that support ``amd-pstate`` preferred core, the core rankings will ++always be advertised by the platform. But OS can choose to ignore that via the ++kernel parameter ``amd_prefcore=disable``. ++ + User Space Interface in ``sysfs`` - General + =========================================== + +@@ -385,6 +427,19 @@ control its functionality at the system level. They are located in the + to the operation mode represented by that string - or to be + unregistered in the "disable" case. + ++``prefcore`` ++ Preferred core state of the driver: "enabled" or "disabled". ++ ++ "enabled" ++ Enable the ``amd-pstate`` preferred core. ++ ++ "disabled" ++ Disable the ``amd-pstate`` preferred core ++ ++ ++ This attribute is read-only to check the state of preferred core set ++ by the kernel parameter. ++ + ``cpupower`` tool support for ``amd-pstate`` + =============================================== + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 1566748f16c4..4fd69cd4241a 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1054,8 +1054,9 @@ config SCHED_MC + + config SCHED_MC_PRIO + bool "CPU core priorities scheduler support" +- depends on SCHED_MC && CPU_SUP_INTEL +- select X86_INTEL_PSTATE ++ depends on SCHED_MC ++ select X86_INTEL_PSTATE if CPU_SUP_INTEL ++ select X86_AMD_PSTATE if CPU_SUP_AMD && ACPI + select CPU_FREQ + default y + help +diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c +index 7ff269a78c20..ad388a0e8484 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -1154,6 +1154,19 @@ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf) + return cppc_get_perf(cpunum, NOMINAL_PERF, nominal_perf); + } + ++/** ++ * cppc_get_highest_perf - Get the highest performance register value. ++ * @cpunum: CPU from which to get highest performance. ++ * @highest_perf: Return address. ++ * ++ * Return: 0 for success, -EIO otherwise. ++ */ ++int cppc_get_highest_perf(int cpunum, u64 *highest_perf) ++{ ++ return cppc_get_perf(cpunum, HIGHEST_PERF, highest_perf); ++} ++EXPORT_SYMBOL_GPL(cppc_get_highest_perf); ++ + /** + * cppc_get_epp_perf - Get the epp register value. + * @cpunum: CPU from which to get epp preference value. +diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c +index 4bd16b3f0781..67db60eda370 100644 +--- a/drivers/acpi/processor_driver.c ++++ b/drivers/acpi/processor_driver.c +@@ -27,6 +27,7 @@ + #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 + #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 + #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 ++#define ACPI_PROCESSOR_NOTIFY_HIGEST_PERF_CHANGED 0x85 + + MODULE_AUTHOR("Paul Diefenbaugh"); + MODULE_DESCRIPTION("ACPI Processor Driver"); +@@ -83,6 +84,11 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, 0); + break; ++ case ACPI_PROCESSOR_NOTIFY_HIGEST_PERF_CHANGED: ++ cpufreq_update_limits(pr->id); ++ acpi_bus_generate_netlink_event(device->pnp.device_class, ++ dev_name(&device->dev), event, 0); ++ break; + default: + acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event); + break; +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 1791d37fbc53..54df68773620 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -37,6 +37,7 @@ + #include <linux/uaccess.h> + #include <linux/static_call.h> + #include <linux/amd-pstate.h> ++#include <linux/topology.h> + + #include <acpi/processor.h> + #include <acpi/cppc_acpi.h> +@@ -64,6 +65,7 @@ static struct cpufreq_driver amd_pstate_driver; + static struct cpufreq_driver amd_pstate_epp_driver; + static int cppc_state = AMD_PSTATE_UNDEFINED; + static bool cppc_enabled; ++static bool amd_pstate_prefcore = true; + + /* + * AMD Energy Preference Performance (EPP) +@@ -296,14 +298,12 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) + &cap1); + if (ret) + return ret; +- +- /* +- * TODO: Introduce AMD specific power feature. +- * +- * CPPC entry doesn't indicate the highest performance in some ASICs. ++ ++ /* Some CPUs have different highest_perf from others, it is safer ++ * to read it than to assume some erroneous value, leading to performance issues. + */ + highest_perf = amd_get_highest_perf(); +- if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1)) ++ if(highest_perf > AMD_CPPC_HIGHEST_PERF(cap1)) + highest_perf = AMD_CPPC_HIGHEST_PERF(cap1); + + WRITE_ONCE(cpudata->highest_perf, highest_perf); +@@ -311,6 +311,7 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) + WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1)); + WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1)); + WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1)); ++ WRITE_ONCE(cpudata->prefcore_ranking, AMD_CPPC_HIGHEST_PERF(cap1)); + WRITE_ONCE(cpudata->min_limit_perf, AMD_CPPC_LOWEST_PERF(cap1)); + return 0; + } +@@ -324,8 +325,11 @@ static int cppc_init_perf(struct amd_cpudata *cpudata) + if (ret) + return ret; + ++ /* Some CPUs have different highest_perf from others, it is safer ++ * to read it than to assume some erroneous value, leading to performance issues. ++ */ + highest_perf = amd_get_highest_perf(); +- if (highest_perf > cppc_perf.highest_perf) ++ if(highest_perf > cppc_perf.highest_perf) + highest_perf = cppc_perf.highest_perf; + + WRITE_ONCE(cpudata->highest_perf, highest_perf); +@@ -334,6 +338,7 @@ static int cppc_init_perf(struct amd_cpudata *cpudata) + WRITE_ONCE(cpudata->lowest_nonlinear_perf, + cppc_perf.lowest_nonlinear_perf); + WRITE_ONCE(cpudata->lowest_perf, cppc_perf.lowest_perf); ++ WRITE_ONCE(cpudata->prefcore_ranking, cppc_perf.highest_perf); + WRITE_ONCE(cpudata->min_limit_perf, cppc_perf.lowest_perf); + + if (cppc_state == AMD_PSTATE_ACTIVE) +@@ -706,6 +711,114 @@ static void amd_perf_ctl_reset(unsigned int cpu) + wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0); + } + ++/* ++ * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks ++ * due to locking, so queue the work for later. ++ */ ++static void amd_pstste_sched_prefcore_workfn(struct work_struct *work) ++{ ++ sched_set_itmt_support(); ++} ++static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn); ++ ++/* ++ * Get the highest performance register value. ++ * @cpu: CPU from which to get highest performance. ++ * @highest_perf: Return address. ++ * ++ * Return: 0 for success, -EIO otherwise. ++ */ ++static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf) ++{ ++ int ret; ++ ++ if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ u64 cap1; ++ ++ ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); ++ if (ret) ++ return ret; ++ WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1)); ++ } else { ++ u64 cppc_highest_perf; ++ ++ ret = cppc_get_highest_perf(cpu, &cppc_highest_perf); ++ if (ret) ++ return ret; ++ WRITE_ONCE(*highest_perf, cppc_highest_perf); ++ } ++ ++ return (ret); ++} ++ ++#define CPPC_MAX_PERF U8_MAX ++ ++static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata) ++{ ++ int ret, prio; ++ u32 highest_perf; ++ ++ ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf); ++ if (ret) ++ return; ++ ++ cpudata->hw_prefcore = true; ++ /* check if CPPC preferred core feature is enabled*/ ++ if (highest_perf < CPPC_MAX_PERF) ++ prio = (int)highest_perf; ++ else { ++ pr_debug("AMD CPPC preferred core is unsupported!\n"); ++ cpudata->hw_prefcore = false; ++ return; ++ } ++ ++ if (!amd_pstate_prefcore) ++ return; ++ ++ /* ++ * The priorities can be set regardless of whether or not ++ * sched_set_itmt_support(true) has been called and it is valid to ++ * update them at any time after it has been called. ++ */ ++ sched_set_itmt_core_prio(prio, cpudata->cpu); ++ ++ schedule_work(&sched_prefcore_work); ++} ++ ++static void amd_pstate_update_limits(unsigned int cpu) ++{ ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ struct amd_cpudata *cpudata = policy->driver_data; ++ u32 prev_high = 0, cur_high = 0; ++ int ret; ++ bool highest_perf_changed = false; ++ ++ mutex_lock(&amd_pstate_driver_lock); ++ if ((!amd_pstate_prefcore) || (!cpudata->hw_prefcore)) ++ goto free_cpufreq_put; ++ ++ ret = amd_pstate_get_highest_perf(cpu, &cur_high); ++ if (ret) ++ goto free_cpufreq_put; ++ ++ prev_high = READ_ONCE(cpudata->prefcore_ranking); ++ if (prev_high != cur_high) { ++ highest_perf_changed = true; ++ WRITE_ONCE(cpudata->prefcore_ranking, cur_high); ++ ++ if (cur_high < CPPC_MAX_PERF) ++ sched_set_itmt_core_prio((int)cur_high, cpu); ++ } ++ ++free_cpufreq_put: ++ cpufreq_cpu_put(policy); ++ ++ if (!highest_perf_changed) ++ cpufreq_update_policy(cpu); ++ ++ mutex_unlock(&amd_pstate_driver_lock); ++} ++ + static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + { + int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; +@@ -727,6 +840,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + + cpudata->cpu = policy->cpu; + ++ amd_pstate_init_prefcore(cpudata); ++ + ret = amd_pstate_init_perf(cpudata); + if (ret) + goto free_cpudata1; +@@ -877,6 +992,28 @@ static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy, + return sysfs_emit(buf, "%u\n", perf); + } + ++static ssize_t show_amd_pstate_prefcore_ranking(struct cpufreq_policy *policy, ++ char *buf) ++{ ++ u32 perf; ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ perf = READ_ONCE(cpudata->prefcore_ranking); ++ ++ return sysfs_emit(buf, "%u\n", perf); ++} ++ ++static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy, ++ char *buf) ++{ ++ bool hw_prefcore; ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ hw_prefcore = READ_ONCE(cpudata->hw_prefcore); ++ ++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(hw_prefcore)); ++} ++ + static ssize_t show_energy_performance_available_preferences( + struct cpufreq_policy *policy, char *buf) + { +@@ -1074,18 +1211,29 @@ static ssize_t status_store(struct device *a, struct device_attribute *b, + return ret < 0 ? ret : count; + } + ++static ssize_t prefcore_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore)); ++} ++ + cpufreq_freq_attr_ro(amd_pstate_max_freq); + cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); + + cpufreq_freq_attr_ro(amd_pstate_highest_perf); ++cpufreq_freq_attr_ro(amd_pstate_prefcore_ranking); ++cpufreq_freq_attr_ro(amd_pstate_hw_prefcore); + cpufreq_freq_attr_rw(energy_performance_preference); + cpufreq_freq_attr_ro(energy_performance_available_preferences); + static DEVICE_ATTR_RW(status); ++static DEVICE_ATTR_RO(prefcore); + + static struct freq_attr *amd_pstate_attr[] = { + &amd_pstate_max_freq, + &amd_pstate_lowest_nonlinear_freq, + &amd_pstate_highest_perf, ++ &amd_pstate_prefcore_ranking, ++ &amd_pstate_hw_prefcore, + NULL, + }; + +@@ -1093,6 +1241,8 @@ static struct freq_attr *amd_pstate_epp_attr[] = { + &amd_pstate_max_freq, + &amd_pstate_lowest_nonlinear_freq, + &amd_pstate_highest_perf, ++ &amd_pstate_prefcore_ranking, ++ &amd_pstate_hw_prefcore, + &energy_performance_preference, + &energy_performance_available_preferences, + NULL, +@@ -1100,6 +1250,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = { + + static struct attribute *pstate_global_attributes[] = { + &dev_attr_status.attr, ++ &dev_attr_prefcore.attr, + NULL + }; + +@@ -1151,6 +1302,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + cpudata->cpu = policy->cpu; + cpudata->epp_policy = 0; + ++ amd_pstate_init_prefcore(cpudata); ++ + ret = amd_pstate_init_perf(cpudata); + if (ret) + goto free_cpudata1; +@@ -1432,6 +1585,7 @@ static struct cpufreq_driver amd_pstate_driver = { + .suspend = amd_pstate_cpu_suspend, + .resume = amd_pstate_cpu_resume, + .set_boost = amd_pstate_set_boost, ++ .update_limits = amd_pstate_update_limits, + .name = "amd-pstate", + .attr = amd_pstate_attr, + }; +@@ -1446,6 +1600,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = { + .online = amd_pstate_epp_cpu_online, + .suspend = amd_pstate_epp_suspend, + .resume = amd_pstate_epp_resume, ++ .update_limits = amd_pstate_update_limits, + .name = "amd-pstate-epp", + .attr = amd_pstate_epp_attr, + }; +@@ -1567,7 +1722,17 @@ static int __init amd_pstate_param(char *str) + + return amd_pstate_set_driver(mode_idx); + } ++ ++static int __init amd_prefcore_param(char *str) ++{ ++ if (!strcmp(str, "disable")) ++ amd_pstate_prefcore = false; ++ ++ return 0; ++} ++ + early_param("amd_pstate", amd_pstate_param); ++early_param("amd_prefcore", amd_prefcore_param); + + MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>"); + MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver"); +diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h +index 6126c977ece0..c0b69ffe7bdb 100644 +--- a/include/acpi/cppc_acpi.h ++++ b/include/acpi/cppc_acpi.h +@@ -139,6 +139,7 @@ struct cppc_cpudata { + #ifdef CONFIG_ACPI_CPPC_LIB + extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); + extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf); ++extern int cppc_get_highest_perf(int cpunum, u64 *highest_perf); + extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); + extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); + extern int cppc_set_enable(int cpu, bool enable); +@@ -165,6 +166,10 @@ static inline int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf) + { + return -ENOTSUPP; + } ++static inline int cppc_get_highest_perf(int cpunum, u64 *highest_perf) ++{ ++ return -ENOTSUPP; ++} + static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs) + { + return -ENOTSUPP; +diff --git a/include/linux/amd-pstate.h b/include/linux/amd-pstate.h +index 6ad02ad9c7b4..d21838835abd 100644 +--- a/include/linux/amd-pstate.h ++++ b/include/linux/amd-pstate.h +@@ -39,11 +39,16 @@ struct amd_aperf_mperf { + * @cppc_req_cached: cached performance request hints + * @highest_perf: the maximum performance an individual processor may reach, + * assuming ideal conditions ++ * For platforms that do not support the preferred core feature, the ++ * highest_pef may be configured with 166 or 255, to avoid max frequency ++ * calculated wrongly. we take the fixed value as the highest_perf. + * @nominal_perf: the maximum sustained performance level of the processor, + * assuming ideal operating conditions + * @lowest_nonlinear_perf: the lowest performance level at which nonlinear power + * savings are achieved + * @lowest_perf: the absolute lowest performance level of the processor ++ * @prefcore_ranking: the preferred core ranking, the higher value indicates a higher ++ * priority. + * @max_freq: the frequency that mapped to highest_perf + * @min_freq: the frequency that mapped to lowest_perf + * @nominal_freq: the frequency that mapped to nominal_perf +@@ -52,6 +57,9 @@ struct amd_aperf_mperf { + * @prev: Last Aperf/Mperf/tsc count value read from register + * @freq: current cpu frequency value + * @boost_supported: check whether the Processor or SBIOS supports boost mode ++ * @hw_prefcore: check whether HW supports preferred core featue. ++ * Only when hw_prefcore and early prefcore param are true, ++ * AMD P-State driver supports preferred core featue. + * @epp_policy: Last saved policy used to set energy-performance preference + * @epp_cached: Cached CPPC energy-performance preference value + * @policy: Cpufreq policy value +@@ -70,6 +78,7 @@ struct amd_cpudata { + u32 nominal_perf; + u32 lowest_nonlinear_perf; + u32 lowest_perf; ++ u32 prefcore_ranking; + u32 min_limit_perf; + u32 max_limit_perf; + u32 min_limit_freq; +@@ -85,6 +94,7 @@ struct amd_cpudata { + + u64 freq; + bool boost_supported; ++ bool hw_prefcore; + + /* EPP feature related attributes*/ + s16 epp_policy; +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 1c5ca92a0555..5d62beea2712 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -263,6 +263,7 @@ static inline bool cpufreq_supports_freq_invariance(void) + return false; + } + static inline void disable_cpufreq(void) { } ++static inline void cpufreq_update_limits(unsigned int cpu) { } + #endif + + #ifdef CONFIG_CPU_FREQ_STAT +-- +2.43.2 + diff --git a/SOURCES/winesync.patch b/SOURCES/0001-ntsync.patch index 459bf54..34a383a 100644 --- a/SOURCES/winesync.patch +++ b/SOURCES/0001-ntsync.patch @@ -1,145 +1,135 @@ -From 153c94d81f583dfbd9e4e81eefc6a9b8e83ff06d Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 34529eb8302090ff79e04d95a6bb7f5fd48cecb6 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 10:50:45 -0600 -Subject: [PATCH 01/34] winesync: Introduce the winesync driver and character +Subject: [PATCH 01/32] ntsync: Introduce the ntsync driver and character device. +ntsync uses a misc device as the simplest and least intrusive uAPI interface. + +Each file description on the device represents an isolated NT instance, intended +to correspond to a single NT virtual machine. --- - drivers/misc/Kconfig | 11 +++++++ - drivers/misc/Makefile | 1 + - drivers/misc/winesync.c | 64 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 76 insertions(+) - create mode 100644 drivers/misc/winesync.c + drivers/misc/Kconfig | 9 ++++++++ + drivers/misc/Makefile | 1 + + drivers/misc/ntsync.c | 53 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 63 insertions(+) + create mode 100644 drivers/misc/ntsync.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 94e9fb4cdd76..4f9e3d80a6e8 100644 +index f37c4b8380ae..622eb26ac040 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -519,6 +519,17 @@ - - If you do not intend to run this kernel as a guest, say N. +@@ -504,6 +504,15 @@ config OPEN_DICE + measured boot flow. Userspace can use CDIs for remote attestation + and sealing. -+config WINESYNC -+ tristate "Synchronization primitives for Wine" ++config NTSYNC ++ tristate "NT synchronization primitive emulation" + help -+ This module provides kernel support for synchronization primitives -+ used by Wine. It is not a hardware driver. ++ This module provides kernel support for emulation of Windows NT ++ synchronization primitives. It is not a hardware driver. + + To compile this driver as a module, choose M here: the -+ module will be called winesync. -+ -+ If unsure, say N. ++ module will be called ntsync. + - config TMR_MANAGER - tristate "Select TMR Manager" - depends on MICROBLAZE && MB_MANAGER + If unsure, say N. + + config VCPU_STALL_DETECTOR diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 2be8542616dd..d061fe45407b 100644 +index f2a4d1ff65d4..bd12e9a3b8c5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -59,6 +59,7 @@ +@@ -59,6 +59,7 @@ obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o -+obj-$(CONFIG_WINESYNC) += winesync.o ++obj-$(CONFIG_NTSYNC) += ntsync.o obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o obj-$(CONFIG_OPEN_DICE) += open-dice.o obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..111f33c5676e +index 000000000000..9424c6210e51 --- /dev/null -+++ b/drivers/misc/winesync.c -@@ -0,0 +1,64 @@ ++++ b/drivers/misc/ntsync.c +@@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* -+ * winesync.c - Kernel driver for Wine synchronization primitives ++ * ntsync.c - Kernel driver for NT synchronization primitives + * -+ * Copyright (C) 2021 Zebediah Figura ++ * Copyright (C) 2021-2022 Elizabeth Figura + */ + +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/module.h> + -+#define WINESYNC_NAME "winesync" ++#define NTSYNC_NAME "ntsync" + -+static int winesync_char_open(struct inode *inode, struct file *file) ++static int ntsync_char_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + -+static int winesync_char_release(struct inode *inode, struct file *file) ++static int ntsync_char_release(struct inode *inode, struct file *file) +{ + return 0; +} + -+static long winesync_char_ioctl(struct file *file, unsigned int cmd, -+ unsigned long parm) ++static long ntsync_char_ioctl(struct file *file, unsigned int cmd, ++ unsigned long parm) +{ + switch (cmd) { + default: -+ return -ENOSYS; ++ return -ENOIOCTLCMD; + } +} + -+static const struct file_operations winesync_fops = { ++static const struct file_operations ntsync_fops = { + .owner = THIS_MODULE, -+ .open = winesync_char_open, -+ .release = winesync_char_release, -+ .unlocked_ioctl = winesync_char_ioctl, -+ .compat_ioctl = winesync_char_ioctl, ++ .open = ntsync_char_open, ++ .release = ntsync_char_release, ++ .unlocked_ioctl = ntsync_char_ioctl, ++ .compat_ioctl = ntsync_char_ioctl, + .llseek = no_llseek, +}; + -+static struct miscdevice winesync_misc = { ++static struct miscdevice ntsync_misc = { + .minor = MISC_DYNAMIC_MINOR, -+ .name = WINESYNC_NAME, -+ .fops = &winesync_fops, ++ .name = NTSYNC_NAME, ++ .fops = &ntsync_fops, +}; + -+static int __init winesync_init(void) -+{ -+ return misc_register(&winesync_misc); -+} -+ -+static void __exit winesync_exit(void) -+{ -+ misc_deregister(&winesync_misc); -+} -+ -+module_init(winesync_init); -+module_exit(winesync_exit); ++module_misc_device(ntsync_misc); + -+MODULE_AUTHOR("Zebediah Figura"); -+MODULE_DESCRIPTION("Kernel driver for Wine synchronization primitives"); ++MODULE_AUTHOR("Elizabeth Figura"); ++MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); -+MODULE_ALIAS("devname:" WINESYNC_NAME); ++MODULE_ALIAS("devname:" NTSYNC_NAME); -- -2.37.3 +2.43.0 -From 1f142d40cb7537bd936a68cadaf0f2a0d94abd62 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From a375bffd8ab8d06b81e4b83c9f5577fdc97246f9 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 10:57:06 -0600 -Subject: [PATCH 02/34] winesync: Reserve a minor device number and ioctl - range. +Subject: [PATCH 02/32] ntsync: Reserve a minor device number and ioctl range. --- Documentation/admin-guide/devices.txt | 3 ++- Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ - drivers/misc/winesync.c | 3 ++- + 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 c07dc0ee860e..4e5abe508426 100644 +index 839054923530..13841636ce92 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/winesync Wine synchronization primitive device ++ 243 = /dev/ntsync NT synchronization primitive device - 243-254 Reserved for local use + 244-254 Reserved for local use @@ -147,86 +137,91 @@ index c07dc0ee860e..4e5abe508426 100644 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 3b985b19f39d..3f313fd4338c 100644 +index 4ea5b837399a..055482769b35 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -375,6 +375,8 @@ Code Seq# Include File Comments <mailto:thomas@winischhofer.net> 0xF6 all LTTng Linux Trace Toolkit Next Generation <mailto:mathieu.desnoyers@efficios.com> -+0xF7 00-0F uapi/linux/winesync.h Wine synchronization primitives ++0xF7 00-1F uapi/linux/ntsync.h NT synchronization primitives + <mailto:wine-devel@winehq.org> 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver <mailto:nchatrad@amd.com> 0xFD all linux/dm-ioctl.h -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 111f33c5676e..85cb6ccaa077 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -40,7 +40,7 @@ static const struct file_operations winesync_fops = { +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 winesync_misc = { + static struct miscdevice ntsync_misc = { - .minor = MISC_DYNAMIC_MINOR, -+ .minor = WINESYNC_MINOR, - .name = WINESYNC_NAME, - .fops = &winesync_fops, ++ .minor = NTSYNC_MINOR, + .name = NTSYNC_NAME, + .fops = &ntsync_fops, }; -@@ -62,3 +62,4 @@ MODULE_AUTHOR("Zebediah Figura"); - MODULE_DESCRIPTION("Kernel driver for Wine synchronization primitives"); +@@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura"); + MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); MODULE_LICENSE("GPL"); - MODULE_ALIAS("devname:" WINESYNC_NAME); -+MODULE_ALIAS_MISCDEV(WINESYNC_MINOR); + MODULE_ALIAS("devname:" NTSYNC_NAME); ++MODULE_ALIAS_MISCDEV(NTSYNC_MINOR); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h -index 0676f18093f9..350aecfcfb29 100644 +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 WINESYNC_MINOR 243 ++#define NTSYNC_MINOR 243 #define MISC_DYNAMIC_MINOR 255 struct device; -- -2.36.0 +2.43.0 -From 8ad26f39cb5442d9e17f22ed0cda8d3669bb11b5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From a5f6ffc3056884b48bb9161bc1246d841d9ed961 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:15:39 -0600 -Subject: [PATCH 03/34] winesync: Introduce WINESYNC_IOC_CREATE_SEM and - WINESYNC_IOC_DELETE. +Subject: [PATCH 03/32] ntsync: Introduce NTSYNC_IOC_CREATE_SEM and + NTSYNC_IOC_DELETE. +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. --- - drivers/misc/winesync.c | 117 ++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 25 ++++++++ + drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 25 ++++++++ 2 files changed, 142 insertions(+) - create mode 100644 include/uapi/linux/winesync.h + create mode 100644 include/uapi/linux/ntsync.h -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 85cb6ccaa077..36e31bbe0390 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c +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 <linux/fs.h> #include <linux/miscdevice.h> #include <linux/module.h> +#include <linux/slab.h> +#include <linux/xarray.h> -+#include <uapi/linux/winesync.h> ++#include <uapi/linux/ntsync.h> - #define WINESYNC_NAME "winesync" + #define NTSYNC_NAME "ntsync" -+enum winesync_type { -+ WINESYNC_TYPE_SEM, ++enum ntsync_type { ++ NTSYNC_TYPE_SEM, +}; + -+struct winesync_obj { ++struct ntsync_obj { + struct rcu_head rhead; + struct kref refcount; + -+ enum winesync_type type; ++ enum ntsync_type type; + + union { + struct { @@ -236,25 +231,25 @@ index 85cb6ccaa077..36e31bbe0390 100644 + } u; +}; + -+struct winesync_device { ++struct ntsync_device { + struct xarray objects; +}; + +static void destroy_obj(struct kref *ref) +{ -+ struct winesync_obj *obj = container_of(ref, struct winesync_obj, refcount); ++ struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); + + kfree_rcu(obj, rhead); +} + -+static void put_obj(struct winesync_obj *obj) ++static void put_obj(struct ntsync_obj *obj) +{ + kref_put(&obj->refcount, destroy_obj); +} + - static int winesync_char_open(struct inode *inode, struct file *file) + static int ntsync_char_open(struct inode *inode, struct file *file) { -+ struct winesync_device *dev; ++ struct ntsync_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) @@ -266,10 +261,10 @@ index 85cb6ccaa077..36e31bbe0390 100644 return nonseekable_open(inode, file); } - static int winesync_char_release(struct inode *inode, struct file *file) + static int ntsync_char_release(struct inode *inode, struct file *file) { -+ struct winesync_device *dev = file->private_data; -+ struct winesync_obj *obj; ++ struct ntsync_device *dev = file->private_data; ++ struct ntsync_obj *obj; + unsigned long id; + + xa_for_each(&dev->objects, id, obj) @@ -282,16 +277,16 @@ index 85cb6ccaa077..36e31bbe0390 100644 + return 0; +} + -+static void init_obj(struct winesync_obj *obj) ++static void init_obj(struct ntsync_obj *obj) +{ + kref_init(&obj->refcount); +} + -+static int winesync_create_sem(struct winesync_device *dev, void __user *argp) ++static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_obj *sem; ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ struct ntsync_obj *sem; + __u32 id; + int ret; + @@ -306,7 +301,7 @@ index 85cb6ccaa077..36e31bbe0390 100644 + return -ENOMEM; + + init_obj(sem); -+ sem->type = WINESYNC_TYPE_SEM; ++ sem->type = NTSYNC_TYPE_SEM; + sem->u.sem.count = args.count; + sem->u.sem.max = args.max; + @@ -319,9 +314,9 @@ index 85cb6ccaa077..36e31bbe0390 100644 + return put_user(id, &user_args->sem); +} + -+static int winesync_delete(struct winesync_device *dev, void __user *argp) ++static int ntsync_delete(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_obj *obj; ++ struct ntsync_obj *obj; + __u32 id; + + if (get_user(id, (__u32 __user *)argp)) @@ -335,87 +330,88 @@ index 85cb6ccaa077..36e31bbe0390 100644 return 0; } - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) { -+ struct winesync_device *dev = file->private_data; ++ struct ntsync_device *dev = file->private_data; + void __user *argp = (void __user *)parm; + switch (cmd) { -+ case WINESYNC_IOC_CREATE_SEM: -+ return winesync_create_sem(dev, argp); -+ case WINESYNC_IOC_DELETE: -+ return winesync_delete(dev, argp); ++ case NTSYNC_IOC_CREATE_SEM: ++ return ntsync_create_sem(dev, argp); ++ case NTSYNC_IOC_DELETE: ++ return ntsync_delete(dev, argp); default: - return -ENOSYS; + return -ENOIOCTLCMD; } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h new file mode 100644 -index 000000000000..aabb491f39d2 +index 000000000000..d97afc138dcc --- /dev/null -+++ b/include/uapi/linux/winesync.h ++++ b/include/uapi/linux/ntsync.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* -+ * Kernel support for Wine synchronization primitives ++ * Kernel support for NT synchronization primitive emulation + * -+ * Copyright (C) 2021 Zebediah Figura ++ * Copyright (C) 2021-2022 Elizabeth Figura + */ + -+#ifndef __LINUX_WINESYNC_H -+#define __LINUX_WINESYNC_H ++#ifndef __LINUX_NTSYNC_H ++#define __LINUX_NTSYNC_H + +#include <linux/types.h> + -+struct winesync_sem_args { ++struct ntsync_sem_args { + __u32 sem; + __u32 count; + __u32 max; +}; + -+#define WINESYNC_IOC_BASE 0xf7 ++#define NTSYNC_IOC_BASE 0xf7 + -+#define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ -+ struct winesync_sem_args) -+#define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) ++#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.36.0 +2.43.0 -From 144e223bfd7c5e733a9e7e50a3a8d37dbbedc0b7 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 81b4a45e9f5ab9275e42e0edb6cbf6073c44d38e Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:22:42 -0600 -Subject: [PATCH 04/34] winesync: Introduce WINESYNC_IOC_PUT_SEM. +Subject: [PATCH 04/32] ntsync: Introduce NTSYNC_IOC_PUT_SEM. +This corresponds to the NT syscall NtReleaseSemaphore(). --- - drivers/misc/winesync.c | 76 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 + + drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 + 2 files changed, 78 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 36e31bbe0390..84b5a5c9e0ce 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -21,9 +21,11 @@ enum winesync_type { - struct winesync_obj { +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 winesync_type type; + enum ntsync_type type; + /* The following fields are protected by the object lock. */ union { struct { __u32 count; -@@ -36,6 +38,19 @@ struct winesync_device { +@@ -36,6 +38,19 @@ struct ntsync_device { struct xarray objects; }; -+static struct winesync_obj *get_obj(struct winesync_device *dev, __u32 id) ++static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id) +{ -+ struct winesync_obj *obj; ++ struct ntsync_obj *obj; + + rcu_read_lock(); + obj = xa_load(&dev->objects, id); @@ -428,15 +424,15 @@ index 36e31bbe0390..84b5a5c9e0ce 100644 + static void destroy_obj(struct kref *ref) { - struct winesync_obj *obj = container_of(ref, struct winesync_obj, refcount); -@@ -48,6 +63,18 @@ static void put_obj(struct winesync_obj *obj) + 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 winesync_obj *get_obj_typed(struct winesync_device *dev, __u32 id, -+ enum winesync_type type) ++static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 id, ++ enum ntsync_type type) +{ -+ struct winesync_obj *obj = get_obj(dev, id); ++ struct ntsync_obj *obj = get_obj(dev, id); + + if (obj && obj->type != type) { + put_obj(obj); @@ -445,18 +441,18 @@ index 36e31bbe0390..84b5a5c9e0ce 100644 + return obj; +} + - static int winesync_char_open(struct inode *inode, struct file *file) + static int ntsync_char_open(struct inode *inode, struct file *file) { - struct winesync_device *dev; -@@ -81,6 +108,7 @@ static int winesync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct winesync_obj *obj) + 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 winesync_create_sem(struct winesync_device *dev, void __user *argp) -@@ -131,6 +159,52 @@ static int winesync_delete(struct winesync_device *dev, void __user *argp) + 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; } @@ -464,7 +460,7 @@ index 36e31bbe0390..84b5a5c9e0ce 100644 + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. + */ -+static int put_sem_state(struct winesync_obj *sem, __u32 count) ++static int put_sem_state(struct ntsync_obj *sem, __u32 count) +{ + lockdep_assert_held(&sem->lock); + @@ -476,18 +472,18 @@ index 36e31bbe0390..84b5a5c9e0ce 100644 + return 0; +} + -+static int winesync_put_sem(struct winesync_device *dev, void __user *argp) ++static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_obj *sem; ++ 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, WINESYNC_TYPE_SEM); ++ sem = get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM); + if (!sem) + return -EINVAL; + @@ -506,68 +502,72 @@ index 36e31bbe0390..84b5a5c9e0ce 100644 + return ret; +} + - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) { -@@ -142,6 +216,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_create_sem(dev, argp); - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); -+ case WINESYNC_IOC_PUT_SEM: -+ return winesync_put_sem(dev, argp); +@@ -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 -ENOSYS; + return -ENOIOCTLCMD; } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index aabb491f39d2..7681a168eb92 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -21,5 +21,7 @@ struct winesync_sem_args { - #define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ - struct winesync_sem_args) - #define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) -+#define WINESYNC_IOC_PUT_SEM _IOWR(WINESYNC_IOC_BASE, 2, \ -+ struct winesync_sem_args) +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.36.0 +2.43.0 -From 207daf2aa77f9d197b205a88322d5359f432bc67 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 68f1adf9a8e440dcb00b6665b8bc0f8aee275857 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:31:44 -0600 -Subject: [PATCH 05/34] winesync: Introduce WINESYNC_IOC_WAIT_ANY. +Subject: [PATCH 05/32] ntsync: Introduce NTSYNC_IOC_WAIT_ANY. +This corresponds to part of the functionality of the NT syscall +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. --- - drivers/misc/winesync.c | 226 ++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 11 ++ - 2 files changed, 237 insertions(+) + drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 13 ++ + 2 files changed, 242 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 84b5a5c9e0ce..d9b5ab159520 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -23,6 +23,8 @@ struct winesync_obj { +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index d1c91c2a4f1a..2e8d3c2d51a4 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -23,6 +23,8 @@ struct ntsync_obj { struct kref refcount; spinlock_t lock; + struct list_head any_waiters; + - enum winesync_type type; + enum ntsync_type type; /* The following fields are protected by the object lock. */ -@@ -34,6 +36,28 @@ struct winesync_obj { +@@ -34,6 +36,28 @@ struct ntsync_obj { } u; }; -+struct winesync_q_entry { ++struct ntsync_q_entry { + struct list_head node; -+ struct winesync_q *q; -+ struct winesync_obj *obj; ++ struct ntsync_q *q; ++ struct ntsync_obj *obj; + __u32 index; +}; + -+struct winesync_q { ++struct ntsync_q { + struct task_struct *task; + __u32 owner; + @@ -579,27 +579,27 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + atomic_t signaled; + + __u32 count; -+ struct winesync_q_entry entries[]; ++ struct ntsync_q_entry entries[]; +}; + - struct winesync_device { + struct ntsync_device { struct xarray objects; }; -@@ -109,6 +133,26 @@ static void init_obj(struct winesync_obj *obj) +@@ -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); +} + -+static void try_wake_any_sem(struct winesync_obj *sem) ++static void try_wake_any_sem(struct ntsync_obj *sem) +{ -+ struct winesync_q_entry *entry; ++ struct ntsync_q_entry *entry; + + lockdep_assert_held(&sem->lock); + + list_for_each_entry(entry, &sem->any_waiters, node) { -+ struct winesync_q *q = entry->q; ++ struct ntsync_q *q = entry->q; + + if (!sem->u.sem.count) + break; @@ -611,8 +611,8 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + } } - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) -@@ -194,6 +238,8 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) + 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) prev_count = sem->u.sem.count; ret = put_sem_state(sem, args.count); @@ -621,11 +621,11 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 spin_unlock(&sem->lock); -@@ -205,6 +251,184 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) +@@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) return ret; } -+static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) ++static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) +{ + int ret = 0; + @@ -648,15 +648,15 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 +} + +/* -+ * Allocate and initialize the winesync_q structure, but do not queue us yet. ++ * Allocate and initialize the ntsync_q structure, but do not queue us yet. + * Also, calculate the relative timeout. + */ -+static int setup_wait(struct winesync_device *dev, -+ const struct winesync_wait_args *args, -+ ktime_t *ret_timeout, struct winesync_q **ret_q) ++static int setup_wait(struct ntsync_device *dev, ++ const struct ntsync_wait_args *args, ++ ktime_t *ret_timeout, struct ntsync_q **ret_q) +{ + const __u32 count = args->count; -+ struct winesync_q *q; ++ struct ntsync_q *q; + ktime_t timeout = 0; + __u32 *ids; + __u32 i, j; @@ -664,6 +664,9 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + if (!args->owner || args->pad) + return -EINVAL; + ++ if (args->count > NTSYNC_MAX_WAIT_COUNT) ++ return -EINVAL; ++ + if (args->timeout) { + struct timespec64 to; + @@ -695,8 +698,8 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + q->count = count; + + for (i = 0; i < count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = get_obj(dev, ids[i]); ++ struct ntsync_q_entry *entry = &q->entries[i]; ++ struct ntsync_obj *obj = get_obj(dev, ids[i]); + + if (!obj) + goto err; @@ -720,19 +723,19 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + return -EINVAL; +} + -+static void try_wake_any_obj(struct winesync_obj *obj) ++static void try_wake_any_obj(struct ntsync_obj *obj) +{ + switch (obj->type) { -+ case WINESYNC_TYPE_SEM: ++ case NTSYNC_TYPE_SEM: + try_wake_any_sem(obj); + break; + } +} + -+static int winesync_wait_any(struct winesync_device *dev, void __user *argp) ++static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_wait_args args; -+ struct winesync_q *q; ++ struct ntsync_wait_args args; ++ struct ntsync_q *q; + ktime_t timeout; + int signaled; + __u32 i; @@ -748,8 +751,8 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + /* queue ourselves */ + + for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = entry->obj; ++ struct ntsync_q_entry *entry = &q->entries[i]; ++ struct ntsync_obj *obj = entry->obj; + + spin_lock(&obj->lock); + list_add_tail(&entry->node, &obj->any_waiters); @@ -759,7 +762,7 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + /* check if we are already signaled */ + + for (i = 0; i < args.count; i++) { -+ struct winesync_obj *obj = q->entries[i].obj; ++ struct ntsync_obj *obj = q->entries[i].obj; + + if (atomic_read(&q->signaled) != -1) + break; @@ -771,13 +774,13 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + + /* sleep */ + -+ ret = winesync_schedule(q, args.timeout ? &timeout : NULL); ++ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); + + /* and finally, unqueue */ + + for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = entry->obj; ++ struct ntsync_q_entry *entry = &q->entries[i]; ++ struct ntsync_obj *obj = entry->obj; + + spin_lock(&obj->lock); + list_del(&entry->node); @@ -788,7 +791,7 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + + signaled = atomic_read(&q->signaled); + if (signaled != -1) { -+ struct winesync_wait_args __user *user_args = argp; ++ struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ + ret = 0; @@ -803,27 +806,27 @@ index 84b5a5c9e0ce..d9b5ab159520 100644 + return ret; +} + - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) { -@@ -218,6 +442,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_WAIT_ANY: -+ return winesync_wait_any(dev, argp); +@@ -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); ++ case NTSYNC_IOC_WAIT_ANY: ++ return ntsync_wait_any(dev, argp); default: - return -ENOSYS; + return -ENOIOCTLCMD; } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 7681a168eb92..f57ebfbe1dd9 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -16,6 +16,15 @@ struct winesync_sem_args { +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 8c610d65f8ef..10f07da7864e 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -16,6 +16,17 @@ struct ntsync_sem_args { __u32 max; }; -+struct winesync_wait_args { ++struct ntsync_wait_args { + __u64 timeout; + __u64 objs; + __u32 count; @@ -832,35 +835,41 @@ index 7681a168eb92..f57ebfbe1dd9 100644 + __u32 pad; +}; + - #define WINESYNC_IOC_BASE 0xf7 ++#define NTSYNC_MAX_WAIT_COUNT 64 ++ + #define NTSYNC_IOC_BASE 0xf7 - #define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ -@@ -23,5 +32,7 @@ struct winesync_sem_args { - #define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) - #define WINESYNC_IOC_PUT_SEM _IOWR(WINESYNC_IOC_BASE, 2, \ - struct winesync_sem_args) -+#define WINESYNC_IOC_WAIT_ANY _IOWR(WINESYNC_IOC_BASE, 3, \ -+ struct winesync_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) #endif -- -2.36.0 +2.43.0 -From 3d68ffb91767194d5a1a07aa6c57849343530a15 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From ec146c6daf3cd94d70135965f3260f2bea90f305 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:36:09 -0600 -Subject: [PATCH 06/34] winesync: Introduce WINESYNC_IOC_WAIT_ALL. +Subject: [PATCH 06/32] ntsync: Introduce NTSYNC_IOC_WAIT_ALL. +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. --- - drivers/misc/winesync.c | 242 ++++++++++++++++++++++++++++++++-- - include/uapi/linux/winesync.h | 2 + - 2 files changed, 236 insertions(+), 8 deletions(-) + drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 2 + + 2 files changed, 235 insertions(+), 8 deletions(-) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index d9b5ab159520..2b708c5b88a6 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -23,7 +23,34 @@ struct winesync_obj { +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 2e8d3c2d51a4..2685363fae9e 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -23,7 +23,34 @@ struct ntsync_obj { struct kref refcount; spinlock_t lock; @@ -893,18 +902,18 @@ index d9b5ab159520..2b708c5b88a6 100644 + */ + atomic_t all_hint; - enum winesync_type type; + enum ntsync_type type; -@@ -54,11 +81,25 @@ struct winesync_q { +@@ -54,11 +81,25 @@ struct ntsync_q { */ atomic_t signaled; + bool all; __u32 count; - struct winesync_q_entry entries[]; + struct ntsync_q_entry entries[]; }; - struct winesync_device { + 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 @@ -921,7 +930,7 @@ index d9b5ab159520..2b708c5b88a6 100644 struct xarray objects; }; -@@ -107,6 +148,8 @@ static int winesync_char_open(struct inode *inode, struct file *file) +@@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) if (!dev) return -ENOMEM; @@ -930,8 +939,8 @@ index d9b5ab159520..2b708c5b88a6 100644 xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); file->private_data = dev; -@@ -132,8 +175,82 @@ static int winesync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct winesync_obj *obj) +@@ -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); @@ -940,12 +949,12 @@ index d9b5ab159520..2b708c5b88a6 100644 + INIT_LIST_HEAD(&obj->all_waiters); +} + -+static bool is_signaled(struct winesync_obj *obj, __u32 owner) ++static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ + lockdep_assert_held(&obj->lock); + + switch (obj->type) { -+ case WINESYNC_TYPE_SEM: ++ case NTSYNC_TYPE_SEM: + return !!obj->u.sem.count; + } + @@ -958,8 +967,8 @@ index d9b5ab159520..2b708c5b88a6 100644 + * should not be locked again. This is necessary so that changing an object's + * state and waking it can be a single atomic operation. + */ -+static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, -+ struct winesync_obj *locked_obj) ++static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, ++ struct ntsync_obj *locked_obj) +{ + __u32 count = q->count; + bool can_wake = true; @@ -971,7 +980,7 @@ index d9b5ab159520..2b708c5b88a6 100644 + + for (i = 0; i < count; i++) { + if (q->entries[i].obj != locked_obj) -+ spin_lock(&q->entries[i].obj->lock); ++ spin_lock_nest_lock(&q->entries[i].obj->lock, &dev->wait_all_lock); + } + + for (i = 0; i < count; i++) { @@ -983,10 +992,10 @@ index d9b5ab159520..2b708c5b88a6 100644 + + if (can_wake && atomic_cmpxchg(&q->signaled, -1, 0) == -1) { + for (i = 0; i < count; i++) { -+ struct winesync_obj *obj = q->entries[i].obj; ++ struct ntsync_obj *obj = q->entries[i].obj; + + switch (obj->type) { -+ case WINESYNC_TYPE_SEM: ++ case NTSYNC_TYPE_SEM: + obj->u.sem.count--; + break; + } @@ -1000,10 +1009,9 @@ index d9b5ab159520..2b708c5b88a6 100644 + } +} + -+static void try_wake_all_obj(struct winesync_device *dev, -+ struct winesync_obj *obj) ++static void try_wake_all_obj(struct ntsync_device *dev, struct ntsync_obj *obj) +{ -+ struct winesync_q_entry *entry; ++ struct ntsync_q_entry *entry; + + lockdep_assert_held(&dev->wait_all_lock); + lockdep_assert_held(&obj->lock); @@ -1012,15 +1020,15 @@ index d9b5ab159520..2b708c5b88a6 100644 + try_wake_all(dev, entry->q, obj); } - static void try_wake_any_sem(struct winesync_obj *sem) -@@ -234,14 +351,29 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) + 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) return -EINVAL; - spin_lock(&sem->lock); + if (atomic_read(&sem->all_hint) > 0) { + spin_lock(&dev->wait_all_lock); -+ spin_lock(&sem->lock); ++ spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); + + prev_count = sem->u.sem.count; + ret = put_sem_state(sem, args.count); @@ -1049,16 +1057,16 @@ index d9b5ab159520..2b708c5b88a6 100644 put_obj(sem); -@@ -278,7 +410,7 @@ static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) +@@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) * Also, calculate the relative timeout. */ - static int setup_wait(struct winesync_device *dev, -- const struct winesync_wait_args *args, -+ const struct winesync_wait_args *args, bool all, - ktime_t *ret_timeout, struct winesync_q **ret_q) + 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) { const __u32 count = args->count; -@@ -318,6 +450,7 @@ static int setup_wait(struct winesync_device *dev, +@@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, q->task = current; q->owner = args->owner; atomic_set(&q->signaled, -1); @@ -1066,7 +1074,7 @@ index d9b5ab159520..2b708c5b88a6 100644 q->count = count; for (i = 0; i < count; i++) { -@@ -327,6 +460,16 @@ static int setup_wait(struct winesync_device *dev, +@@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, if (!obj) goto err; @@ -1083,7 +1091,7 @@ index d9b5ab159520..2b708c5b88a6 100644 entry->obj = obj; entry->q = q; entry->index = i; -@@ -367,7 +510,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) +@@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; @@ -1092,14 +1100,14 @@ index d9b5ab159520..2b708c5b88a6 100644 if (ret < 0) return ret; -@@ -429,6 +572,87 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) +@@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) return ret; } -+static int winesync_wait_all(struct winesync_device *dev, void __user *argp) ++static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_wait_args args; -+ struct winesync_q *q; ++ struct ntsync_wait_args args; ++ struct ntsync_q *q; + ktime_t timeout; + int signaled; + __u32 i; @@ -1117,8 +1125,8 @@ index d9b5ab159520..2b708c5b88a6 100644 + spin_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = entry->obj; ++ struct ntsync_q_entry *entry = &q->entries[i]; ++ struct ntsync_obj *obj = entry->obj; + + atomic_inc(&obj->all_hint); + @@ -1137,15 +1145,15 @@ index d9b5ab159520..2b708c5b88a6 100644 + + /* sleep */ + -+ ret = winesync_schedule(q, args.timeout ? &timeout : NULL); ++ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); + + /* and finally, unqueue */ + + spin_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = entry->obj; ++ struct ntsync_q_entry *entry = &q->entries[i]; ++ struct ntsync_obj *obj = entry->obj; + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather @@ -1162,7 +1170,7 @@ index d9b5ab159520..2b708c5b88a6 100644 + + signaled = atomic_read(&q->signaled); + if (signaled != -1) { -+ struct winesync_wait_args __user *user_args = argp; ++ struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ + ret = 0; @@ -1177,56 +1185,57 @@ index d9b5ab159520..2b708c5b88a6 100644 + return ret; +} + - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) { -@@ -442,6 +666,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_WAIT_ALL: -+ return winesync_wait_all(dev, argp); - case WINESYNC_IOC_WAIT_ANY: - return winesync_wait_any(dev, argp); +@@ -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); ++ 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/winesync.h b/include/uapi/linux/winesync.h -index f57ebfbe1dd9..44025a510cb9 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -34,5 +34,7 @@ struct winesync_wait_args { - struct winesync_sem_args) - #define WINESYNC_IOC_WAIT_ANY _IOWR(WINESYNC_IOC_BASE, 3, \ - struct winesync_wait_args) -+#define WINESYNC_IOC_WAIT_ALL _IOWR(WINESYNC_IOC_BASE, 4, \ -+ struct winesync_wait_args) +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 10f07da7864e..a5bed5a39b21 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) #endif -- -2.36.0 +2.43.0 -From 2838a60302cd26a2ab92a143749e455edebe7b7c Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 965d8711ba4fbb0867c8baef95129f0ff62d9419 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:41:10 -0600 -Subject: [PATCH 07/34] winesync: Introduce WINESYNC_IOC_CREATE_MUTEX. +Subject: [PATCH 07/32] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX. +This corresponds to the NT syscall NtCreateMutant(). --- - drivers/misc/winesync.c | 72 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 8 ++++ + drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 8 +++++ 2 files changed, 80 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 2b708c5b88a6..18eb05975907 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 2685363fae9e..d48f2ef41341 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c @@ -16,6 +16,7 @@ - enum winesync_type { - WINESYNC_TYPE_SEM, -+ WINESYNC_TYPE_MUTEX, + enum ntsync_type { + NTSYNC_TYPE_SEM, ++ NTSYNC_TYPE_MUTEX, }; - struct winesync_obj { -@@ -60,6 +61,10 @@ struct winesync_obj { + struct ntsync_obj { +@@ -60,6 +61,10 @@ struct ntsync_obj { __u32 count; __u32 max; } sem; @@ -1237,40 +1246,40 @@ index 2b708c5b88a6..18eb05975907 100644 } u; }; -@@ -188,6 +193,10 @@ static bool is_signaled(struct winesync_obj *obj, __u32 owner) +@@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) switch (obj->type) { - case WINESYNC_TYPE_SEM: + case NTSYNC_TYPE_SEM: return !!obj->u.sem.count; -+ case WINESYNC_TYPE_MUTEX: ++ case NTSYNC_TYPE_MUTEX: + if (obj->u.mutex.owner && obj->u.mutex.owner != owner) + return false; + return obj->u.mutex.count < UINT_MAX; } WARN(1, "bad object type %#x\n", obj->type); -@@ -230,6 +239,10 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, - case WINESYNC_TYPE_SEM: +@@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + case NTSYNC_TYPE_SEM: obj->u.sem.count--; break; -+ case WINESYNC_TYPE_MUTEX: ++ case NTSYNC_TYPE_MUTEX: + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; } } wake_up_process(q->task); -@@ -272,6 +285,28 @@ static void try_wake_any_sem(struct winesync_obj *sem) +@@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) } } -+static void try_wake_any_mutex(struct winesync_obj *mutex) ++static void try_wake_any_mutex(struct ntsync_obj *mutex) +{ -+ struct winesync_q_entry *entry; ++ struct ntsync_q_entry *entry; + + lockdep_assert_held(&mutex->lock); + + list_for_each_entry(entry, &mutex->any_waiters, node) { -+ struct winesync_q *q = entry->q; ++ struct ntsync_q *q = entry->q; + + if (mutex->u.mutex.count == UINT_MAX) + break; @@ -1285,18 +1294,18 @@ index 2b708c5b88a6..18eb05975907 100644 + } +} + - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) + static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) { - struct winesync_sem_args __user *user_args = argp; -@@ -304,6 +339,38 @@ static int winesync_create_sem(struct winesync_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); } -+static int winesync_create_mutex(struct winesync_device *dev, void __user *argp) ++static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_obj *mutex; ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ struct ntsync_obj *mutex; + __u32 id; + int ret; + @@ -1311,7 +1320,7 @@ index 2b708c5b88a6..18eb05975907 100644 + return -ENOMEM; + + init_obj(mutex); -+ mutex->type = WINESYNC_TYPE_MUTEX; ++ mutex->type = NTSYNC_TYPE_MUTEX; + mutex->u.mutex.count = args.count; + mutex->u.mutex.owner = args.owner; + @@ -1324,79 +1333,80 @@ index 2b708c5b88a6..18eb05975907 100644 + return put_user(id, &user_args->mutex); +} + - static int winesync_delete(struct winesync_device *dev, void __user *argp) + static int ntsync_delete(struct ntsync_device *dev, void __user *argp) { - struct winesync_obj *obj; -@@ -495,6 +562,9 @@ static void try_wake_any_obj(struct winesync_obj *obj) - case WINESYNC_TYPE_SEM: + struct ntsync_obj *obj; +@@ -497,6 +564,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + case NTSYNC_TYPE_SEM: try_wake_any_sem(obj); break; -+ case WINESYNC_TYPE_MUTEX: ++ case NTSYNC_TYPE_MUTEX: + try_wake_any_mutex(obj); + break; } } -@@ -660,6 +730,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, +@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, void __user *argp = (void __user *)parm; switch (cmd) { -+ case WINESYNC_IOC_CREATE_MUTEX: -+ return winesync_create_mutex(dev, argp); - case WINESYNC_IOC_CREATE_SEM: - return winesync_create_sem(dev, argp); - case WINESYNC_IOC_DELETE: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 44025a510cb9..23606a3b1546 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -16,6 +16,12 @@ struct winesync_sem_args { ++ case NTSYNC_IOC_CREATE_MUTEX: ++ return ntsync_create_mutex(dev, argp); + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_DELETE: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index a5bed5a39b21..26d1b3d4847f 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -16,6 +16,12 @@ struct ntsync_sem_args { __u32 max; }; -+struct winesync_mutex_args { ++struct ntsync_mutex_args { + __u32 mutex; + __u32 owner; + __u32 count; +}; + - struct winesync_wait_args { + struct ntsync_wait_args { __u64 timeout; __u64 objs; -@@ -36,5 +42,7 @@ struct winesync_wait_args { - struct winesync_wait_args) - #define WINESYNC_IOC_WAIT_ALL _IOWR(WINESYNC_IOC_BASE, 4, \ - struct winesync_wait_args) -+#define WINESYNC_IOC_CREATE_MUTEX _IOWR(WINESYNC_IOC_BASE, 5, \ -+ struct winesync_mutex_args) +@@ -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) #endif -- -2.36.0 +2.43.0 -From 25b9628ad91377840cdc2b08dd53e1539ad05bdd Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From b348f2e4e4054c20f0f1852ffaa90095e1f32415 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:44:41 -0600 -Subject: [PATCH 08/34] winesync: Introduce WINESYNC_IOC_PUT_MUTEX. +Subject: [PATCH 08/32] ntsync: Introduce NTSYNC_IOC_PUT_MUTEX. +This corresponds to the NT syscall NtReleaseMutant(). --- - drivers/misc/winesync.c | 67 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ + drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ 2 files changed, 69 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 18eb05975907..d18d08a68546 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -450,6 +450,71 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index d48f2ef41341..28f43768d1c3 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) return ret; } +/* + * Actually change the mutex state, returning -EPERM if not the owner. + */ -+static int put_mutex_state(struct winesync_obj *mutex, -+ const struct winesync_mutex_args *args) ++static int put_mutex_state(struct ntsync_obj *mutex, ++ const struct ntsync_mutex_args *args) +{ + lockdep_assert_held(&mutex->lock); + @@ -1408,11 +1418,11 @@ index 18eb05975907..d18d08a68546 100644 + return 0; +} + -+static int winesync_put_mutex(struct winesync_device *dev, void __user *argp) ++static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_obj *mutex; ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ struct ntsync_obj *mutex; + __u32 prev_count; + int ret; + @@ -1421,13 +1431,13 @@ index 18eb05975907..d18d08a68546 100644 + if (!args.owner) + return -EINVAL; + -+ mutex = get_obj_typed(dev, args.mutex, WINESYNC_TYPE_MUTEX); ++ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX); + if (!mutex) + return -EINVAL; + + if (atomic_read(&mutex->all_hint) > 0) { + spin_lock(&dev->wait_all_lock); -+ spin_lock(&mutex->lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); + + prev_count = mutex->u.mutex.count; + ret = put_mutex_state(mutex, &args); @@ -1457,48 +1467,51 @@ index 18eb05975907..d18d08a68546 100644 + return ret; +} + - static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) { int ret = 0; -@@ -736,6 +801,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_create_sem(dev, argp); - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); -+ case WINESYNC_IOC_PUT_MUTEX: -+ return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); - case WINESYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 23606a3b1546..fde08cb8ab95 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -44,5 +44,7 @@ struct winesync_wait_args { - struct winesync_wait_args) - #define WINESYNC_IOC_CREATE_MUTEX _IOWR(WINESYNC_IOC_BASE, 5, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ -+ struct winesync_mutex_args) +@@ -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: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 26d1b3d4847f..2e44e7e77776 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) #endif -- -2.36.0 +2.43.0 -From 97d6dc0155da6609849e6a03bcc9e7d7e0cb58f5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From f042ca07e1744d2bb04942163e4e65fc6e624f41 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:46:46 -0600 -Subject: [PATCH 09/34] winesync: Introduce WINESYNC_IOC_KILL_OWNER. +Subject: [PATCH 09/32] ntsync: Introduce NTSYNC_IOC_KILL_OWNER. +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. --- - drivers/misc/winesync.c | 80 ++++++++++++++++++++++++++++++++++- - include/uapi/linux/winesync.h | 1 + + drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++- + include/uapi/linux/ntsync.h | 1 + 2 files changed, 79 insertions(+), 2 deletions(-) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index d18d08a68546..891537063bb6 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -64,6 +64,7 @@ struct winesync_obj { +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; @@ -1506,25 +1519,25 @@ index d18d08a68546..891537063bb6 100644 } mutex; } u; }; -@@ -87,6 +88,7 @@ struct winesync_q { +@@ -87,6 +88,7 @@ struct ntsync_q { atomic_t signaled; bool all; + bool ownerdead; __u32 count; - struct winesync_q_entry entries[]; + struct ntsync_q_entry entries[]; }; -@@ -240,6 +242,9 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, +@@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, obj->u.sem.count--; break; - case WINESYNC_TYPE_MUTEX: + 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; -@@ -300,6 +305,9 @@ static void try_wake_any_mutex(struct winesync_obj *mutex) +@@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) continue; if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { @@ -1534,14 +1547,14 @@ index d18d08a68546..891537063bb6 100644 mutex->u.mutex.count++; mutex->u.mutex.owner = q->owner; wake_up_process(q->task); -@@ -515,6 +523,71 @@ static int winesync_put_mutex(struct winesync_device *dev, void __user *argp) +@@ -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 winesync_obj *mutex) ++static void put_mutex_ownerdead_state(struct ntsync_obj *mutex) +{ + lockdep_assert_held(&mutex->lock); + @@ -1550,9 +1563,9 @@ index d18d08a68546..891537063bb6 100644 + mutex->u.mutex.count = 0; +} + -+static int winesync_kill_owner(struct winesync_device *dev, void __user *argp) ++static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_obj *obj; ++ struct ntsync_obj *obj; + unsigned long id; + __u32 owner; + @@ -1567,14 +1580,14 @@ index d18d08a68546..891537063bb6 100644 + if (!kref_get_unless_zero(&obj->refcount)) + continue; + -+ if (obj->type != WINESYNC_TYPE_MUTEX) { ++ 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(&obj->lock); ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); + + if (obj->u.mutex.owner == owner) { + put_mutex_ownerdead_state(obj); @@ -1603,10 +1616,10 @@ index d18d08a68546..891537063bb6 100644 + return 0; +} + - static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) { int ret = 0; -@@ -583,6 +656,7 @@ static int setup_wait(struct winesync_device *dev, +@@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev, q->owner = args->owner; atomic_set(&q->signaled, -1); q->all = all; @@ -1614,8 +1627,8 @@ index d18d08a68546..891537063bb6 100644 q->count = count; for (i = 0; i < count; i++) { -@@ -695,7 +769,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - struct winesync_wait_args __user *user_args = argp; +@@ -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; @@ -1623,8 +1636,8 @@ index d18d08a68546..891537063bb6 100644 if (put_user(signaled, &user_args->index)) ret = -EFAULT; -@@ -776,7 +850,7 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp) - struct winesync_wait_args __user *user_args = argp; +@@ -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; @@ -1632,58 +1645,59 @@ index d18d08a68546..891537063bb6 100644 if (put_user(signaled, &user_args->index)) ret = -EFAULT; -@@ -801,6 +875,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_create_sem(dev, argp); - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); -+ case WINESYNC_IOC_KILL_OWNER: -+ return winesync_kill_owner(dev, argp); - case WINESYNC_IOC_PUT_MUTEX: - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index fde08cb8ab95..f57aa76d57f5 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -46,5 +46,6 @@ struct winesync_wait_args { - struct winesync_mutex_args) - #define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) +@@ -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.36.0 +2.43.0 -From 888bb6fa10b7eb593db18a38fe696fc396ee30de Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From fc85bff90ef0348584fca122f96aa3ec1a5fe604 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:47:55 -0600 -Subject: [PATCH 10/34] winesync: Introduce WINESYNC_IOC_READ_SEM. +Subject: [PATCH 10/32] ntsync: Introduce NTSYNC_IOC_READ_SEM. +This corresponds to the NT syscall NtQuerySemaphore(). --- - drivers/misc/winesync.c | 29 +++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ + drivers/misc/ntsync.c | 29 +++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ 2 files changed, 31 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 891537063bb6..98bedda2f8eb 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -523,6 +523,33 @@ static int winesync_put_mutex(struct winesync_device *dev, void __user *argp) +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 1173c750c106..70c60f294bb2 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -522,6 +522,33 @@ static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) return ret; } -+static int winesync_read_sem(struct winesync_device *dev, void __user *argp) ++static int ntsync_read_sem(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_obj *sem; ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ struct ntsync_obj *sem; + __u32 id; + + if (get_user(id, &user_args->sem)) + return -EFAULT; + -+ sem = get_obj_typed(dev, id, WINESYNC_TYPE_SEM); ++ sem = get_obj_typed(dev, id, NTSYNC_TYPE_SEM); + if (!sem) + return -EINVAL; + @@ -1703,60 +1717,61 @@ index 891537063bb6..98bedda2f8eb 100644 /* * Actually change the mutex state to mark its owner as dead. */ -@@ -881,6 +908,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_READ_SEM: -+ return winesync_read_sem(dev, argp); - case WINESYNC_IOC_WAIT_ALL: - return winesync_wait_all(dev, argp); - case WINESYNC_IOC_WAIT_ANY: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index f57aa76d57f5..311eb810647d 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -47,5 +47,7 @@ struct winesync_wait_args { - #define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ - struct winesync_mutex_args) - #define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) -+#define WINESYNC_IOC_READ_SEM _IOWR(WINESYNC_IOC_BASE, 8, \ -+ struct winesync_sem_args) +@@ -883,6 +910,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_put_mutex(dev, argp); + case NTSYNC_IOC_PUT_SEM: + return ntsync_put_sem(dev, argp); ++ case NTSYNC_IOC_READ_SEM: ++ return ntsync_read_sem(dev, argp); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); + case NTSYNC_IOC_WAIT_ANY: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index fec9a3993322..b84a57c13d80 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -49,5 +49,7 @@ struct ntsync_wait_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) ++#define NTSYNC_IOC_READ_SEM _IOWR(NTSYNC_IOC_BASE, 8, \ ++ struct ntsync_sem_args) #endif -- -2.36.0 +2.43.0 -From 4f17c2ab7b9aca22fb00f7f16e0bd3cf70c44fe1 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 4acc2acbbcacf80485e7d443c0a2327d50879c64 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 11:48:10 -0600 -Subject: [PATCH 11/34] winesync: Introduce WINESYNC_IOC_READ_MUTEX. +Subject: [PATCH 11/32] ntsync: Introduce NTSYNC_IOC_READ_MUTEX. +This corresponds to the NT syscall NtQueryMutant(). --- - drivers/misc/winesync.c | 31 +++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ + drivers/misc/ntsync.c | 31 +++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ 2 files changed, 33 insertions(+) -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 98bedda2f8eb..eae272663abe 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -550,6 +550,35 @@ static int winesync_read_sem(struct winesync_device *dev, void __user *argp) +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 70c60f294bb2..88adb52bad93 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -549,6 +549,35 @@ static int ntsync_read_sem(struct ntsync_device *dev, void __user *argp) return 0; } -+static int winesync_read_mutex(struct winesync_device *dev, void __user *argp) ++static int ntsync_read_mutex(struct ntsync_device *dev, void __user *argp) +{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_obj *mutex; ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ struct ntsync_obj *mutex; + __u32 id; + int ret; + + if (get_user(id, &user_args->mutex)) + return -EFAULT; + -+ mutex = get_obj_typed(dev, id, WINESYNC_TYPE_MUTEX); ++ mutex = get_obj_typed(dev, id, NTSYNC_TYPE_MUTEX); + if (!mutex) + return -EINVAL; + @@ -1777,447 +1792,754 @@ index 98bedda2f8eb..eae272663abe 100644 /* * Actually change the mutex state to mark its owner as dead. */ -@@ -908,6 +937,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_READ_MUTEX: -+ return winesync_read_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: - return winesync_read_sem(dev, argp); - case WINESYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 311eb810647d..3371a303a927 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -49,5 +49,7 @@ struct winesync_wait_args { - #define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) - #define WINESYNC_IOC_READ_SEM _IOWR(WINESYNC_IOC_BASE, 8, \ - struct winesync_sem_args) -+#define WINESYNC_IOC_READ_MUTEX _IOWR(WINESYNC_IOC_BASE, 9, \ -+ struct winesync_mutex_args) +@@ -910,6 +939,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_put_mutex(dev, argp); + case NTSYNC_IOC_PUT_SEM: + return ntsync_put_sem(dev, argp); ++ case NTSYNC_IOC_READ_MUTEX: ++ return ntsync_read_mutex(dev, argp); + case NTSYNC_IOC_READ_SEM: + return ntsync_read_sem(dev, argp); + case NTSYNC_IOC_WAIT_ALL: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index b84a57c13d80..fa57f190c80e 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -51,5 +51,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_KILL_OWNER _IOW (NTSYNC_IOC_BASE, 7, __u32) + #define NTSYNC_IOC_READ_SEM _IOWR(NTSYNC_IOC_BASE, 8, \ + struct ntsync_sem_args) ++#define NTSYNC_IOC_READ_MUTEX _IOWR(NTSYNC_IOC_BASE, 9, \ ++ struct ntsync_mutex_args) #endif -- -2.36.0 +2.43.0 -From e897f7ec5164d6d5d3d9881756be9a538c533487 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Fri, 5 Mar 2021 11:50:49 -0600 -Subject: [PATCH 12/34] docs: winesync: Add documentation for the winesync - uAPI. +From 1bc3fa335b3c30797586eebbf533135ccddcb934 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 19 Jan 2022 18:21:03 -0600 +Subject: [PATCH 12/32] ntsync: Introduce NTSYNC_IOC_CREATE_EVENT. +This corresponds to the NT syscall NtCreateEvent(). --- - Documentation/userspace-api/index.rst | 1 + - Documentation/userspace-api/winesync.rst | 324 +++++++++++++++++++++++ - 2 files changed, 325 insertions(+) - create mode 100644 Documentation/userspace-api/winesync.rst + drivers/misc/ntsync.c | 65 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 8 +++++ + 2 files changed, 73 insertions(+) -diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst -index a61eac0c73f8..0bf697ddcb09 100644 ---- a/Documentation/userspace-api/index.rst -+++ b/Documentation/userspace-api/index.rst -@@ -29,6 +29,7 @@ place where this information is gathered. - sysfs-platform_profile - vduse - futex2 -+ winesync +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 88adb52bad93..3778dbe617e9 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -17,6 +17,7 @@ + enum ntsync_type { + NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, ++ NTSYNC_TYPE_EVENT, + }; - .. only:: subproject and html + struct ntsync_obj { +@@ -66,6 +67,10 @@ struct ntsync_obj { + __u32 owner; + bool ownerdead; + } mutex; ++ struct { ++ bool manual; ++ bool signaled; ++ } event; + } u; + }; -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -new file mode 100644 -index 000000000000..34e54be229cf ---- /dev/null -+++ b/Documentation/userspace-api/winesync.rst -@@ -0,0 +1,324 @@ -+===================================== -+Wine synchronization primitive driver -+===================================== -+ -+This page documents the user-space API for the winesync driver. -+ -+winesync is a support driver for emulation of NT synchronization -+primitives by the Wine project or other NT emulators. It exists -+because implementation in user-space, using existing tools, cannot -+simultaneously satisfy performance, correctness, and security -+constraints. It is implemented entirely in software, and does not -+drive any hardware device. -+ -+This interface is meant as a compatibility tool only, and should not -+be used for general synchronization. Instead use generic, versatile -+interfaces such as futex(2) and poll(2). -+ -+Synchronization primitives -+========================== -+ -+The winesync driver exposes two types of synchronization primitives, -+semaphores and mutexes. -+ -+A semaphore holds a single volatile 32-bit counter, and a static -+32-bit integer denoting the maximum value. It is considered signaled -+when the counter is nonzero. The counter is decremented by one when a -+wait is satisfied. Both the initial and maximum count are established -+when the semaphore is created. -+ -+A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit -+identifier denoting its owner. A mutex is considered signaled when its -+owner is zero (indicating that it is not owned). The recursion count -+is incremented when a wait is satisfied, and ownership is set to the -+given identifier. -+ -+A mutex also holds an internal flag denoting whether its previous -+owner has died; such a mutex is said to be inconsistent. Owner death -+is not tracked automatically based on thread death, but rather must be -+communicated using ``WINESYNC_IOC_KILL_OWNER``. An inconsistent mutex -+is inherently considered unowned. -+ -+Except for the "unowned" semantics of zero, the actual value of the -+owner identifier is not interpreted by the winesync driver at all. The -+intended use is to store a thread identifier; however, the winesync -+driver does not actually validate that a calling thread provides -+consistent or unique identifiers. -+ -+Unless specified otherwise, all operations on an object are atomic and -+totally ordered with respect to other operations on the same object. -+ -+Objects are represented by unsigned 32-bit integers. -+ -+Char device -+=========== -+ -+The winesync driver creates a single char device /dev/winesync. Each -+file description opened on the device represents a unique namespace. -+That is, objects created on one open file description are shared -+across all its individual descriptors, but are not shared with other -+open() calls on the same device. The same file description may be -+shared across multiple processes. -+ -+ioctl reference -+=============== -+ -+All operations on the device are done through ioctls. There are three -+structures used in ioctl calls:: -+ -+ struct winesync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+ }; -+ -+ struct winesync_mutex_args { -+ __u32 mutex; -+ __u32 owner; -+ __u32 count; -+ }; -+ -+ struct winesync_wait_args { -+ __u64 timeout; -+ __u64 objs; -+ __u32 count; -+ __u32 owner; -+ __u32 index; -+ __u32 pad; -+ }; -+ -+Depending on the ioctl, members of the structure may be used as input, -+output, or not at all. All ioctls return 0 on success. -+ -+The ioctls are as follows: -+ -+.. c:macro:: WINESYNC_IOC_CREATE_SEM -+ -+ Create a semaphore object. Takes a pointer to struct -+ :c:type:`winesync_sem_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``sem`` -+ - On output, contains the identifier of the created semaphore. -+ * - ``count`` -+ - Initial count of the semaphore. -+ * - ``max`` -+ - Maximum count of the semaphore. -+ -+ Fails with ``EINVAL`` if ``count`` is greater than ``max``. -+ -+.. c:macro:: WINESYNC_IOC_CREATE_MUTEX -+ -+ Create a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: +@@ -199,6 +204,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); +@@ -248,6 +255,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); +@@ -314,6 +325,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; + -+ .. list-table:: ++ lockdep_assert_held(&event->lock); + -+ * - ``mutex`` -+ - On output, contains the identifier of the created mutex. -+ * - ``count`` -+ - Initial recursion count of the mutex. -+ * - ``owner`` -+ - Initial owner of the mutex. ++ list_for_each_entry(entry, &event->any_waiters, node) { ++ struct ntsync_q *q = entry->q; + -+ If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is -+ zero and ``count`` is nonzero, the function fails with ``EINVAL``. ++ if (!event->u.event.signaled) ++ break; + -+.. c:macro:: WINESYNC_IOC_DELETE ++ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (!event->u.event.manual) ++ event->u.event.signaled = false; ++ wake_up_process(q->task); ++ } ++ } ++} + -+ Delete an object of any type. Takes an input-only pointer to a -+ 32-bit integer denoting the object to delete. + static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_sem_args __user *user_args = argp; +@@ -378,6 +409,35 @@ static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) + return put_user(id, &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; ++ __u32 id; ++ int ret; + -+ Wait ioctls currently in progress are not interrupted, and behave as -+ if the object remains valid. ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; + -+.. c:macro:: WINESYNC_IOC_PUT_SEM ++ event = kzalloc(sizeof(*event), GFP_KERNEL); ++ if (!event) ++ return -ENOMEM; + -+ Post to a semaphore object. Takes a pointer to struct -+ :c:type:`winesync_sem_args`, which is used as follows: ++ init_obj(event); ++ event->type = NTSYNC_TYPE_EVENT; ++ event->u.event.manual = args.manual; ++ event->u.event.signaled = args.signaled; + -+ .. list-table:: ++ ret = xa_alloc(&dev->objects, &id, event, xa_limit_32b, GFP_KERNEL); ++ if (ret < 0) { ++ kfree(event); ++ return ret; ++ } + -+ * - ``sem`` -+ - Semaphore object to post to. -+ * - ``count`` -+ - Count to add to the semaphore. On output, contains the -+ previous count of the semaphore. -+ * - ``max`` -+ - Not used. ++ return put_user(id, &user_args->event); ++} + -+ If adding ``count`` to the semaphore's current count would raise the -+ latter past the semaphore's maximum count, the ioctl fails with -+ ``EOVERFLOW`` and the semaphore is not affected. If raising the -+ semaphore's count causes it to become signaled, eligible threads -+ waiting on this semaphore will be woken and the semaphore's count -+ decremented appropriately. + static int ntsync_delete(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_obj *obj; +@@ -762,6 +822,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; + } + } + +@@ -927,6 +990,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 fa57f190c80e..c7cbdeff32c9 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; ++}; + -+.. c:macro:: WINESYNC_IOC_PUT_MUTEX + struct ntsync_wait_args { + __u64 timeout; + __u64 objs; +@@ -53,5 +59,7 @@ struct ntsync_wait_args { + struct ntsync_sem_args) + #define NTSYNC_IOC_READ_MUTEX _IOWR(NTSYNC_IOC_BASE, 9, \ + struct ntsync_mutex_args) ++#define NTSYNC_IOC_CREATE_EVENT _IOWR(NTSYNC_IOC_BASE, 10, \ ++ struct ntsync_event_args) + + #endif +-- +2.43.0 + +From d4d9e2196dc13cf89b8181eb4eee86d4a26ef026 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 19 Jan 2022 18:43:30 -0600 +Subject: [PATCH 13/32] ntsync: Introduce NTSYNC_IOC_SET_EVENT. + +This corresponds to the NT syscall NtSetEvent(). +--- + drivers/misc/ntsync.c | 45 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 47 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 3778dbe617e9..cd6478bd93bd 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -703,6 +703,49 @@ static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) + return 0; + } + ++static int ntsync_set_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; ++ bool prev_state; + -+ Release a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; + -+ .. list-table:: ++ event = get_obj_typed(dev, args.event, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -EINVAL; + -+ * - ``mutex`` -+ - Mutex object to release. -+ * - ``owner`` -+ - Mutex owner identifier. -+ * - ``count`` -+ - On output, contains the previous recursion count. ++ if (atomic_read(&event->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); + -+ If ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner`` -+ is not the current owner of the mutex, the ioctl fails with -+ ``EPERM``. ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_all_obj(dev, event); ++ try_wake_any_event(event); + -+ The mutex's count will be decremented by one. If decrementing the -+ mutex's count causes it to become zero, the mutex is marked as -+ unowned and signaled, and eligible threads waiting on it will be -+ woken as appropriate. ++ spin_unlock(&event->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&event->lock); + -+.. c:macro:: WINESYNC_IOC_READ_SEM ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_any_event(event); + -+ Read the current state of a semaphore object. Takes a pointer to -+ struct :c:type:`winesync_sem_args`, which is used as follows: ++ spin_unlock(&event->lock); ++ } + -+ .. list-table:: ++ put_obj(event); + -+ * - ``sem`` -+ - Semaphore object to read. -+ * - ``count`` -+ - On output, contains the current count of the semaphore. -+ * - ``max`` -+ - On output, contains the maximum count of the semaphore. ++ if (put_user(prev_state, &user_args->signaled)) ++ return -EFAULT; + -+.. c:macro:: WINESYNC_IOC_READ_MUTEX ++ return 0; ++} + -+ Read the current state of a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) + { + int ret = 0; +@@ -1008,6 +1051,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_read_mutex(dev, argp); + case NTSYNC_IOC_READ_SEM: + return ntsync_read_sem(dev, argp); ++ case NTSYNC_IOC_SET_EVENT: ++ return ntsync_set_event(dev, argp); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); + case NTSYNC_IOC_WAIT_ANY: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index c7cbdeff32c9..8a230f5d4b3f 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -61,5 +61,7 @@ struct ntsync_wait_args { + struct ntsync_mutex_args) + #define NTSYNC_IOC_CREATE_EVENT _IOWR(NTSYNC_IOC_BASE, 10, \ + struct ntsync_event_args) ++#define NTSYNC_IOC_SET_EVENT _IOWR(NTSYNC_IOC_BASE, 11, \ ++ struct ntsync_event_args) + + #endif +-- +2.43.0 + +From 03224658123725d6b8a27b55cd103ad782ebad7b Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 19 Jan 2022 19:00:25 -0600 +Subject: [PATCH 14/32] ntsync: Introduce NTSYNC_IOC_RESET_EVENT. + +This corresponds to the NT syscall NtResetEvent(). +--- + drivers/misc/ntsync.c | 31 +++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 33 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index cd6478bd93bd..151714dee0ff 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -746,6 +746,35 @@ static int ntsync_set_event(struct ntsync_device *dev, void __user *argp) + return 0; + } + ++static int ntsync_reset_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; ++ bool prev_state; + -+ .. list-table:: ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; + -+ * - ``mutex`` -+ - Mutex object to read. -+ * - ``owner`` -+ - On output, contains the current owner of the mutex, or zero -+ if the mutex is not currently owned. -+ * - ``count`` -+ - On output, contains the current recursion count of the mutex. ++ event = get_obj_typed(dev, args.event, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -EINVAL; + -+ If the mutex is marked as inconsistent, the function fails with -+ ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to -+ zero. ++ spin_lock(&event->lock); + -+.. c:macro:: WINESYNC_IOC_KILL_OWNER ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = false; + -+ Mark any mutexes owned by the given owner as unowned and -+ inconsistent. Takes an input-only pointer to a 32-bit integer -+ denoting the owner. If the owner is zero, the ioctl fails with -+ ``EINVAL``. ++ spin_unlock(&event->lock); + -+ For each mutex currently owned by the given owner, eligible threads -+ waiting on said mutex will be woken as appropriate (and such waits -+ will fail with ``EOWNERDEAD``, as described below). ++ put_obj(event); + -+ The operation as a whole is not atomic; however, the modification of -+ each mutex is atomic and totally ordered with respect to other -+ operations on the same mutex. ++ if (put_user(prev_state, &user_args->signaled)) ++ return -EFAULT; + -+.. c:macro:: WINESYNC_IOC_WAIT_ANY ++ return 0; ++} + -+ Poll on any of a list of objects, atomically acquiring at most one. -+ Takes a pointer to struct :c:type:`winesync_wait_args`, which is -+ used as follows: + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) + { + int ret = 0; +@@ -1051,6 +1080,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_read_mutex(dev, argp); + case NTSYNC_IOC_READ_SEM: + return ntsync_read_sem(dev, argp); ++ case NTSYNC_IOC_RESET_EVENT: ++ return ntsync_reset_event(dev, argp); + case NTSYNC_IOC_SET_EVENT: + return ntsync_set_event(dev, argp); + case NTSYNC_IOC_WAIT_ALL: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 8a230f5d4b3f..806125856117 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -63,5 +63,7 @@ struct ntsync_wait_args { + struct ntsync_event_args) + #define NTSYNC_IOC_SET_EVENT _IOWR(NTSYNC_IOC_BASE, 11, \ + struct ntsync_event_args) ++#define NTSYNC_IOC_RESET_EVENT _IOWR(NTSYNC_IOC_BASE, 12, \ ++ struct ntsync_event_args) + + #endif +-- +2.43.0 + +From 16daeb0c9b8d95ab27c0c807c49ddebb5dba52c0 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 19 Jan 2022 19:10:12 -0600 +Subject: [PATCH 15/32] ntsync: Introduce NTSYNC_IOC_PULSE_EVENT. + +This corresponds to the NT syscall NtPulseEvent(). +--- + drivers/misc/ntsync.c | 11 +++++++++-- + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 151714dee0ff..45405d01e11d 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -703,7 +703,8 @@ static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) + return 0; + } + +-static int ntsync_set_event(struct ntsync_device *dev, void __user *argp) ++static int ntsync_set_event(struct ntsync_device *dev, void __user *argp, ++ bool pulse) + { + struct ntsync_event_args __user *user_args = argp; + struct ntsync_event_args args; +@@ -725,6 +726,8 @@ static int ntsync_set_event(struct ntsync_device *dev, 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); +@@ -734,6 +737,8 @@ static int ntsync_set_event(struct ntsync_device *dev, 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); + } +@@ -1072,6 +1077,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_delete(dev, argp); + case NTSYNC_IOC_KILL_OWNER: + return ntsync_kill_owner(dev, argp); ++ case NTSYNC_IOC_PULSE_EVENT: ++ return ntsync_set_event(dev, argp, true); + case NTSYNC_IOC_PUT_MUTEX: + return ntsync_put_mutex(dev, argp); + case NTSYNC_IOC_PUT_SEM: +@@ -1083,7 +1090,7 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + case NTSYNC_IOC_RESET_EVENT: + return ntsync_reset_event(dev, argp); + case NTSYNC_IOC_SET_EVENT: +- return ntsync_set_event(dev, argp); ++ return ntsync_set_event(dev, argp, false); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); + case NTSYNC_IOC_WAIT_ANY: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 806125856117..30f56b4388c8 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -65,5 +65,7 @@ struct ntsync_wait_args { + struct ntsync_event_args) + #define NTSYNC_IOC_RESET_EVENT _IOWR(NTSYNC_IOC_BASE, 12, \ + struct ntsync_event_args) ++#define NTSYNC_IOC_PULSE_EVENT _IOWR(NTSYNC_IOC_BASE, 13, \ ++ struct ntsync_event_args) + + #endif +-- +2.43.0 + +From c264fe3627e7032d88cd6d56f4ce6a2c2fbc30af Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 19 Jan 2022 19:14:00 -0600 +Subject: [PATCH 16/32] ntsync: Introduce NTSYNC_IOC_READ_EVENT. + +This corresponds to the NT syscall NtQueryEvent(). +--- + drivers/misc/ntsync.c | 29 +++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 31 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 45405d01e11d..6821d9aa967d 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -638,6 +638,33 @@ static int ntsync_read_mutex(struct ntsync_device *dev, void __user *argp) + return ret; + } + ++static int ntsync_read_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; ++ __u32 id; + -+ .. list-table:: ++ if (get_user(id, &user_args->event)) ++ return -EFAULT; + -+ * - ``timeout`` -+ - Optional pointer to a 64-bit struct :c:type:`timespec` -+ (specified as an integer so that the structure has the same -+ size regardless of architecture). The timeout is specified in -+ absolute format, as measured against the MONOTONIC clock. If -+ the timeout is equal to or earlier than the current time, the -+ function returns immediately without sleeping. If ``timeout`` -+ is zero, i.e. NULL, the function will sleep until an object -+ is signaled, and will not fail with ``ETIMEDOUT``. -+ * - ``objs`` -+ - Pointer to an array of ``count`` 32-bit object identifiers -+ (specified as an integer so that the structure has the same -+ size regardless of architecture). If any identifier is -+ invalid, the function fails with ``EINVAL``. -+ * - ``count`` -+ - Number of object identifiers specified in the ``objs`` array. -+ * - ``owner`` -+ - Mutex owner identifier. If any object in ``objs`` is a mutex, -+ the ioctl will attempt to acquire that mutex on behalf of -+ ``owner``. If ``owner`` is zero, the ioctl fails with -+ ``EINVAL``. -+ * - ``index`` -+ - On success, contains the index (into ``objs``) of the object -+ which was signaled. -+ * - ``pad`` -+ - This field is not used and must be set to zero. ++ event = get_obj_typed(dev, id, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -EINVAL; + -+ This function attempts to acquire one of the given objects. If -+ unable to do so, it sleeps until an object becomes signaled, -+ subsequently acquiring it, or the timeout expires. In the latter -+ case the ioctl fails with ``ETIMEDOUT``. The function only acquires -+ one object, even if multiple objects are signaled. ++ args.event = id; ++ spin_lock(&event->lock); ++ args.manual = event->u.event.manual; ++ args.signaled = event->u.event.signaled; ++ spin_unlock(&event->lock); + -+ A semaphore is considered to be signaled if its count is nonzero, -+ and is acquired by decrementing its count by one. A mutex is -+ considered to be signaled if it is unowned or if its owner matches -+ the ``owner`` argument, and is acquired by incrementing its -+ recursion count by one and setting its owner to the ``owner`` -+ argument. ++ put_obj(event); + -+ Acquisition is atomic and totally ordered with respect to other -+ operations on the same object. If two wait operations (with -+ different ``owner`` identifiers) are queued on the same mutex, only -+ one is signaled. If two wait operations are queued on the same -+ semaphore, and a value of one is posted to it, only one is signaled. -+ The order in which threads are signaled is not specified. ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} + -+ If an inconsistent mutex is acquired, the ioctl fails with -+ ``EOWNERDEAD``. Although this is a failure return, the function may -+ otherwise be considered successful. The mutex is marked as owned by -+ the given owner (with a recursion count of 1) and as no longer -+ inconsistent, and ``index`` is still set to the index of the mutex. + /* + * Actually change the mutex state to mark its owner as dead. + */ +@@ -1083,6 +1110,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + return ntsync_put_mutex(dev, argp); + case NTSYNC_IOC_PUT_SEM: + return ntsync_put_sem(dev, argp); ++ case NTSYNC_IOC_READ_EVENT: ++ return ntsync_read_event(dev, argp); + case NTSYNC_IOC_READ_MUTEX: + return ntsync_read_mutex(dev, argp); + case NTSYNC_IOC_READ_SEM: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 30f56b4388c8..86c28b909777 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -67,5 +67,7 @@ struct ntsync_wait_args { + struct ntsync_event_args) + #define NTSYNC_IOC_PULSE_EVENT _IOWR(NTSYNC_IOC_BASE, 13, \ + struct ntsync_event_args) ++#define NTSYNC_IOC_READ_EVENT _IOWR(NTSYNC_IOC_BASE, 14, \ ++ struct ntsync_event_args) + + #endif +-- +2.43.0 + +From 198ddbebdbe3d062505bde44619da050eead04e8 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Wed, 13 Apr 2022 20:02:39 -0500 +Subject: [PATCH 17/32] ntsync: Introduce alertable waits. + +This implements the "alertable" feature of NtWaitForMultipleObjects(). +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. +--- + 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 6821d9aa967d..6f4cb9a3ed5a 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -840,10 +840,11 @@ static int setup_wait(struct ntsync_device *dev, + const __u32 count = args->count; + struct ntsync_q *q; + ktime_t timeout = 0; ++ __u32 total_count; + __u32 *ids; + __u32 i, j; + +- if (!args->owner || args->pad) ++ if (!args->owner) + return -EINVAL; + + if (args->count > NTSYNC_MAX_WAIT_COUNT) +@@ -860,7 +861,11 @@ static int setup_wait(struct ntsync_device *dev, + timeout = timespec64_to_ns(&to); + } + +- ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL); ++ total_count = count; ++ if (args->alert) ++ total_count++; + -+ It is valid to pass the same object more than once. If a wakeup -+ occurs due to that object being signaled, ``index`` is set to the -+ lowest index corresponding to that object. ++ ids = kmalloc_array(total_count, sizeof(*ids), GFP_KERNEL); + if (!ids) + return -ENOMEM; + if (copy_from_user(ids, u64_to_user_ptr(args->objs), +@@ -868,8 +873,10 @@ static int setup_wait(struct ntsync_device *dev, + kfree(ids); + return -EFAULT; + } ++ if (args->alert) ++ ids[count] = args->alert; + +- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); ++ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL); + if (!q) { + kfree(ids); + return -ENOMEM; +@@ -881,7 +888,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, ids[i]); + +@@ -936,9 +943,9 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_wait_args args; + struct ntsync_q *q; ++ __u32 i, total_count; + ktime_t timeout; + int signaled; +- __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) +@@ -948,9 +955,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++; + -+ The function may fail with ``EINTR`` if a signal is received. + /* 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; + +@@ -959,9 +970,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) +@@ -978,7 +995,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; + +@@ -1038,6 +1055,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; + -+.. c:macro:: WINESYNC_IOC_WAIT_ALL ++ 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 */ + +@@ -1045,6 +1070,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. ++ */ + -+ Poll on a list of objects, atomically acquiring all of them. Takes a -+ pointer to struct :c:type:`winesync_wait_args`, which is used -+ identically to ``WINESYNC_IOC_WAIT_ANY``, except that ``index`` is -+ always filled with zero on success. ++ if (args.alert) { ++ struct ntsync_obj *obj = q->entries[args.count].obj; + -+ This function attempts to simultaneously acquire all of the given -+ objects. If unable to do so, it sleeps until all objects become -+ simultaneously signaled, subsequently acquiring them, or the timeout -+ expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and -+ no objects are modified. ++ if (atomic_read(&q->signaled) == -1) { ++ spin_lock(&obj->lock); ++ try_wake_any_obj(obj); ++ spin_unlock(&obj->lock); ++ } ++ } + -+ Objects may become signaled and subsequently designaled (through -+ acquisition by other threads) while this thread is sleeping. Only -+ once all objects are simultaneously signaled does the ioctl acquire -+ them and return. The entire acquisition is atomic and totally -+ ordered with respect to other operations on any of the given -+ objects. + /* sleep */ + + ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); +@@ -1067,6 +1107,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; + -+ If an inconsistent mutex is acquired, the ioctl fails with -+ ``EOWNERDEAD``. Similarly to ``WINESYNC_IOC_WAIT_ANY``, all objects -+ are nevertheless marked as acquired. Note that if multiple mutex -+ objects are specified, there is no way to know which were marked as -+ inconsistent. ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_del(&entry->node); ++ spin_unlock(&obj->lock); + -+ Unlike ``WINESYNC_IOC_WAIT_ANY``, it is not valid to pass the same -+ object more than once. If this is attempted, the function fails with -+ ``EINVAL``. ++ put_obj(obj); ++ } + + spin_unlock(&dev->wait_all_lock); + +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 86c28b909777..e145b36a15ea 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.36.0 +2.43.0 -From 622699b7dd8d5390dccdd9be1159e93dee6815ac Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 9208836580ed5e5aadfdfaf59dc8352ff6c4a07c Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:06:23 -0600 -Subject: [PATCH 13/34] selftests: winesync: Add some tests for semaphore - state. +Subject: [PATCH 18/32] selftests: ntsync: Add some tests for semaphore state. --- tools/testing/selftests/Makefile | 1 + - .../selftests/drivers/winesync/Makefile | 8 + - .../testing/selftests/drivers/winesync/config | 1 + - .../selftests/drivers/winesync/winesync.c | 153 ++++++++++++++++++ + .../testing/selftests/drivers/ntsync/Makefile | 8 + + tools/testing/selftests/drivers/ntsync/config | 1 + + .../testing/selftests/drivers/ntsync/ntsync.c | 153 ++++++++++++++++++ 4 files changed, 163 insertions(+) - create mode 100644 tools/testing/selftests/drivers/winesync/Makefile - create mode 100644 tools/testing/selftests/drivers/winesync/config - create mode 100644 tools/testing/selftests/drivers/winesync/winesync.c + 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 8247a7c69..553c949dc 100644 +index 8247a7c69c36..40b7318a8e22 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile -@@ -18,6 +18,7 @@ TARGETS += drivers/dma-buf +@@ -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 -+TARGETS += drivers/winesync - TARGETS += dt - TARGETS += efivarfs - TARGETS += exec -diff --git a/tools/testing/selftests/drivers/winesync/Makefile b/tools/testing/selftests/drivers/winesync/Makefile +diff --git a/tools/testing/selftests/drivers/ntsync/Makefile b/tools/testing/selftests/drivers/ntsync/Makefile new file mode 100644 -index 000000000000..43b39fdeea10 +index 000000000000..a34da5ccacf0 --- /dev/null -+++ b/tools/testing/selftests/drivers/winesync/Makefile ++++ b/tools/testing/selftests/drivers/ntsync/Makefile @@ -0,0 +1,8 @@ +# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only -+TEST_GEN_PROGS := winesync ++TEST_GEN_PROGS := ntsync + +top_srcdir =../../../../.. +CFLAGS += -I$(top_srcdir)/usr/include +LDLIBS += -lpthread + +include ../../lib.mk -diff --git a/tools/testing/selftests/drivers/winesync/config b/tools/testing/selftests/drivers/winesync/config +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/winesync/config ++++ b/tools/testing/selftests/drivers/ntsync/config @@ -0,0 +1 @@ +CONFIG_WINESYNC=y -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c new file mode 100644 -index 000000000000..58ade297fef9 +index 000000000000..777c408e8f9e --- /dev/null -+++ b/tools/testing/selftests/drivers/winesync/winesync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Various unit tests for the "winesync" synchronization primitive driver. ++ * Various unit tests for the "ntsync" synchronization primitive driver. + * -+ * Copyright (C) 2021 Zebediah Figura ++ * Copyright (C) 2021-2022 Elizabeth Figura + */ + +#define _GNU_SOURCE @@ -2226,18 +2548,18 @@ index 000000000000..58ade297fef9 +#include <fcntl.h> +#include <time.h> +#include <pthread.h> -+#include <linux/winesync.h> ++#include <linux/ntsync.h> +#include "../../kselftest_harness.h" + +static int read_sem_state(int fd, __u32 sem, __u32 *count, __u32 *max) +{ -+ struct winesync_sem_args args; ++ struct ntsync_sem_args args; + int ret; + + args.sem = sem; + args.count = 0xdeadbeef; + args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_SEM, &args); + *count = args.count; + *max = args.max; + return ret; @@ -2254,12 +2576,12 @@ index 000000000000..58ade297fef9 + +static int put_sem(int fd, __u32 sem, __u32 *count) +{ -+ struct winesync_sem_args args; ++ struct ntsync_sem_args args; + int ret; + + args.sem = sem; + args.count = *count; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &args); + *count = args.count; + return ret; +} @@ -2267,7 +2589,7 @@ index 000000000000..58ade297fef9 +static int wait_any(int fd, __u32 count, const __u32 *objs, __u32 owner, + __u32 *index) +{ -+ struct winesync_wait_args args = {0}; ++ struct ntsync_wait_args args = {0}; + struct timespec timeout; + int ret; + @@ -2278,88 +2600,88 @@ index 000000000000..58ade297fef9 + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); + *index = args.index; + return ret; +} + +TEST(semaphore_state) +{ -+ struct winesync_sem_args sem_args; ++ struct ntsync_sem_args sem_args; + struct timespec timeout; -+ __u32 sem, count, index; ++ __u32 count, index; + int fd, ret; + + clock_gettime(CLOCK_MONOTONIC, &timeout); + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, sem_args.sem); -+ check_sem_state(fd, sem, 2, 2); ++ check_sem_state(fd, sem_args.sem, 2, 2); + + count = 0; -+ ret = put_sem(fd, sem, &count); ++ ret = put_sem(fd, sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(2, count); -+ check_sem_state(fd, sem, 2, 2); ++ check_sem_state(fd, sem_args.sem, 2, 2); + + count = 1; -+ ret = put_sem(fd, sem, &count); ++ ret = put_sem(fd, sem_args.sem, &count); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EOVERFLOW, errno); -+ check_sem_state(fd, sem, 2, 2); ++ check_sem_state(fd, sem_args.sem, 2, 2); + -+ ret = wait_any(fd, 1, &sem, 123, &index); ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, index); -+ check_sem_state(fd, sem, 1, 2); ++ check_sem_state(fd, sem_args.sem, 1, 2); + -+ ret = wait_any(fd, 1, &sem, 123, &index); ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, index); -+ check_sem_state(fd, sem, 0, 2); ++ check_sem_state(fd, sem_args.sem, 0, 2); + -+ ret = wait_any(fd, 1, &sem, 123, &index); ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + + count = 3; -+ ret = put_sem(fd, sem, &count); ++ ret = put_sem(fd, sem_args.sem, &count); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EOVERFLOW, errno); -+ check_sem_state(fd, sem, 0, 2); ++ check_sem_state(fd, sem_args.sem, 0, 2); + + count = 2; -+ ret = put_sem(fd, sem, &count); ++ ret = put_sem(fd, sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, count); -+ check_sem_state(fd, sem, 2, 2); ++ check_sem_state(fd, sem_args.sem, 2, 2); + -+ ret = wait_any(fd, 1, &sem, 123, &index); ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); + EXPECT_EQ(0, ret); -+ ret = wait_any(fd, 1, &sem, 123, &index); ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); + EXPECT_EQ(0, ret); + + count = 1; -+ ret = put_sem(fd, sem, &count); ++ ret = put_sem(fd, sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, count); -+ check_sem_state(fd, sem, 1, 2); ++ check_sem_state(fd, sem_args.sem, 1, 2); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); + + close(fd); @@ -2367,34 +2689,34 @@ index 000000000000..58ade297fef9 + +TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From c62acefda29b36849abde8134bf2a3fe8d893520 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 7f8e2b5dedf3fe0192bcf7924d651d33df8898a9 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:07:04 -0600 -Subject: [PATCH 14/34] selftests: winesync: Add some tests for mutex state. +Subject: [PATCH 19/32] selftests: ntsync: Add some tests for mutex state. --- - .../selftests/drivers/winesync/winesync.c | 188 ++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 58ade297fef9..801b776da5aa 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 777c408e8f9e..8390dbbb1dd5 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -49,6 +49,42 @@ static int put_sem(int fd, __u32 sem, __u32 *count) return ret; } +static int read_mutex_state(int fd, __u32 mutex, __u32 *count, __u32 *owner) +{ -+ struct winesync_mutex_args args; ++ struct ntsync_mutex_args args; + int ret; + + args.mutex = mutex; + args.count = 0xdeadbeef; + args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &args); + *count = args.count; + *owner = args.owner; + return ret; @@ -2411,13 +2733,13 @@ index 58ade297fef9..801b776da5aa 100644 + +static int put_mutex(int fd, __u32 mutex, __u32 owner, __u32 *count) +{ -+ struct winesync_mutex_args args; ++ struct ntsync_mutex_args args; + int ret; + + args.mutex = mutex; + args.owner = owner; + args.count = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_MUTEX, &args); + *count = args.count; + return ret; +} @@ -2431,32 +2753,32 @@ index 58ade297fef9..801b776da5aa 100644 +TEST(mutex_state) +{ -+ struct winesync_mutex_args mutex_args; ++ struct ntsync_mutex_args mutex_args; + __u32 mutex, owner, count, index; + struct timespec timeout; + int fd, ret; + + clock_gettime(CLOCK_MONOTONIC, &timeout); + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); + + mutex_args.owner = 123; + mutex_args.count = 0; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + mutex = mutex_args.mutex; @@ -2505,22 +2827,22 @@ index 58ade297fef9..801b776da5aa 100644 + EXPECT_EQ(ETIMEDOUT, errno); + + owner = 0; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + + owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(0, ret); + check_mutex_state(fd, mutex, 1, 456); + + owner = 456; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(0, ret); + + mutex_args.count = 0xdeadbeef; + mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EOWNERDEAD, errno); + EXPECT_EQ(0, mutex_args.count); @@ -2528,7 +2850,7 @@ index 58ade297fef9..801b776da5aa 100644 + + mutex_args.count = 0xdeadbeef; + mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EOWNERDEAD, errno); + EXPECT_EQ(0, mutex_args.count); @@ -2541,12 +2863,12 @@ index 58ade297fef9..801b776da5aa 100644 + check_mutex_state(fd, mutex, 1, 123); + + owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(0, ret); + + mutex_args.count = 0xdeadbeef; + mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EOWNERDEAD, errno); + EXPECT_EQ(0, mutex_args.count); @@ -2558,13 +2880,13 @@ index 58ade297fef9..801b776da5aa 100644 + EXPECT_EQ(0, index); + check_mutex_state(fd, mutex, 1, 123); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex); + EXPECT_EQ(0, ret); + + mutex_args.owner = 0; + mutex_args.count = 0; + mutex_args.mutex = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + mutex = mutex_args.mutex; @@ -2575,7 +2897,7 @@ index 58ade297fef9..801b776da5aa 100644 + EXPECT_EQ(0, index); + check_mutex_state(fd, mutex, 1, 123); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + close(fd); @@ -2583,51 +2905,51 @@ index 58ade297fef9..801b776da5aa 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From 540cefcfe255d0b4c7208ae57a43fe0f16ce2531 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 596798d186edb9ca00396222e9dc0c43fcb40548 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:07:45 -0600 -Subject: [PATCH 15/34] selftests: winesync: Add some tests for +Subject: [PATCH 20/32] selftests: ntsync: Add some tests for WINESYNC_IOC_WAIT_ANY. --- - .../selftests/drivers/winesync/winesync.c | 107 ++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 801b776da5aa..5903061d38b6 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 8390dbbb1dd5..8ae930e7a601 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -338,4 +338,111 @@ TEST(mutex_state) close(fd); } +TEST(test_wait_any) +{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; + __u32 objs[2], owner, index; + struct timespec timeout; + int fd, ret; + + clock_gettime(CLOCK_MONOTONIC, &timeout); + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + @@ -2653,7 +2975,7 @@ index 801b776da5aa..5903061d38b6 100644 + check_mutex_state(fd, mutex_args.mutex, 1, 123); + + sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + @@ -2674,7 +2996,7 @@ index 801b776da5aa..5903061d38b6 100644 + EXPECT_EQ(ETIMEDOUT, errno); + + owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(0, ret); + + ret = wait_any(fd, 2, objs, 456, &index); @@ -2688,7 +3010,7 @@ index 801b776da5aa..5903061d38b6 100644 + + /* test waiting on the same object twice */ + sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + @@ -2702,9 +3024,9 @@ index 801b776da5aa..5903061d38b6 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + close(fd); @@ -2712,22 +3034,22 @@ index 801b776da5aa..5903061d38b6 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From 17f55215ea56e925369e2eec7eaead604a273e34 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 4610258d640a5bd75b7482b92cb74c4ffba58b84 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:08:25 -0600 -Subject: [PATCH 16/34] selftests: winesync: Add some tests for +Subject: [PATCH 21/32] selftests: ntsync: Add some tests for WINESYNC_IOC_WAIT_ALL. --- - .../selftests/drivers/winesync/winesync.c | 104 +++++++++++++++++- + .../testing/selftests/drivers/ntsync/ntsync.c | 104 +++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 5903061d38b6..0718219f54bf 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 8ae930e7a601..586e798d3228 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -85,8 +85,8 @@ static int put_mutex(int fd, __u32 mutex, __u32 owner, __u32 *count) return ret; } @@ -2737,13 +3059,13 @@ index 5903061d38b6..0718219f54bf 100644 +static int wait_objs(int fd, unsigned long request, __u32 count, + const __u32 *objs, __u32 owner, __u32 *index) { - struct winesync_wait_args args = {0}; + struct ntsync_wait_args args = {0}; struct timespec timeout; @@ -99,11 +99,23 @@ static int wait_any(int fd, __u32 count, const __u32 *objs, __u32 owner, args.objs = (uintptr_t)objs; args.owner = owner; args.index = 0xdeadbeef; -- ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &args); +- ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); + ret = ioctl(fd, request, &args); *index = args.index; return ret; @@ -2752,43 +3074,43 @@ index 5903061d38b6..0718219f54bf 100644 +static int wait_any(int fd, __u32 count, const __u32 *objs, + __u32 owner, __u32 *index) +{ -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ANY, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); +} + +static int wait_all(int fd, __u32 count, const __u32 *objs, + __u32 owner, __u32 *index) +{ -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ALL, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); +} + TEST(semaphore_state) { - struct winesync_sem_args sem_args; + struct ntsync_sem_args sem_args; @@ -445,4 +457,90 @@ TEST(test_wait_any) close(fd); } +TEST(test_wait_all) +{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_sem_args sem_args = {0}; ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; + __u32 objs[2], owner, index; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + @@ -2820,7 +3142,7 @@ index 5903061d38b6..0718219f54bf 100644 + check_mutex_state(fd, mutex_args.mutex, 2, 123); + + sem_args.count = 3; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + @@ -2831,7 +3153,7 @@ index 5903061d38b6..0718219f54bf 100644 + check_mutex_state(fd, mutex_args.mutex, 3, 123); + + owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); ++ ret = ioctl(fd, NTSYNC_IOC_KILL_OWNER, &owner); + EXPECT_EQ(0, ret); + + ret = wait_all(fd, 2, objs, 123, &index); @@ -2846,9 +3168,9 @@ index 5903061d38b6..0718219f54bf 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + close(fd); @@ -2856,114 +3178,114 @@ index 5903061d38b6..0718219f54bf 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From 6d07a2265d06d3f0af6fe2d9874762fb2e922488 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From a18ca868f284f8eec745aec2346b2ff138370473 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:08:54 -0600 -Subject: [PATCH 17/34] selftests: winesync: Add some tests for invalid object +Subject: [PATCH 22/32] selftests: ntsync: Add some tests for invalid object handling. --- - .../selftests/drivers/winesync/winesync.c | 93 +++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 0718219f54bf..8a9fb496f5e0 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 586e798d3228..ac24a94f2518 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -543,4 +543,97 @@ TEST(test_wait_all) close(fd); } +TEST(invalid_objects) +{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; + __u32 objs[2] = {0}; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); + -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_SEM, &sem_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + + wait_args.objs = (uintptr_t)objs; + wait_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ALL, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[0]); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &objs[0]); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + + sem_args.max = 1; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); + EXPECT_EQ(0, ret); + + mutex_args.mutex = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_MUTEX, &mutex_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + + objs[0] = sem_args.sem; + objs[1] = sem_args.sem + 1; + wait_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ALL, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + + objs[0] = sem_args.sem + 1; + objs[1] = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ALL, &wait_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + + sem_args.sem = mutex_args.mutex; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_SEM, &sem_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + close(fd); @@ -2971,22 +3293,22 @@ index 0718219f54bf..8a9fb496f5e0 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From fafaf63d58b1f8ae3644ec5850c170bce6f6b5d2 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From e49d10455ebe2a5d056523a225b8b179b1da932a Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:09:32 -0600 -Subject: [PATCH 18/34] selftests: winesync: Add some tests for wakeup - signaling with WINESYNC_IOC_WAIT_ANY. +Subject: [PATCH 23/32] selftests: ntsync: Add some tests for wakeup signaling + with WINESYNC_IOC_WAIT_ANY. --- - .../selftests/drivers/winesync/winesync.c | 154 ++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 8a9fb496f5e0..04855df00894 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index ac24a94f2518..919cabc3ba5e 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -636,4 +636,158 @@ TEST(invalid_objects) close(fd); } @@ -3001,7 +3323,7 @@ index 8a9fb496f5e0..04855df00894 100644 +{ + int fd; + unsigned long request; -+ struct winesync_wait_args *args; ++ struct ntsync_wait_args *args; + int ret; + int err; +}; @@ -3033,29 +3355,29 @@ index 8a9fb496f5e0..04855df00894 100644 + +TEST(wake_any) +{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_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 objs[2], count, index; + struct timespec timeout; + pthread_t thread; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + @@ -3072,7 +3394,7 @@ index 8a9fb496f5e0..04855df00894 100644 + wait_args.index = 0xdeadbeef; + thread_args.fd = fd; + thread_args.args = &wait_args; -+ thread_args.request = WINESYNC_IOC_WAIT_ANY; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; + ret = pthread_create(&thread, NULL, wait_thread, &thread_args); + EXPECT_EQ(0, ret); + @@ -3080,7 +3402,7 @@ index 8a9fb496f5e0..04855df00894 100644 + EXPECT_EQ(ETIMEDOUT, ret); + + sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + check_sem_state(fd, sem_args.sem, 0, 3); @@ -3132,9 +3454,9 @@ index 8a9fb496f5e0..04855df00894 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + ret = wait_for_thread(thread, 200); @@ -3147,51 +3469,51 @@ index 8a9fb496f5e0..04855df00894 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From c1916abd720dc30c3dc1972fd9a4d69844e8ffbd Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From a9f683caedb447a30b28a3ebb3d8fc597fe26d73 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Fri, 5 Mar 2021 12:09:36 -0600 -Subject: [PATCH 19/34] selftests: winesync: Add some tests for wakeup - signaling with WINESYNC_IOC_WAIT_ALL. +Subject: [PATCH 24/32] selftests: ntsync: Add some tests for wakeup signaling + with WINESYNC_IOC_WAIT_ALL. --- - .../selftests/drivers/winesync/winesync.c | 102 ++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 04855df00894..ad6d0f9a2a35 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 919cabc3ba5e..3dbae7c8ac1f 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -790,4 +790,106 @@ TEST(wake_any) close(fd); } +TEST(wake_all) +{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_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 objs[2], count, index; + struct timespec timeout; + pthread_t thread; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + @@ -3205,7 +3527,7 @@ index 04855df00894..ad6d0f9a2a35 100644 + wait_args.owner = 456; + thread_args.fd = fd; + thread_args.args = &wait_args; -+ thread_args.request = WINESYNC_IOC_WAIT_ALL; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; + ret = pthread_create(&thread, NULL, wait_thread, &thread_args); + EXPECT_EQ(0, ret); + @@ -3213,7 +3535,7 @@ index 04855df00894..ad6d0f9a2a35 100644 + EXPECT_EQ(ETIMEDOUT, ret); + + sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + @@ -3236,7 +3558,7 @@ index 04855df00894..ad6d0f9a2a35 100644 + check_mutex_state(fd, mutex_args.mutex, 0, 0); + + sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, sem_args.count); + check_sem_state(fd, sem_args.sem, 1, 3); @@ -3256,9 +3578,9 @@ index 04855df00894..ad6d0f9a2a35 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &sem_args.sem); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); + EXPECT_EQ(0, ret); + + ret = wait_for_thread(thread, 200); @@ -3271,539 +3593,35 @@ index 04855df00894..ad6d0f9a2a35 100644 + TEST_HARNESS_MAIN -- -2.36.0 - -From 30ea479d690ddcc7eed1b580843f54ab7910d6bd Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Fri, 5 Mar 2021 12:22:55 -0600 -Subject: [PATCH 20/34] maintainers: Add an entry for winesync. - ---- - MAINTAINERS | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 72b9654f764c..ff31beb17835 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -23391,6 +23391,15 @@ - S: Maintained - F: drivers/media/rc/winbond-cir.c - -+WINESYNC SYNCHRONIZATION PRIMITIVE DRIVER -+M: Zebediah Figura <zfigura@codeweavers.com> -+L: wine-devel@winehq.org -+S: Supported -+F: Documentation/userspace-api/winesync.rst -+F: drivers/misc/winesync.c -+F: include/uapi/linux/winesync.h -+F: tools/testing/selftests/drivers/winesync/ -+ - WINSYSTEMS EBC-C384 WATCHDOG DRIVER - L: linux-watchdog@vger.kernel.org - S: Orphan --- -2.37.3 - -From 4e6e34339182f13972e7b906c0bd0dde74eda3d7 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 18:21:03 -0600 -Subject: [PATCH 21/34] winesync: Introduce WINESYNC_IOC_CREATE_EVENT. - ---- - drivers/misc/winesync.c | 65 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 8 +++++ - 2 files changed, 73 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index eae272663abe..eaba41510784 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -17,6 +17,7 @@ - enum winesync_type { - WINESYNC_TYPE_SEM, - WINESYNC_TYPE_MUTEX, -+ WINESYNC_TYPE_EVENT, - }; - - struct winesync_obj { -@@ -66,6 +67,10 @@ struct winesync_obj { - __u32 owner; - bool ownerdead; - } mutex; -+ struct { -+ bool manual; -+ bool signaled; -+ } event; - } u; - }; - -@@ -199,6 +204,8 @@ static bool is_signaled(struct winesync_obj *obj, __u32 owner) - if (obj->u.mutex.owner && obj->u.mutex.owner != owner) - return false; - return obj->u.mutex.count < UINT_MAX; -+ case WINESYNC_TYPE_EVENT: -+ return obj->u.event.signaled; - } - - WARN(1, "bad object type %#x\n", obj->type); -@@ -248,6 +255,10 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, - obj->u.mutex.count++; - obj->u.mutex.owner = q->owner; - break; -+ case WINESYNC_TYPE_EVENT: -+ if (!obj->u.event.manual) -+ obj->u.event.signaled = false; -+ break; - } - } - wake_up_process(q->task); -@@ -315,6 +326,26 @@ static void try_wake_any_mutex(struct winesync_obj *mutex) - } - } - -+static void try_wake_any_event(struct winesync_obj *event) -+{ -+ struct winesync_q_entry *entry; -+ -+ lockdep_assert_held(&event->lock); -+ -+ list_for_each_entry(entry, &event->any_waiters, node) { -+ struct winesync_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); -+ } -+ } -+} -+ - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) - { - struct winesync_sem_args __user *user_args = argp; -@@ -379,6 +410,35 @@ static int winesync_create_mutex(struct winesync_device *dev, void __user *argp) - return put_user(id, &user_args->mutex); - } - -+static int winesync_create_event(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_event_args __user *user_args = argp; -+ struct winesync_event_args args; -+ struct winesync_obj *event; -+ __u32 id; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ event = kzalloc(sizeof(*event), GFP_KERNEL); -+ if (!event) -+ return -ENOMEM; -+ -+ init_obj(event); -+ event->type = WINESYNC_TYPE_EVENT; -+ event->u.event.manual = args.manual; -+ event->u.event.signaled = args.signaled; -+ -+ ret = xa_alloc(&dev->objects, &id, event, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { -+ kfree(event); -+ return ret; -+ } -+ -+ return put_user(id, &user_args->event); -+} -+ - static int winesync_delete(struct winesync_device *dev, void __user *argp) - { - struct winesync_obj *obj; -@@ -760,6 +820,9 @@ static void try_wake_any_obj(struct winesync_obj *obj) - case WINESYNC_TYPE_MUTEX: - try_wake_any_mutex(obj); - break; -+ case WINESYNC_TYPE_EVENT: -+ try_wake_any_event(obj); -+ break; - } - } - -@@ -925,6 +988,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - void __user *argp = (void __user *)parm; - - switch (cmd) { -+ case WINESYNC_IOC_CREATE_EVENT: -+ return winesync_create_event(dev, argp); - case WINESYNC_IOC_CREATE_MUTEX: - return winesync_create_mutex(dev, argp); - case WINESYNC_IOC_CREATE_SEM: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 3371a303a927..3999407534e0 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -22,6 +22,12 @@ struct winesync_mutex_args { - __u32 count; - }; - -+struct winesync_event_args { -+ __u32 event; -+ __u32 manual; -+ __u32 signaled; -+}; -+ - struct winesync_wait_args { - __u64 timeout; - __u64 objs; -@@ -51,5 +57,7 @@ struct winesync_wait_args { - struct winesync_sem_args) - #define WINESYNC_IOC_READ_MUTEX _IOWR(WINESYNC_IOC_BASE, 9, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_CREATE_EVENT _IOWR(WINESYNC_IOC_BASE, 10, \ -+ struct winesync_event_args) - - #endif --- -2.36.0 +2.43.0 -From 92a843a6d77099e638d5513fb4093e42ba84a3a3 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 18:43:30 -0600 -Subject: [PATCH 22/34] winesync: Introduce WINESYNC_IOC_SET_EVENT. - ---- - drivers/misc/winesync.c | 45 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 47 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index eaba41510784..658ad7b80c29 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -704,6 +704,49 @@ static int winesync_kill_owner(struct winesync_device *dev, void __user *argp) - return 0; - } - -+static int winesync_set_event(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_event_args __user *user_args = argp; -+ struct winesync_event_args args; -+ struct winesync_obj *event; -+ bool prev_state; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ event = get_obj_typed(dev, args.event, WINESYNC_TYPE_EVENT); -+ if (!event) -+ return -EINVAL; -+ -+ if (atomic_read(&event->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock(&event->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); -+ } -+ -+ put_obj(event); -+ -+ if (put_user(prev_state, &user_args->signaled)) -+ return -EFAULT; -+ -+ return 0; -+} -+ - static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -1006,6 +1049,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_read_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: - return winesync_read_sem(dev, argp); -+ case WINESYNC_IOC_SET_EVENT: -+ return winesync_set_event(dev, argp); - case WINESYNC_IOC_WAIT_ALL: - return winesync_wait_all(dev, argp); - case WINESYNC_IOC_WAIT_ANY: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 3999407534e0..34cd65d879a8 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -59,5 +59,7 @@ struct winesync_wait_args { - struct winesync_mutex_args) - #define WINESYNC_IOC_CREATE_EVENT _IOWR(WINESYNC_IOC_BASE, 10, \ - struct winesync_event_args) -+#define WINESYNC_IOC_SET_EVENT _IOWR(WINESYNC_IOC_BASE, 11, \ -+ struct winesync_event_args) - - #endif --- -2.36.0 - -From 7abe646cd9c913b78156186e3a2d98715a0f3513 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 19:00:25 -0600 -Subject: [PATCH 23/34] winesync: Introduce WINESYNC_IOC_RESET_EVENT. - ---- - drivers/misc/winesync.c | 31 +++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 33 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 658ad7b80c29..a93f173127f4 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -747,6 +747,35 @@ static int winesync_set_event(struct winesync_device *dev, void __user *argp) - return 0; - } - -+static int winesync_reset_event(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_event_args __user *user_args = argp; -+ struct winesync_event_args args; -+ struct winesync_obj *event; -+ bool prev_state; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ event = get_obj_typed(dev, args.event, WINESYNC_TYPE_EVENT); -+ if (!event) -+ return -EINVAL; -+ -+ spin_lock(&event->lock); -+ -+ prev_state = event->u.event.signaled; -+ event->u.event.signaled = false; -+ -+ spin_unlock(&event->lock); -+ -+ put_obj(event); -+ -+ if (put_user(prev_state, &user_args->signaled)) -+ return -EFAULT; -+ -+ return 0; -+} -+ - static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -1049,6 +1078,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_read_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: - return winesync_read_sem(dev, argp); -+ case WINESYNC_IOC_RESET_EVENT: -+ return winesync_reset_event(dev, argp); - case WINESYNC_IOC_SET_EVENT: - return winesync_set_event(dev, argp); - case WINESYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 34cd65d879a8..e71271fc44ba 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -61,5 +61,7 @@ struct winesync_wait_args { - struct winesync_event_args) - #define WINESYNC_IOC_SET_EVENT _IOWR(WINESYNC_IOC_BASE, 11, \ - struct winesync_event_args) -+#define WINESYNC_IOC_RESET_EVENT _IOWR(WINESYNC_IOC_BASE, 12, \ -+ struct winesync_event_args) - - #endif --- -2.36.0 - -From 3ea6a631230c7b17d345e2249f5f72ad24c46a79 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 19:10:12 -0600 -Subject: [PATCH 24/34] winesync: Introduce WINESYNC_IOC_PULSE_EVENT. - ---- - drivers/misc/winesync.c | 11 +++++++++-- - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index a93f173127f4..27d5baa457df 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -704,7 +704,8 @@ static int winesync_kill_owner(struct winesync_device *dev, void __user *argp) - return 0; - } - --static int winesync_set_event(struct winesync_device *dev, void __user *argp) -+static int winesync_set_event(struct winesync_device *dev, void __user *argp, -+ bool pulse) - { - struct winesync_event_args __user *user_args = argp; - struct winesync_event_args args; -@@ -726,6 +727,8 @@ static int winesync_set_event(struct winesync_device *dev, 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); -@@ -735,6 +738,8 @@ static int winesync_set_event(struct winesync_device *dev, 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); - } -@@ -1070,6 +1075,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_delete(dev, argp); - case WINESYNC_IOC_KILL_OWNER: - return winesync_kill_owner(dev, argp); -+ case WINESYNC_IOC_PULSE_EVENT: -+ return winesync_set_event(dev, argp, true); - case WINESYNC_IOC_PUT_MUTEX: - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: -@@ -1081,7 +1088,7 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - case WINESYNC_IOC_RESET_EVENT: - return winesync_reset_event(dev, argp); - case WINESYNC_IOC_SET_EVENT: -- return winesync_set_event(dev, argp); -+ return winesync_set_event(dev, argp, false); - case WINESYNC_IOC_WAIT_ALL: - return winesync_wait_all(dev, argp); - case WINESYNC_IOC_WAIT_ANY: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index e71271fc44ba..7c09d0e9733c 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -63,5 +63,7 @@ struct winesync_wait_args { - struct winesync_event_args) - #define WINESYNC_IOC_RESET_EVENT _IOWR(WINESYNC_IOC_BASE, 12, \ - struct winesync_event_args) -+#define WINESYNC_IOC_PULSE_EVENT _IOWR(WINESYNC_IOC_BASE, 13, \ -+ struct winesync_event_args) - - #endif --- -2.36.0 - -From 0fb972bb73385f9140f81a5f976b95ba750b73dd Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 19:14:00 -0600 -Subject: [PATCH 25/34] winesync: Introduce WINESYNC_IOC_READ_EVENT. - ---- - drivers/misc/winesync.c | 30 ++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 32 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 27d5baa457df..0f8a8a94eef8 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -639,6 +639,33 @@ static int winesync_read_mutex(struct winesync_device *dev, void __user *argp) - return ret; - } - -+static int winesync_read_event(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_event_args __user *user_args = argp; -+ struct winesync_event_args args; -+ struct winesync_obj *event; -+ __u32 id; -+ -+ if (get_user(id, &user_args->event)) -+ return -EFAULT; -+ -+ event = get_obj_typed(dev, id, WINESYNC_TYPE_EVENT); -+ if (!event) -+ return -EINVAL; -+ -+ args.event = id; -+ spin_lock(&event->lock); -+ args.manual = event->u.event.manual; -+ args.signaled = event->u.event.signaled; -+ spin_unlock(&event->lock); -+ -+ put_obj(event); -+ -+ if (copy_to_user(user_args, &args, sizeof(args))) -+ return -EFAULT; -+ return 0; -+} -+ - /* - * Actually change the mutex state to mark its owner as dead. - */ -@@ -1081,6 +1109,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_READ_EVENT: -+ return winesync_read_event(dev, argp); - case WINESYNC_IOC_READ_MUTEX: - return winesync_read_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 7c09d0e9733c..fb3788339ffe 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -65,5 +65,7 @@ struct winesync_wait_args { - struct winesync_event_args) - #define WINESYNC_IOC_PULSE_EVENT _IOWR(WINESYNC_IOC_BASE, 13, \ - struct winesync_event_args) -+#define WINESYNC_IOC_READ_EVENT _IOWR(WINESYNC_IOC_BASE, 14, \ -+ struct winesync_event_args) - - #endif --- -2.36.0 - -From ae7648556c522595d288bc169bde503140a59db0 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From f56885c1a183947d3b1f5e11a80ce23c7f150e33 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 19 Jan 2022 19:34:47 -0600 -Subject: [PATCH 26/34] selftests: winesync: Add some tests for manual-reset +Subject: [PATCH 25/32] selftests: ntsync: Add some tests for manual-reset event state. --- - .../selftests/drivers/winesync/winesync.c | 92 +++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index ad6d0f9a2a35..7e99f09b113b 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 3dbae7c8ac1f..cbe4ed73ffb9 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -85,6 +85,30 @@ static int put_mutex(int fd, __u32 mutex, __u32 owner, __u32 *count) return ret; } +static int read_event_state(int fd, __u32 event, __u32 *signaled, __u32 *manual) +{ -+ struct winesync_event_args args; ++ struct ntsync_event_args args; + int ret; + + args.event = event; + args.signaled = 0xdeadbeef; + args.manual = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_EVENT, &args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_EVENT, &args); + *signaled = args.signaled; + *manual = args.manual; + return ret; @@ -3828,28 +3646,28 @@ index ad6d0f9a2a35..7e99f09b113b 100644 +TEST(manual_event_state) +{ -+ struct winesync_event_args event_args; ++ struct ntsync_event_args event_args; + __u32 index; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, event_args.event); + check_event_state(fd, event_args.event, 0, 1); + + event_args.signaled = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 1, 1); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + check_event_state(fd, event_args.event, 1, 1); @@ -3860,12 +3678,12 @@ index ad6d0f9a2a35..7e99f09b113b 100644 + check_event_state(fd, event_args.event, 1, 1); + + event_args.signaled = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + check_event_state(fd, event_args.event, 0, 1); + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 1); @@ -3874,21 +3692,21 @@ index ad6d0f9a2a35..7e99f09b113b 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + check_event_state(fd, event_args.event, 0, 1); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 1); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + + close(fd); @@ -3896,48 +3714,48 @@ index ad6d0f9a2a35..7e99f09b113b 100644 + TEST(test_wait_any) { - struct winesync_mutex_args mutex_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; -- -2.36.0 +2.43.0 -From 5eeeb415ccc7e046fc71f20345bf8be20edfc1c4 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From d1e2db12a317942c72505085459dad6d64c8926a Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 19 Jan 2022 19:45:39 -0600 -Subject: [PATCH 27/34] selftests: winesync: Add some tests for auto-reset - event state. +Subject: [PATCH 26/32] selftests: ntsync: Add some tests for auto-reset event + state. --- - .../selftests/drivers/winesync/winesync.c | 59 +++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 7e99f09b113b..3a9ac69308af 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index cbe4ed73ffb9..c158c15fc03e 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 winesync_event_args event_args; ++ struct ntsync_event_args event_args; + __u32 index; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, event_args.event); + + check_event_state(fd, event_args.event, 1, 0); + + event_args.signaled = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + check_event_state(fd, event_args.event, 1, 0); @@ -3948,7 +3766,7 @@ index 7e99f09b113b..3a9ac69308af 100644 + check_event_state(fd, event_args.event, 0, 0); + + event_args.signaled = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 0); @@ -3957,21 +3775,21 @@ index 7e99f09b113b..3a9ac69308af 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + check_event_state(fd, event_args.event, 0, 0); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 0); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + + close(fd); @@ -3979,31 +3797,31 @@ index 7e99f09b113b..3a9ac69308af 100644 + TEST(test_wait_any) { - struct winesync_mutex_args mutex_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; -- -2.36.0 +2.43.0 -From 6857a39cd264169494908abf8564ac7161773203 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 011b5115949be3b87e3009ea5e4ede6708cf3ece Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 19 Jan 2022 21:00:50 -0600 -Subject: [PATCH 28/34] selftests: winesync: Add some tests for wakeup - signaling with events. +Subject: [PATCH 27/32] selftests: ntsync: Add some tests for wakeup signaling + with events. --- - .../selftests/drivers/winesync/winesync.c | 152 +++++++++++++++++- + .../testing/selftests/drivers/ntsync/ntsync.c | 152 +++++++++++++++++- 1 file changed, 150 insertions(+), 2 deletions(-) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 3a9ac69308af..2ccc51510230 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index c158c15fc03e..8f07577cf156 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -610,6 +610,7 @@ TEST(test_wait_any) TEST(test_wait_all) { -+ struct winesync_event_args event_args = {0}; - struct winesync_mutex_args mutex_args = {0}; - struct winesync_sem_args sem_args = {0}; ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_sem_args sem_args = {0}; __u32 objs[2], owner, index; @@ -632,6 +633,11 @@ TEST(test_wait_all) EXPECT_EQ(0, ret); @@ -4011,7 +3829,7 @@ index 3a9ac69308af..2ccc51510230 100644 + event_args.manual = true; + event_args.signaled = true; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + objs[0] = sem_args.sem; @@ -4034,9 +3852,9 @@ index 3a9ac69308af..2ccc51510230 100644 ret = wait_all(fd, 2, objs, 123, &index); @@ -690,6 +704,8 @@ TEST(test_wait_all) EXPECT_EQ(0, ret); - ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); + ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); close(fd); @@ -4045,10 +3863,10 @@ index 3a9ac69308af..2ccc51510230 100644 TEST(wake_any) { -+ struct winesync_event_args event_args = {0}; - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; ++ 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}; @@ -918,10 +935,103 @@ TEST(wake_any) EXPECT_EQ(0, thread_args.ret); EXPECT_EQ(1, wait_args.index); @@ -4057,7 +3875,7 @@ index 3a9ac69308af..2ccc51510230 100644 + + event_args.manual = false; + event_args.signaled = false; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + + objs[1] = event_args.event; @@ -4068,7 +3886,7 @@ index 3a9ac69308af..2ccc51510230 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 0); @@ -4085,7 +3903,7 @@ index 3a9ac69308af..2ccc51510230 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 0); @@ -4095,12 +3913,12 @@ index 3a9ac69308af..2ccc51510230 100644 + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + + event_args.manual = true; + event_args.signaled = false; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + + objs[1] = event_args.event; @@ -4111,7 +3929,7 @@ index 3a9ac69308af..2ccc51510230 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 1, 1); @@ -4121,7 +3939,7 @@ index 3a9ac69308af..2ccc51510230 100644 + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, event_args.signaled); + @@ -4132,7 +3950,7 @@ index 3a9ac69308af..2ccc51510230 100644 + ret = wait_for_thread(thread, 100); + EXPECT_EQ(ETIMEDOUT, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, event_args.signaled); + check_event_state(fd, event_args.event, 0, 1); @@ -4142,7 +3960,7 @@ index 3a9ac69308af..2ccc51510230 100644 + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + /* delete an object while it's being waited on */ @@ -4157,11 +3975,11 @@ index 3a9ac69308af..2ccc51510230 100644 TEST(wake_all) { -+ struct winesync_event_args manual_event_args = {0}; -+ struct winesync_event_args auto_event_args = {0}; - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; ++ 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; - __u32 objs[2], count, index; + __u32 objs[4], count, index; @@ -4174,12 +3992,12 @@ index 3a9ac69308af..2ccc51510230 100644 + manual_event_args.manual = true; + manual_event_args.signaled = true; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &manual_event_args); ++ 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, WINESYNC_IOC_CREATE_EVENT, &auto_event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args); + EXPECT_EQ(0, ret); + objs[0] = sem_args.sem; @@ -4199,25 +4017,25 @@ index 3a9ac69308af..2ccc51510230 100644 check_mutex_state(fd, mutex_args.mutex, 0, 0); -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &manual_event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &manual_event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, manual_event_args.signaled); + sem_args.count = 2; - ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); + ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); EXPECT_EQ(0, ret); EXPECT_EQ(0, sem_args.count); + check_sem_state(fd, sem_args.sem, 2, 3); + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &auto_event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &auto_event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, auto_event_args.signaled); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &manual_event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &manual_event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, manual_event_args.signaled); + -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &auto_event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &auto_event_args); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, auto_event_args.signaled); + @@ -4230,81 +4048,81 @@ index 3a9ac69308af..2ccc51510230 100644 EXPECT_EQ(0, ret); @@ -1034,6 +1178,10 @@ TEST(wake_all) EXPECT_EQ(0, ret); - ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); + ret = ioctl(fd, NTSYNC_IOC_DELETE, &mutex_args.mutex); EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &manual_event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &manual_event_args.event); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &auto_event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &auto_event_args.event); + EXPECT_EQ(0, ret); ret = wait_for_thread(thread, 200); EXPECT_EQ(0, ret); -- -2.36.0 +2.43.0 -From 8d2d3a310b90252903cc10e84e2bb1a06d7e8fac Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 74c862089a6975afeb0a11bfb6e1c632ae231419 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 19 Jan 2022 21:06:22 -0600 -Subject: [PATCH 29/34] selftests: winesync: Add some tests for invalid object +Subject: [PATCH 28/32] selftests: ntsync: Add some tests for invalid object handling with events. --- - .../selftests/drivers/winesync/winesync.c | 34 +++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 2ccc51510230..f2e18836c733 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 8f07577cf156..01bd034d4467 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -712,6 +712,7 @@ TEST(test_wait_all) TEST(invalid_objects) { -+ struct winesync_event_args event_args = {0}; - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; ++ 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}; @@ -737,6 +738,22 @@ TEST(invalid_objects) EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + wait_args.objs = (uintptr_t)objs; wait_args.count = 1; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); + ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &wait_args); @@ -763,6 +780,23 @@ TEST(invalid_objects) EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); + event_args.event = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_PULSE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_PULSE_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_READ_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_READ_EVENT, &event_args); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + @@ -4312,374 +4130,21 @@ index 2ccc51510230..f2e18836c733 100644 objs[1] = sem_args.sem + 1; wait_args.count = 2; -- -2.36.0 - -From 25270ec5877bcf2aa81fc4dd8326a4ee5af6e541 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 19 Jan 2022 22:01:46 -0600 -Subject: [PATCH 30/34] docs: winesync: Document event APIs. - ---- - Documentation/userspace-api/winesync.rst | 104 ++++++++++++++++++++++- - 1 file changed, 101 insertions(+), 3 deletions(-) - -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -index 34e54be229cf..ffa2f8fbc7e3 100644 ---- a/Documentation/userspace-api/winesync.rst -+++ b/Documentation/userspace-api/winesync.rst -@@ -18,8 +18,8 @@ interfaces such as futex(2) and poll(2). - Synchronization primitives - ========================== - --The winesync driver exposes two types of synchronization primitives, --semaphores and mutexes. -+The winesync driver exposes three types of synchronization primitives: -+semaphores, mutexes, and events. - - A semaphore holds a single volatile 32-bit counter, and a static - 32-bit integer denoting the maximum value. It is considered signaled -@@ -45,6 +45,12 @@ intended use is to store a thread identifier; however, the winesync - driver does not actually validate that a calling thread provides - consistent or unique identifiers. - -+An event holds a volatile boolean state denoting whether it is -+signaled or not. There are two types of events, auto-reset and -+manual-reset. An auto-reset event is designaled when a wait is -+satisfied; a manual-reset event is not. The event type is specified -+when the event is created. -+ - Unless specified otherwise, all operations on an object are atomic and - totally ordered with respect to other operations on the same object. - -@@ -78,6 +84,12 @@ structures used in ioctl calls:: - __u32 count; - }; - -+ struct winesync_event_args { -+ __u32 event; -+ __u32 signaled; -+ __u32 manual; -+ }; -+ - struct winesync_wait_args { - __u64 timeout; - __u64 objs; -@@ -125,6 +137,22 @@ The ioctls are as follows: - If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is - zero and ``count`` is nonzero, the function fails with ``EINVAL``. - -+.. c:macro:: WINESYNC_IOC_CREATE_EVENT -+ -+ Create an event object. Takes a pointer to struct -+ :c:type:`winesync_event_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``event`` -+ - On output, contains the identifier of the created event. -+ * - ``signaled`` -+ - If nonzero, the event is initially signaled, otherwise -+ nonsignaled. -+ * - ``manual`` -+ - If nonzero, the event is a manual-reset event, otherwise -+ auto-reset. -+ - .. c:macro:: WINESYNC_IOC_DELETE - - Delete an object of any type. Takes an input-only pointer to a -@@ -178,6 +206,60 @@ The ioctls are as follows: - unowned and signaled, and eligible threads waiting on it will be - woken as appropriate. - -+.. c:macro:: WINESYNC_IOC_SET_EVENT -+ -+ Signal an event object. Takes a pointer to struct -+ :c:type:`winesync_event_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``event`` -+ - Event object to set. -+ * - ``signaled`` -+ - On output, contains the previous state of the event. -+ * - ``manual`` -+ - Unused. -+ -+ Eligible threads will be woken, and auto-reset events will be -+ designaled appropriately. -+ -+.. c:macro:: WINESYNC_IOC_RESET_EVENT -+ -+ Designal an event object. Takes a pointer to struct -+ :c:type:`winesync_event_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``event`` -+ - Event object to reset. -+ * - ``signaled`` -+ - On output, contains the previous state of the event. -+ * - ``manual`` -+ - Unused. -+ -+.. c:macro:: WINESYNC_IOC_PULSE_EVENT -+ -+ Wake threads waiting on an event object without leaving it in a -+ signaled state. Takes a pointer to struct -+ :c:type:`winesync_event_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``event`` -+ - Event object to pulse. -+ * - ``signaled`` -+ - On output, contains the previous state of the event. -+ * - ``manual`` -+ - Unused. -+ -+ A pulse operation can be thought of as a set followed by a reset, -+ performed as a single atomic operation. If two threads are waiting -+ on an auto-reset event which is pulsed, only one will be woken. If -+ two threads are waiting a manual-reset event which is pulsed, both -+ will be woken. However, in both cases, the event will be unsignaled -+ afterwards, and a simultaneous read operation will always report the -+ event as unsignaled. -+ - .. c:macro:: WINESYNC_IOC_READ_SEM - - Read the current state of a semaphore object. Takes a pointer to -@@ -211,6 +293,21 @@ The ioctls are as follows: - ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to - zero. - -+.. c:macro:: WINESYNC_IOC_READ_EVENT -+ -+ Read the current state of an event object. Takes a pointer to struct -+ :c:type:`winesync_event_args`, which is used as follows: -+ -+ .. list-table:: -+ -+ * - ``event`` -+ - Event object. -+ * - ``signaled`` -+ - On output, contains the current state of the event. -+ * - ``manual`` -+ - On output, contains 1 if the event is a manual-reset event, -+ and 0 otherwise. -+ - .. c:macro:: WINESYNC_IOC_KILL_OWNER - - Mark any mutexes owned by the given owner as unowned and -@@ -272,7 +369,8 @@ The ioctls are as follows: - considered to be signaled if it is unowned or if its owner matches - the ``owner`` argument, and is acquired by incrementing its - recursion count by one and setting its owner to the ``owner`` -- argument. -+ argument. An auto-reset event is acquired by designaling it; a -+ manual-reset event is not affected by acquisition. - - Acquisition is atomic and totally ordered with respect to other - operations on the same object. If two wait operations (with --- -2.36.0 - -From 80f5b4dfd947592ff89cb54a07ce9d1087c608d0 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 13 Apr 2022 20:02:39 -0500 -Subject: [PATCH 31/34] winesync: Introduce alertable waits. - ---- - drivers/misc/winesync.c | 68 ++++++++++++++++++++++++++++++----- - include/uapi/linux/winesync.h | 2 +- - 2 files changed, 60 insertions(+), 10 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 4fbf231a7909..7a28f58dbbf2 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -841,10 +841,11 @@ static int setup_wait(struct winesync_device *dev, - const __u32 count = args->count; - struct winesync_q *q; - ktime_t timeout = 0; -+ __u32 total_count; - __u32 *ids; - __u32 i, j; - -- if (!args->owner || args->pad) -+ if (!args->owner) - return -EINVAL; - - if (args->timeout) { -@@ -858,7 +859,11 @@ static int setup_wait(struct winesync_device *dev, - timeout = timespec64_to_ns(&to); - } - -- ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL); -+ total_count = count; -+ if (args->alert) -+ total_count++; -+ -+ ids = kmalloc_array(total_count, sizeof(*ids), GFP_KERNEL); - if (!ids) - return -ENOMEM; - if (copy_from_user(ids, u64_to_user_ptr(args->objs), -@@ -866,8 +871,10 @@ static int setup_wait(struct winesync_device *dev, - kfree(ids); - return -EFAULT; - } -+ if (args->alert) -+ ids[count] = args->alert; - -- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); -+ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL); - if (!q) { - kfree(ids); - return -ENOMEM; -@@ -879,7 +886,7 @@ static int setup_wait(struct winesync_device *dev, - q->ownerdead = false; - q->count = count; - -- for (i = 0; i < count; i++) { -+ for (i = 0; i < total_count; i++) { - struct winesync_q_entry *entry = &q->entries[i]; - struct winesync_obj *obj = get_obj(dev, ids[i]); - -@@ -934,9 +941,9 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - { - struct winesync_wait_args args; - struct winesync_q *q; -+ __u32 i, total_count; - ktime_t timeout; - int signaled; -- __u32 i; - int ret; - - if (copy_from_user(&args, argp, sizeof(args))) -@@ -946,9 +953,13 @@ static int winesync_wait_any(struct winesync_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 winesync_q_entry *entry = &q->entries[i]; - struct winesync_obj *obj = entry->obj; - -@@ -957,9 +968,15 @@ static int winesync_wait_any(struct winesync_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 winesync_obj *obj = q->entries[i].obj; - - if (atomic_read(&q->signaled) != -1) -@@ -976,7 +993,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - - /* and finally, unqueue */ - -- for (i = 0; i < args.count; i++) { -+ for (i = 0; i < total_count; i++) { - struct winesync_q_entry *entry = &q->entries[i]; - struct winesync_obj *obj = entry->obj; - -@@ -1036,6 +1053,14 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp) - */ - list_add_tail(&entry->node, &obj->all_waiters); - } -+ if (args.alert) { -+ struct winesync_q_entry *entry = &q->entries[args.count]; -+ struct winesync_obj *obj = entry->obj; -+ -+ spin_lock(&obj->lock); -+ list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); -+ } - - /* check if we are already signaled */ - -@@ -1043,6 +1068,21 @@ static int winesync_wait_all(struct winesync_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 winesync_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 = winesync_schedule(q, args.timeout ? &timeout : NULL); -@@ -1065,6 +1105,16 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp) - - put_obj(obj); - } -+ if (args.alert) { -+ struct winesync_q_entry *entry = &q->entries[args.count]; -+ struct winesync_obj *obj = entry->obj; -+ -+ spin_lock(&obj->lock); -+ list_del(&entry->node); -+ spin_unlock(&obj->lock); -+ -+ put_obj(obj); -+ } - - spin_unlock(&dev->wait_all_lock); - -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index fb3788339ffe..5b4e369f7469 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -34,7 +34,7 @@ struct winesync_wait_args { - __u32 count; - __u32 owner; - __u32 index; -- __u32 pad; -+ __u32 alert; - }; - - #define WINESYNC_IOC_BASE 0xf7 --- -2.37.3 +2.43.0 -From 127efad71a0702a68890097b114b3467c234259f Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 8550d7aec916d737b2e81f5916c25da69d0d3de0 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 20 Apr 2022 18:08:37 -0500 -Subject: [PATCH 32/34] selftests: winesync: Add tests for alertable waits. +Subject: [PATCH 29/32] selftests: ntsync: Add tests for alertable waits. --- - .../selftests/drivers/winesync/winesync.c | 191 +++++++++++++++++- - 1 file changed, 188 insertions(+), 3 deletions(-) + .../testing/selftests/drivers/ntsync/ntsync.c | 189 +++++++++++++++++- + 1 file changed, 186 insertions(+), 3 deletions(-) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index f2e18836c733..a87e3c48709b 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 01bd034d4467..a58387d6744b 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -110,7 +110,7 @@ static int read_event_state(int fd, __u32 event, __u32 *signaled, __u32 *manual) }) @@ -4687,7 +4152,7 @@ index f2e18836c733..a87e3c48709b 100644 - const __u32 *objs, __u32 owner, __u32 *index) + const __u32 *objs, __u32 owner, __u32 alert, __u32 *index) { - struct winesync_wait_args args = {0}; + struct ntsync_wait_args args = {0}; struct timespec timeout; @@ -123,6 +123,7 @@ static int wait_objs(int fd, unsigned long request, __u32 count, args.objs = (uintptr_t)objs; @@ -4697,56 +4162,54 @@ index f2e18836c733..a87e3c48709b 100644 ret = ioctl(fd, request, &args); *index = args.index; return ret; -@@ -131,13 +132,29 @@ static int wait_objs(int fd, unsigned long request, __u32 count, +@@ -131,13 +132,27 @@ static int wait_objs(int fd, unsigned long request, __u32 count, static int wait_any(int fd, __u32 count, const __u32 *objs, __u32 owner, __u32 *index) { -- return wait_objs(fd, WINESYNC_IOC_WAIT_ANY, count, objs, owner, index); -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ANY, -+ count, objs, owner, 0, 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 __u32 *objs, __u32 owner, __u32 *index) { -- return wait_objs(fd, WINESYNC_IOC_WAIT_ALL, count, objs, owner, index); -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ALL, -+ count, objs, owner, 0, 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 __u32 *objs, + __u32 owner, __u32 alert, __u32 *index) +{ -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ANY, ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, + count, objs, owner, alert, index); +} + +static int wait_all_alert(int fd, __u32 count, const __u32 *objs, + __u32 owner, __u32 alert, __u32 *index) +{ -+ return wait_objs(fd, WINESYNC_IOC_WAIT_ALL, ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, + count, objs, owner, alert, index); } TEST(semaphore_state) -@@ -1225,4 +1242,172 @@ TEST(wake_all) +@@ -1225,4 +1240,172 @@ TEST(wake_all) close(fd); } +TEST(alert_any) +{ -+ struct winesync_event_args event_args = {0}; -+ struct winesync_sem_args sem_args = {0}; ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; + __u32 objs[2], index; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, sem_args.sem); + objs[0] = sem_args.sem; @@ -4754,28 +4217,28 @@ index f2e18836c733..a87e3c48709b 100644 + sem_args.count = 1; + sem_args.max = 2; + sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ 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(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + 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(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + + ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); @@ -4786,19 +4249,19 @@ index f2e18836c733..a87e3c48709b 100644 + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + + /* test with an auto-reset event */ + + event_args.manual = false; + event_args.signaled = true; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + + sem_args.sem = objs[0]; + sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + + ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); @@ -4813,12 +4276,12 @@ index f2e18836c733..a87e3c48709b 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[0]); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &objs[0]); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[1]); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &objs[1]); + EXPECT_EQ(0, ret); + + close(fd); @@ -4826,18 +4289,18 @@ index f2e18836c733..a87e3c48709b 100644 + +TEST(alert_all) +{ -+ struct winesync_event_args event_args = {0}; -+ struct winesync_sem_args sem_args = {0}; ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; + __u32 objs[2], index; + int fd, ret; + -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); ++ 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, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, sem_args.sem); + objs[0] = sem_args.sem; @@ -4845,14 +4308,14 @@ index f2e18836c733..a87e3c48709b 100644 + sem_args.count = 1; + sem_args.max = 2; + sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_SEM, &sem_args); ++ 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, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ 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); @@ -4863,19 +4326,19 @@ index f2e18836c733..a87e3c48709b 100644 + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + + /* test with an auto-reset event */ + + event_args.manual = false; + event_args.signaled = true; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); + EXPECT_EQ(0, ret); + + sem_args.sem = objs[1]; + sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); ++ ret = ioctl(fd, NTSYNC_IOC_PUT_SEM, &sem_args); + EXPECT_EQ(0, ret); + + ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); @@ -4890,12 +4353,12 @@ index f2e18836c733..a87e3c48709b 100644 + EXPECT_EQ(-1, ret); + EXPECT_EQ(ETIMEDOUT, errno); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); + EXPECT_EQ(0, ret); + -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[0]); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &objs[0]); + EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[1]); ++ ret = ioctl(fd, NTSYNC_IOC_DELETE, &objs[1]); + EXPECT_EQ(0, ret); + + close(fd); @@ -4903,42 +4366,42 @@ index f2e18836c733..a87e3c48709b 100644 + TEST_HARNESS_MAIN -- -2.36.0 +2.43.0 -From e5ec8276fae40b6a2cdab3cb728160705c0f40ab Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> +From 96d776b0b301b8a9f0b2fc27e62ff8b26e407072 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> Date: Wed, 20 Apr 2022 18:24:43 -0500 -Subject: [PATCH 33/34] serftests: winesync: Add some tests for wakeup - signaling via alerts. +Subject: [PATCH 30/32] selftests: ntsync: Add some tests for wakeup signaling + via alerts. --- - .../selftests/drivers/winesync/winesync.c | 66 +++++++++++++++++++ + .../testing/selftests/drivers/ntsync/ntsync.c | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index a87e3c48709b..169e922484b0 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -1245,8 +1245,12 @@ TEST(wake_all) +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index a58387d6744b..fda9f1c5e810 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -1243,8 +1243,12 @@ TEST(wake_all) TEST(alert_any) { - struct winesync_event_args event_args = {0}; -+ struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; + 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; + struct timespec timeout; __u32 objs[2], index; + pthread_t thread; int fd, ret; - fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -@@ -1295,6 +1299,35 @@ TEST(alert_any) + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -1293,6 +1297,35 @@ TEST(alert_any) EXPECT_EQ(0, ret); EXPECT_EQ(2, index); + /* test wakeup via alert */ + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + + get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); @@ -4950,14 +4413,14 @@ index a87e3c48709b..169e922484b0 100644 + wait_args.alert = event_args.event; + thread_args.fd = fd; + thread_args.args = &wait_args; -+ thread_args.request = WINESYNC_IOC_WAIT_ANY; ++ 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(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + + ret = wait_for_thread(thread, 100); @@ -4965,29 +4428,29 @@ index a87e3c48709b..169e922484b0 100644 + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(2, wait_args.index); + - ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); + ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); EXPECT_EQ(0, ret); -@@ -1336,8 +1369,12 @@ TEST(alert_any) +@@ -1334,8 +1367,12 @@ TEST(alert_any) TEST(alert_all) { - struct winesync_event_args event_args = {0}; -+ struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; + 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; + struct timespec timeout; __u32 objs[2], index; + pthread_t thread; int fd, ret; - fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -@@ -1372,6 +1409,35 @@ TEST(alert_all) + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -1370,6 +1407,35 @@ TEST(alert_all) EXPECT_EQ(0, ret); EXPECT_EQ(2, index); + /* test wakeup via alert */ + -+ ret = ioctl(fd, WINESYNC_IOC_RESET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_RESET_EVENT, &event_args); + EXPECT_EQ(0, ret); + + get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); @@ -4999,14 +4462,14 @@ index a87e3c48709b..169e922484b0 100644 + wait_args.alert = event_args.event; + thread_args.fd = fd; + thread_args.args = &wait_args; -+ thread_args.request = WINESYNC_IOC_WAIT_ALL; ++ 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(fd, WINESYNC_IOC_SET_EVENT, &event_args); ++ ret = ioctl(fd, NTSYNC_IOC_SET_EVENT, &event_args); + EXPECT_EQ(0, ret); + + ret = wait_for_thread(thread, 100); @@ -5014,32 +4477,431 @@ index a87e3c48709b..169e922484b0 100644 + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(2, wait_args.index); + - ret = ioctl(fd, WINESYNC_IOC_DELETE, &event_args.event); + ret = ioctl(fd, NTSYNC_IOC_DELETE, &event_args.event); EXPECT_EQ(0, ret); -- -2.36.0 +2.43.0 + +From 5ecf8efc0d4f019edcf4334b54314226bc30bd62 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura <zfigura@codeweavers.com> +Date: Fri, 5 Mar 2021 12:22:55 -0600 +Subject: [PATCH 31/32] maintainers: Add an entry for ntsync. + +--- + MAINTAINERS | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index a7c4cf8201e0..90e84b768c42 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15341,6 +15341,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 <zfigura@codeweavers.com> ++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 <fthain@linux-m68k.org> + L: linux-m68k@lists.linux-m68k.org +-- +2.43.0 -From 50ed00eef095c7799949b2523a5c21210b374f86 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Wed, 20 Apr 2022 18:58:17 -0500 -Subject: [PATCH 34/34] docs: winesync: Document alertable waits. +From e4db1ebaa7b9b150bcf54a4d57699e746b4d5b75 Mon Sep 17 00:00:00 2001 +From: Peter Jung <admin@ptr1337.dev> +Date: Wed, 24 Jan 2024 17:37:06 +0100 +Subject: [PATCH 32/32] docs: ntsync: Add documentation for the ntsync uAPI. +Signed-off-by: Peter Jung <admin@ptr1337.dev> --- - Documentation/userspace-api/winesync.rst | 40 ++++++++++++++++++------ - 1 file changed, 31 insertions(+), 9 deletions(-) + Documentation/userspace-api/index.rst | 1 + + Documentation/userspace-api/ntsync.rst | 445 +++++++++++++++++++++++++ + 2 files changed, 446 insertions(+) + create mode 100644 Documentation/userspace-api/ntsync.rst -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -index ffa2f8fbc7e3..f0110d2744c7 100644 ---- a/Documentation/userspace-api/winesync.rst -+++ b/Documentation/userspace-api/winesync.rst -@@ -354,9 +354,13 @@ The ioctls are as follows: - ``EINVAL``. - * - ``index`` - - On success, contains the index (into ``objs``) of the object -- which was signaled. -- * - ``pad`` -- - This field is not used and must be set to zero. +diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst +index 031df47a7c19..188bf15c4ecf 100644 +--- a/Documentation/userspace-api/index.rst ++++ b/Documentation/userspace-api/index.rst +@@ -33,6 +33,7 @@ place where this information is gathered. + sysfs-platform_profile + vduse + futex2 ++ ntsync + + .. only:: subproject and html + +diff --git a/Documentation/userspace-api/ntsync.rst b/Documentation/userspace-api/ntsync.rst +new file mode 100644 +index 000000000000..45d945b3e246 +--- /dev/null ++++ b/Documentation/userspace-api/ntsync.rst +@@ -0,0 +1,445 @@ ++=================================== ++NT synchronization primitive driver ++=================================== ++ ++This page documents the user-space API for the ntsync driver. ++ ++ntsync is a support driver for emulation of NT synchronization ++primitives by user-space NT emulators. It exists because implementation ++in user-space, using existing tools, cannot match Windows performance ++while offering accurate semantics. It is implemented entirely in ++software, and does not drive any hardware device. ++ ++This interface is meant as a compatibility tool only, and should not ++be used for general synchronization. Instead use generic, versatile ++interfaces such as futex(2) and poll(2). ++ ++Synchronization primitives ++========================== ++ ++The ntsync driver exposes three types of synchronization primitives: ++semaphores, mutexes, and events. ++ ++A semaphore holds a single volatile 32-bit counter, and a static ++32-bit integer denoting the maximum value. It is considered signaled ++when the counter is nonzero. The counter is decremented by one when a ++wait is satisfied. Both the initial and maximum count are established ++when the semaphore is created. ++ ++A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit ++identifier denoting its owner. A mutex is considered signaled when its ++owner is zero (indicating that it is not owned). The recursion count ++is incremented when a wait is satisfied, and ownership is set to the ++given identifier. ++ ++A mutex also holds an internal flag denoting whether its previous ++owner has died; such a mutex is said to be inconsistent. Owner death ++is not tracked automatically based on thread death, but rather must be ++communicated using ``NTSYNC_IOC_KILL_OWNER``. An inconsistent mutex ++is inherently considered unowned. ++ ++Except for the "unowned" semantics of zero, the actual value of the ++owner identifier is not interpreted by the ntsync driver at all. The ++intended use is to store a thread identifier; however, the ntsync ++driver does not actually validate that a calling thread provides ++consistent or unique identifiers. ++ ++An event holds a volatile boolean state denoting whether it is ++signaled or not. There are two types of events, auto-reset and ++manual-reset. An auto-reset event is designaled when a wait is ++satisfied; a manual-reset event is not. The event type is specified ++when the event is created. ++ ++Unless specified otherwise, all operations on an object are atomic and ++totally ordered with respect to other operations on the same object. ++ ++Objects are represented by unsigned 32-bit integers. ++ ++Char device ++=========== ++ ++The ntsync driver creates a single char device /dev/ntsync. Each ++file description opened on the device represents a unique namespace. ++That is, objects created on one open file description are shared ++across all its individual descriptors, but are not shared with other ++open() calls on the same device. The same file description may be ++shared across multiple processes. ++ ++ioctl reference ++=============== ++ ++All operations on the device are done through ioctls. There are four ++structures used in ioctl calls:: ++ ++ struct ntsync_sem_args { ++ __u32 sem; ++ __u32 count; ++ __u32 max; ++ }; ++ ++ struct ntsync_mutex_args { ++ __u32 mutex; ++ __u32 owner; ++ __u32 count; ++ }; ++ ++ struct ntsync_event_args { ++ __u32 event; ++ __u32 signaled; ++ __u32 manual; ++ }; ++ ++ struct ntsync_wait_args { ++ __u64 timeout; ++ __u64 objs; ++ __u32 count; ++ __u32 owner; ++ __u32 index; ++ __u32 alert; ++ }; ++ ++Depending on the ioctl, members of the structure may be used as input, ++output, or not at all. All ioctls return 0 on success. ++ ++The ioctls are as follows: ++ ++.. c:macro:: NTSYNC_IOC_CREATE_SEM ++ ++ Create a semaphore object. Takes a pointer to struct ++ :c:type:`ntsync_sem_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``sem`` ++ - On output, contains the identifier of the created semaphore. ++ * - ``count`` ++ - Initial count of the semaphore. ++ * - ``max`` ++ - Maximum count of the semaphore. ++ ++ Fails with ``EINVAL`` if ``count`` is greater than ``max``. ++ ++.. c:macro:: NTSYNC_IOC_CREATE_MUTEX ++ ++ Create a mutex object. Takes a pointer to struct ++ :c:type:`ntsync_mutex_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``mutex`` ++ - On output, contains the identifier of the created mutex. ++ * - ``count`` ++ - Initial recursion count of the mutex. ++ * - ``owner`` ++ - Initial owner of the mutex. ++ ++ If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is ++ zero and ``count`` is nonzero, the function fails with ``EINVAL``. ++ ++.. c:macro:: NTSYNC_IOC_CREATE_EVENT ++ ++ Create an event object. Takes a pointer to struct ++ :c:type:`ntsync_event_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``event`` ++ - On output, contains the identifier of the created event. ++ * - ``signaled`` ++ - If nonzero, the event is initially signaled, otherwise ++ nonsignaled. ++ * - ``manual`` ++ - If nonzero, the event is a manual-reset event, otherwise ++ auto-reset. ++ ++.. c:macro:: NTSYNC_IOC_DELETE ++ ++ Delete an object of any type. Takes an input-only pointer to a ++ 32-bit integer denoting the object to delete. ++ ++ Wait ioctls currently in progress are not interrupted, and behave as ++ if the object remains valid. ++ ++.. c:macro:: NTSYNC_IOC_PUT_SEM ++ ++ Post to a semaphore object. Takes a pointer to struct ++ :c:type:`ntsync_sem_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``sem`` ++ - Semaphore object to post to. ++ * - ``count`` ++ - Count to add to the semaphore. On output, contains the ++ previous count of the semaphore. ++ * - ``max`` ++ - Not used. ++ ++ If adding ``count`` to the semaphore's current count would raise the ++ latter past the semaphore's maximum count, the ioctl fails with ++ ``EOVERFLOW`` and the semaphore is not affected. If raising the ++ semaphore's count causes it to become signaled, eligible threads ++ waiting on this semaphore will be woken and the semaphore's count ++ decremented appropriately. ++ ++.. c:macro:: NTSYNC_IOC_PUT_MUTEX ++ ++ Release a mutex object. Takes a pointer to struct ++ :c:type:`ntsync_mutex_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``mutex`` ++ - Mutex object to release. ++ * - ``owner`` ++ - Mutex owner identifier. ++ * - ``count`` ++ - On output, contains the previous recursion count. ++ ++ If ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner`` ++ is not the current owner of the mutex, the ioctl fails with ++ ``EPERM``. ++ ++ The mutex's count will be decremented by one. If decrementing the ++ mutex's count causes it to become zero, the mutex is marked as ++ unowned and signaled, and eligible threads waiting on it will be ++ woken as appropriate. ++ ++.. c:macro:: NTSYNC_IOC_SET_EVENT ++ ++ Signal an event object. Takes a pointer to struct ++ :c:type:`ntsync_event_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``event`` ++ - Event object to set. ++ * - ``signaled`` ++ - On output, contains the previous state of the event. ++ * - ``manual`` ++ - Unused. ++ ++ Eligible threads will be woken, and auto-reset events will be ++ designaled appropriately. ++ ++.. c:macro:: NTSYNC_IOC_RESET_EVENT ++ ++ Designal an event object. Takes a pointer to struct ++ :c:type:`ntsync_event_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``event`` ++ - Event object to reset. ++ * - ``signaled`` ++ - On output, contains the previous state of the event. ++ * - ``manual`` ++ - Unused. ++ ++.. c:macro:: NTSYNC_IOC_PULSE_EVENT ++ ++ Wake threads waiting on an event object without leaving it in a ++ signaled state. Takes a pointer to struct ++ :c:type:`ntsync_event_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``event`` ++ - Event object to pulse. ++ * - ``signaled`` ++ - On output, contains the previous state of the event. ++ * - ``manual`` ++ - Unused. ++ ++ A pulse operation can be thought of as a set followed by a reset, ++ performed as a single atomic operation. If two threads are waiting ++ on an auto-reset event which is pulsed, only one will be woken. If ++ two threads are waiting a manual-reset event which is pulsed, both ++ will be woken. However, in both cases, the event will be unsignaled ++ afterwards, and a simultaneous read operation will always report the ++ event as unsignaled. ++ ++.. c:macro:: NTSYNC_IOC_READ_SEM ++ ++ Read the current state of a semaphore object. Takes a pointer to ++ struct :c:type:`ntsync_sem_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``sem`` ++ - Semaphore object to read. ++ * - ``count`` ++ - On output, contains the current count of the semaphore. ++ * - ``max`` ++ - On output, contains the maximum count of the semaphore. ++ ++.. c:macro:: NTSYNC_IOC_READ_MUTEX ++ ++ Read the current state of a mutex object. Takes a pointer to struct ++ :c:type:`ntsync_mutex_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``mutex`` ++ - Mutex object to read. ++ * - ``owner`` ++ - On output, contains the current owner of the mutex, or zero ++ if the mutex is not currently owned. ++ * - ``count`` ++ - On output, contains the current recursion count of the mutex. ++ ++ If the mutex is marked as inconsistent, the function fails with ++ ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to ++ zero. ++ ++.. c:macro:: NTSYNC_IOC_READ_EVENT ++ ++ Read the current state of an event object. Takes a pointer to struct ++ :c:type:`ntsync_event_args`, which is used as follows: ++ ++ .. list-table:: ++ ++ * - ``event`` ++ - Event object. ++ * - ``signaled`` ++ - On output, contains the current state of the event. ++ * - ``manual`` ++ - On output, contains 1 if the event is a manual-reset event, ++ and 0 otherwise. ++ ++.. c:macro:: NTSYNC_IOC_KILL_OWNER ++ ++ Mark any mutexes owned by the given owner as unowned and ++ inconsistent. Takes an input-only pointer to a 32-bit integer ++ denoting the owner. If the owner is zero, the ioctl fails with ++ ``EINVAL``. ++ ++ For each mutex currently owned by the given owner, eligible threads ++ waiting on said mutex will be woken as appropriate (and such waits ++ will fail with ``EOWNERDEAD``, as described below). ++ ++ The operation as a whole is not atomic; however, the modification of ++ each mutex is atomic and totally ordered with respect to other ++ operations on the same mutex. ++ ++.. c:macro:: NTSYNC_IOC_WAIT_ANY ++ ++ Poll on any of a list of objects, atomically acquiring at most one. ++ Takes a pointer to struct :c:type:`ntsync_wait_args`, which is ++ used as follows: ++ ++ .. list-table:: ++ ++ * - ``timeout`` ++ - Optional pointer to a 64-bit struct :c:type:`timespec` ++ (specified as an integer so that the structure has the same ++ size regardless of architecture). The timeout is specified in ++ absolute format, as measured against the MONOTONIC clock. If ++ the timeout is equal to or earlier than the current time, the ++ function returns immediately without sleeping. If ``timeout`` ++ is zero, i.e. NULL, the function will sleep until an object ++ is signaled, and will not fail with ``ETIMEDOUT``. ++ * - ``objs`` ++ - Pointer to an array of ``count`` 32-bit object identifiers ++ (specified as an integer so that the structure has the same ++ size regardless of architecture). If any identifier is ++ invalid, the function fails with ``EINVAL``. ++ * - ``count`` ++ - Number of object identifiers specified in the ``objs`` array. ++ If greater than ``NTSYNC_MAX_WAIT_COUNT``, the function fails ++ with ``EINVAL``. ++ * - ``owner`` ++ - Mutex owner identifier. If any object in ``objs`` is a mutex, ++ the ioctl will attempt to acquire that mutex on behalf of ++ ``owner``. If ``owner`` is zero, the ioctl fails with ++ ``EINVAL``. ++ * - ``index`` ++ - On success, contains the index (into ``objs``) of the object + which was signaled. If ``alert`` was signaled instead, + this contains ``count``. + * - ``alert`` @@ -5047,16 +4909,34 @@ index ffa2f8fbc7e3..f0110d2744c7 100644 + an "alert" event object which, if signaled, will terminate + the wait. If nonzero, the identifier must point to a valid + event. - - This function attempts to acquire one of the given objects. If - unable to do so, it sleeps until an object becomes signaled, -@@ -385,9 +389,19 @@ The ioctls are as follows: - the given owner (with a recursion count of 1) and as no longer - inconsistent, and ``index`` is still set to the index of the mutex. - -- It is valid to pass the same object more than once. If a wakeup -- occurs due to that object being signaled, ``index`` is set to the -- lowest index corresponding to that object. ++ ++ This function attempts to acquire one of the given objects. If ++ unable to do so, it sleeps until an object becomes signaled, ++ subsequently acquiring it, or the timeout expires. In the latter ++ case the ioctl fails with ``ETIMEDOUT``. The function only acquires ++ one object, even if multiple objects are signaled. ++ ++ A semaphore is considered to be signaled if its count is nonzero, ++ and is acquired by decrementing its count by one. A mutex is ++ considered to be signaled if it is unowned or if its owner matches ++ the ``owner`` argument, and is acquired by incrementing its ++ recursion count by one and setting its owner to the ``owner`` ++ argument. An auto-reset event is acquired by designaling it; a ++ manual-reset event is not affected by acquisition. ++ ++ Acquisition is atomic and totally ordered with respect to other ++ operations on the same object. If two wait operations (with ++ different ``owner`` identifiers) are queued on the same mutex, only ++ one is signaled. If two wait operations are queued on the same ++ semaphore, and a value of one is posted to it, only one is signaled. ++ The order in which threads are signaled is not specified. ++ ++ If an inconsistent mutex is acquired, the ioctl fails with ++ ``EOWNERDEAD``. Although this is a failure return, the function may ++ otherwise be considered successful. The mutex is marked as owned by ++ the given owner (with a recursion count of 1) and as no longer ++ inconsistent, and ``index`` is still set to the index of the mutex. ++ + The ``alert`` argument is an "extra" event which can terminate the + wait, independently of all other objects. If members of ``objs`` and + ``alert`` are both simultaneously signaled, a member of ``objs`` @@ -5070,22 +4950,35 @@ index ffa2f8fbc7e3..f0110d2744c7 100644 + passing the same event in the ``objs`` array and in ``alert``. If a + wakeup occurs due to that object being signaled, ``index`` is set to + the lowest index corresponding to that object. - - The function may fail with ``EINTR`` if a signal is received. - -@@ -396,7 +410,7 @@ The ioctls are as follows: - Poll on a list of objects, atomically acquiring all of them. Takes a - pointer to struct :c:type:`winesync_wait_args`, which is used - identically to ``WINESYNC_IOC_WAIT_ANY``, except that ``index`` is -- always filled with zero on success. ++ ++ The function may fail with ``EINTR`` if a signal is received. ++ ++.. c:macro:: NTSYNC_IOC_WAIT_ALL ++ ++ Poll on a list of objects, atomically acquiring all of them. Takes a ++ pointer to struct :c:type:`ntsync_wait_args`, which is used ++ identically to ``NTSYNC_IOC_WAIT_ANY``, except that ``index`` is + always filled with zero on success if not woken via alert. - - This function attempts to simultaneously acquire all of the given - objects. If unable to do so, it sleeps until all objects become -@@ -417,6 +431,14 @@ The ioctls are as follows: - objects are specified, there is no way to know which were marked as - inconsistent. - ++ ++ This function attempts to simultaneously acquire all of the given ++ objects. If unable to do so, it sleeps until all objects become ++ simultaneously signaled, subsequently acquiring them, or the timeout ++ expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and ++ no objects are modified. ++ ++ Objects may become signaled and subsequently designaled (through ++ acquisition by other threads) while this thread is sleeping. Only ++ once all objects are simultaneously signaled does the ioctl acquire ++ them and return. The entire acquisition is atomic and totally ++ ordered with respect to other operations on any of the given ++ objects. ++ ++ If an inconsistent mutex is acquired, the ioctl fails with ++ ``EOWNERDEAD``. Similarly to ``NTSYNC_IOC_WAIT_ANY``, all objects ++ are nevertheless marked as acquired. Note that if multiple mutex ++ objects are specified, there is no way to know which were marked as ++ inconsistent. ++ + As with "any" waits, the ``alert`` argument is an "extra" event + which can terminate the wait. Critically, however, an "all" wait + will succeed if all members in ``objs`` are signaled, *or* if @@ -5093,12 +4986,10 @@ index ffa2f8fbc7e3..f0110d2744c7 100644 + ``count``. As with "any" waits, if both conditions are filled, the + former takes priority, and objects in ``objs`` will be acquired. + - Unlike ``WINESYNC_IOC_WAIT_ANY``, it is not valid to pass the same -- object more than once. If this is attempted, the function fails with -- ``EINVAL``. ++ Unlike ``NTSYNC_IOC_WAIT_ANY``, it is not valid to pass the same + object more than once, nor is it valid to pass the same object in -+ ``objs`` and in ``alert`` If this is attempted, the function fails ++ ``objs`` and in ``alert``. If this is attempted, the function fails + with ``EINVAL``. -- -2.36.0 +2.43.0 diff --git a/SOURCES/kernel-aarch64-16k-debug-fedora.config b/SOURCES/kernel-aarch64-16k-debug-fedora.config index bd4f041..9ff368c 100644 --- a/SOURCES/kernel-aarch64-16k-debug-fedora.config +++ b/SOURCES/kernel-aarch64-16k-debug-fedora.config @@ -9956,7 +9956,7 @@ CONFIG_ZYNQMP_PM_DOMAINS=y CONFIG_ZYNQMP_POWER=y CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-16k-fedora.config b/SOURCES/kernel-aarch64-16k-fedora.config index ec61b3f..4a2d617 100644 --- a/SOURCES/kernel-aarch64-16k-fedora.config +++ b/SOURCES/kernel-aarch64-16k-fedora.config @@ -9927,7 +9927,7 @@ CONFIG_ZYNQMP_PM_DOMAINS=y CONFIG_ZYNQMP_POWER=y CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-64k-debug-rhel.config b/SOURCES/kernel-aarch64-64k-debug-rhel.config index 8b16e57..5350ae9 100644 --- a/SOURCES/kernel-aarch64-64k-debug-rhel.config +++ b/SOURCES/kernel-aarch64-64k-debug-rhel.config @@ -8044,7 +8044,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-64k-rhel.config b/SOURCES/kernel-aarch64-64k-rhel.config index 14aa64a..4186861 100644 --- a/SOURCES/kernel-aarch64-64k-rhel.config +++ b/SOURCES/kernel-aarch64-64k-rhel.config @@ -8019,7 +8019,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-debug-fedora.config b/SOURCES/kernel-aarch64-debug-fedora.config index 4eaf2fc..f94d35a 100644 --- a/SOURCES/kernel-aarch64-debug-fedora.config +++ b/SOURCES/kernel-aarch64-debug-fedora.config @@ -9956,7 +9956,7 @@ CONFIG_ZYNQMP_PM_DOMAINS=y CONFIG_ZYNQMP_POWER=y CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-debug-rhel.config b/SOURCES/kernel-aarch64-debug-rhel.config index bae5983..07cd10c 100644 --- a/SOURCES/kernel-aarch64-debug-rhel.config +++ b/SOURCES/kernel-aarch64-debug-rhel.config @@ -8040,7 +8040,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-fedora.config b/SOURCES/kernel-aarch64-fedora.config index 7eb940a..738e4be 100644 --- a/SOURCES/kernel-aarch64-fedora.config +++ b/SOURCES/kernel-aarch64-fedora.config @@ -9927,7 +9927,7 @@ CONFIG_ZYNQMP_PM_DOMAINS=y CONFIG_ZYNQMP_POWER=y CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-rhel.config b/SOURCES/kernel-aarch64-rhel.config index 723a6e3..8d41ffa 100644 --- a/SOURCES/kernel-aarch64-rhel.config +++ b/SOURCES/kernel-aarch64-rhel.config @@ -8015,7 +8015,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-rt-debug-rhel.config b/SOURCES/kernel-aarch64-rt-debug-rhel.config index 6802b3d..6ff8207 100644 --- a/SOURCES/kernel-aarch64-rt-debug-rhel.config +++ b/SOURCES/kernel-aarch64-rt-debug-rhel.config @@ -8100,7 +8100,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-aarch64-rt-rhel.config b/SOURCES/kernel-aarch64-rt-rhel.config index cb5df81..4f7912e 100644 --- a/SOURCES/kernel-aarch64-rt-rhel.config +++ b/SOURCES/kernel-aarch64-rt-rhel.config @@ -8075,7 +8075,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-ppc64le-debug-fedora.config b/SOURCES/kernel-ppc64le-debug-fedora.config index 7982fad..972cfc8 100644 --- a/SOURCES/kernel-ppc64le-debug-fedora.config +++ b/SOURCES/kernel-ppc64le-debug-fedora.config @@ -8263,7 +8263,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-ppc64le-debug-rhel.config b/SOURCES/kernel-ppc64le-debug-rhel.config index 7fde4dc..bb0d6df 100644 --- a/SOURCES/kernel-ppc64le-debug-rhel.config +++ b/SOURCES/kernel-ppc64le-debug-rhel.config @@ -7509,7 +7509,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-ppc64le-fedora.config b/SOURCES/kernel-ppc64le-fedora.config index 21b92d4..f3382b9 100644 --- a/SOURCES/kernel-ppc64le-fedora.config +++ b/SOURCES/kernel-ppc64le-fedora.config @@ -8232,7 +8232,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-ppc64le-rhel.config b/SOURCES/kernel-ppc64le-rhel.config index dfad115..dc57e1d 100644 --- a/SOURCES/kernel-ppc64le-rhel.config +++ b/SOURCES/kernel-ppc64le-rhel.config @@ -7486,7 +7486,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-s390x-debug-fedora.config b/SOURCES/kernel-s390x-debug-fedora.config index fe00aca..ea107d3 100644 --- a/SOURCES/kernel-s390x-debug-fedora.config +++ b/SOURCES/kernel-s390x-debug-fedora.config @@ -8199,7 +8199,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-s390x-debug-rhel.config b/SOURCES/kernel-s390x-debug-rhel.config index b563264..c0f9b83 100644 --- a/SOURCES/kernel-s390x-debug-rhel.config +++ b/SOURCES/kernel-s390x-debug-rhel.config @@ -7492,7 +7492,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-s390x-fedora.config b/SOURCES/kernel-s390x-fedora.config index 1507306..e61d28b 100644 --- a/SOURCES/kernel-s390x-fedora.config +++ b/SOURCES/kernel-s390x-fedora.config @@ -8168,7 +8168,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-s390x-rhel.config b/SOURCES/kernel-s390x-rhel.config index 6af13b4..654b6ca 100644 --- a/SOURCES/kernel-s390x-rhel.config +++ b/SOURCES/kernel-s390x-rhel.config @@ -7469,7 +7469,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-s390x-zfcpdump-rhel.config b/SOURCES/kernel-s390x-zfcpdump-rhel.config index aa058bb..6840b0a 100644 --- a/SOURCES/kernel-s390x-zfcpdump-rhel.config +++ b/SOURCES/kernel-s390x-zfcpdump-rhel.config @@ -7492,7 +7492,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-debug-fedora.config b/SOURCES/kernel-x86_64-debug-fedora.config index 1a2d8b0..c53228e 100644 --- a/SOURCES/kernel-x86_64-debug-fedora.config +++ b/SOURCES/kernel-x86_64-debug-fedora.config @@ -8847,7 +8847,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-debug-rhel.config b/SOURCES/kernel-x86_64-debug-rhel.config index a907156..3e6acda 100644 --- a/SOURCES/kernel-x86_64-debug-rhel.config +++ b/SOURCES/kernel-x86_64-debug-rhel.config @@ -7842,7 +7842,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-fedora.config b/SOURCES/kernel-x86_64-fedora.config index a1ba3a8..6b6f84a 100644 --- a/SOURCES/kernel-x86_64-fedora.config +++ b/SOURCES/kernel-x86_64-fedora.config @@ -8817,7 +8817,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-rhel.config b/SOURCES/kernel-x86_64-rhel.config index 1c6c754..60ae0b8 100644 --- a/SOURCES/kernel-x86_64-rhel.config +++ b/SOURCES/kernel-x86_64-rhel.config @@ -7818,7 +7818,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-rt-debug-rhel.config b/SOURCES/kernel-x86_64-rt-debug-rhel.config index cdf65b7..5f037bb 100644 --- a/SOURCES/kernel-x86_64-rt-debug-rhel.config +++ b/SOURCES/kernel-x86_64-rt-debug-rhel.config @@ -7903,7 +7903,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel-x86_64-rt-rhel.config b/SOURCES/kernel-x86_64-rt-rhel.config index 8f7d92f..2fcde56 100644 --- a/SOURCES/kernel-x86_64-rt-rhel.config +++ b/SOURCES/kernel-x86_64-rt-rhel.config @@ -7879,7 +7879,7 @@ CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y # CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set CONFIG_I2C_NCT6775=m CONFIG_ZENIFY=y -CONFIG_WINESYNC=y +CONFIG_NTSYNC=y CONFIG_USER_NS_UNPRIVILEGED=y CONFIG_TCP_CONG_BBR2=m CONFIG_HID_IPTS=m diff --git a/SOURCES/kernel.changelog b/SOURCES/kernel.changelog index 6cb5d52..c40dbe9 100644 --- a/SOURCES/kernel.changelog +++ b/SOURCES/kernel.changelog @@ -1,3 +1,8 @@ +* Fri Feb 23 2024 Justin M. Forbes <jforbes@fedoraproject.org> [6.7.6-0] +- Add CVE fix for 6.7.6 (Justin M. Forbes) +- Linux v6.7.6 +Resolves: + * Sat Feb 17 2024 Justin M. Forbes <jforbes@fedoraproject.org> [6.7.5-0] - Backported some CVE fixes lets note them in BugsFixed (Justin M. Forbes) - selftests: openvswitch: Add validation for the recursion test (Aaron Conole) diff --git a/SOURCES/patch-6.7-redhat.patch b/SOURCES/patch-6.7-redhat.patch index 8ba4339..0a7703b 100644 --- a/SOURCES/patch-6.7-redhat.patch +++ b/SOURCES/patch-6.7-redhat.patch @@ -16,23 +16,17 @@ drivers/firmware/sysfb.c | 18 ++- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 15 ++ - drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 +- - drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 9 +- + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 11 +- drivers/hid/hid-rmi.c | 66 -------- drivers/hwtracing/coresight/coresight-etm4x-core.c | 19 +++ drivers/input/keyboard/atkbd.c | 3 +- drivers/input/rmi4/rmi_driver.c | 124 +++++++++------ drivers/iommu/iommu.c | 22 +++ - drivers/md/dm-core.h | 2 + - drivers/md/dm-ioctl.c | 3 +- - drivers/md/dm-table.c | 9 +- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 + drivers/pci/quirks.c | 24 +++ drivers/platform/x86/thinkpad_acpi.c | 20 ++- drivers/scsi/sd.c | 10 ++ drivers/usb/core/hub.c | 7 + - fs/btrfs/transaction.c | 38 +---- - fs/smb/client/namespace.c | 16 ++ include/linux/efi.h | 22 ++- include/linux/lsm_hook_defs.h | 2 + include/linux/module.h | 1 + @@ -41,7 +35,6 @@ include/linux/security.h | 5 + kernel/module/main.c | 2 + kernel/module/signing.c | 9 +- - net/openvswitch/flow_netlink.c | 49 ++++-- scripts/mod/modpost.c | 8 + scripts/tags.sh | 2 + security/integrity/platform_certs/load_uefi.c | 6 +- @@ -51,7 +44,7 @@ tools/power/cpupower/Makefile | 2 +- .../selftests/net/openvswitch/openvswitch.sh | 13 ++ .../testing/selftests/net/openvswitch/ovs-dpctl.py | 71 +++++++-- - 53 files changed, 866 insertions(+), 253 deletions(-) + 46 files changed, 796 insertions(+), 196 deletions(-) diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index 98d304010170..7f674a6cfa8a 100644 @@ -79,7 +72,7 @@ index 98d304010170..7f674a6cfa8a 100644 0x1020 0x1F unknown diff --git a/Makefile b/Makefile -index 0f5bb9ddc98f..a46f4937fa26 100644 +index d07a8e0179ac..5779c09825d9 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,18 @@ $(if $(filter __%, $(MAKECMDGOALS)), \ @@ -660,7 +653,7 @@ index 2deebece810e..cc21ed67a330 100644 + #endif /* CONFIG_SUSPEND */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -index 5fe1df95dc38..7f48c7ec4136 100644 +index 19bc8d47317b..7f48c7ec4136 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4441,13 +4441,15 @@ int amdgpu_device_prepare(struct drm_device *dev) @@ -697,35 +690,6 @@ index 5fe1df95dc38..7f48c7ec4136 100644 } /** -@@ -4496,7 +4503,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) - drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); - - cancel_delayed_work_sync(&adev->delayed_init_work); -- flush_delayed_work(&adev->gfx.gfx_off_delay_work); - - amdgpu_ras_suspend(adev); - -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c -index b9674c57c436..6ddc8e3360e2 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c -@@ -723,8 +723,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) - - if (adev->gfx.gfx_off_req_count == 0 && - !adev->gfx.gfx_off_state) { -- schedule_delayed_work(&adev->gfx.gfx_off_delay_work, -+ /* If going to s2idle, no need to wait */ -+ if (adev->in_s0ix) { -+ if (!amdgpu_dpm_set_powergating_by_smu(adev, -+ AMD_IP_BLOCK_TYPE_GFX, true)) -+ adev->gfx.gfx_off_state = true; -+ } else { -+ schedule_delayed_work(&adev->gfx.gfx_off_delay_work, - delay); -+ } - } - } else { - if (adev->gfx.gfx_off_req_count == 0) { diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index d4af17fdba46..154f0403cbf4 100644 --- a/drivers/hid/hid-rmi.c @@ -1132,60 +1096,6 @@ index 33e2a9b5d339..6ae1abc3f11c 100644 /** * iommu_setup_default_domain - Set the default_domain for the group * @group: Group to change -diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h -index 095b9b49aa82..e6757a30dcca 100644 ---- a/drivers/md/dm-core.h -+++ b/drivers/md/dm-core.h -@@ -22,6 +22,8 @@ - #include "dm-ima.h" - - #define DM_RESERVED_MAX_IOS 1024 -+#define DM_MAX_TARGETS 1048576 -+#define DM_MAX_TARGET_PARAMS 1024 - - struct dm_io; - -diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c -index e65058e0ed06..3b1ad7127cb8 100644 ---- a/drivers/md/dm-ioctl.c -+++ b/drivers/md/dm-ioctl.c -@@ -1941,7 +1941,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern - minimum_data_size - sizeof(param_kernel->version))) - return -EFAULT; - -- if (param_kernel->data_size < minimum_data_size) { -+ if (unlikely(param_kernel->data_size < minimum_data_size) || -+ unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) { - DMERR("Invalid data size in the ioctl structure: %u", - param_kernel->data_size); - return -EINVAL; -diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c -index 198d38b53322..08c9c20f9c66 100644 ---- a/drivers/md/dm-table.c -+++ b/drivers/md/dm-table.c -@@ -129,7 +129,12 @@ static int alloc_targets(struct dm_table *t, unsigned int num) - int dm_table_create(struct dm_table **result, blk_mode_t mode, - unsigned int num_targets, struct mapped_device *md) - { -- struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL); -+ struct dm_table *t; -+ -+ if (num_targets > DM_MAX_TARGETS) -+ return -EOVERFLOW; -+ -+ t = kzalloc(sizeof(*t), GFP_KERNEL); - - if (!t) - return -ENOMEM; -@@ -144,7 +149,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode, - - if (!num_targets) { - kfree(t); -- return -ENOMEM; -+ return -EOVERFLOW; - } - - if (alloc_targets(t, num_targets)) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6b6aa3c36744..0ce08e9a0a3d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1310,10 +1220,10 @@ index 542a4bbb21bc..62161ceed2e2 100644 if (err) goto err_out_driver; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index ef8d9bda94ac..3fab06f3b43e 100644 +index 4854d883e601..e1ee781ca985 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5777,6 +5777,13 @@ static void hub_event(struct work_struct *work) +@@ -5795,6 +5795,13 @@ static void hub_event(struct work_struct *work) (u16) hub->change_bits[0], (u16) hub->event_bits[0]); @@ -1327,103 +1237,6 @@ index ef8d9bda94ac..3fab06f3b43e 100644 /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ usb_lock_device(hdev); -diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c -index 5b3333ceef04..c52807d97efa 100644 ---- a/fs/btrfs/transaction.c -+++ b/fs/btrfs/transaction.c -@@ -564,56 +564,22 @@ static int btrfs_reserve_trans_metadata(struct btrfs_fs_info *fs_info, - u64 num_bytes, - u64 *delayed_refs_bytes) - { -- struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv; - struct btrfs_space_info *si = fs_info->trans_block_rsv.space_info; -- u64 extra_delayed_refs_bytes = 0; -- u64 bytes; -+ u64 bytes = num_bytes + *delayed_refs_bytes; - int ret; - -- /* -- * If there's a gap between the size of the delayed refs reserve and -- * its reserved space, than some tasks have added delayed refs or bumped -- * its size otherwise (due to block group creation or removal, or block -- * group item update). Also try to allocate that gap in order to prevent -- * using (and possibly abusing) the global reserve when committing the -- * transaction. -- */ -- if (flush == BTRFS_RESERVE_FLUSH_ALL && -- !btrfs_block_rsv_full(delayed_refs_rsv)) { -- spin_lock(&delayed_refs_rsv->lock); -- if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) -- extra_delayed_refs_bytes = delayed_refs_rsv->size - -- delayed_refs_rsv->reserved; -- spin_unlock(&delayed_refs_rsv->lock); -- } -- -- bytes = num_bytes + *delayed_refs_bytes + extra_delayed_refs_bytes; -- - /* - * We want to reserve all the bytes we may need all at once, so we only - * do 1 enospc flushing cycle per transaction start. - */ - ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); -- if (ret == 0) { -- if (extra_delayed_refs_bytes > 0) -- btrfs_migrate_to_delayed_refs_rsv(fs_info, -- extra_delayed_refs_bytes); -- return 0; -- } -- -- if (extra_delayed_refs_bytes > 0) { -- bytes -= extra_delayed_refs_bytes; -- ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); -- if (ret == 0) -- return 0; -- } - - /* - * If we are an emergency flush, which can steal from the global block - * reserve, then attempt to not reserve space for the delayed refs, as - * we will consume space for them from the global block reserve. - */ -- if (flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { -+ if (ret && flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) { - bytes -= *delayed_refs_bytes; - *delayed_refs_bytes = 0; - ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush); -diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c -index a6968573b775..4a517b280f2b 100644 ---- a/fs/smb/client/namespace.c -+++ b/fs/smb/client/namespace.c -@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page) - return s; - } - -+static void fs_context_set_ids(struct smb3_fs_context *ctx) -+{ -+ kuid_t uid = current_fsuid(); -+ kgid_t gid = current_fsgid(); -+ -+ if (ctx->multiuser) { -+ if (!ctx->uid_specified) -+ ctx->linux_uid = uid; -+ if (!ctx->gid_specified) -+ ctx->linux_gid = gid; -+ } -+ if (!ctx->cruid_specified) -+ ctx->cred_uid = uid; -+} -+ - /* - * Create a vfsmount that we can automount - */ -@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) - tmp.leaf_fullpath = NULL; - tmp.UNC = tmp.prepath = NULL; - tmp.dfs_root_ses = NULL; -+ fs_context_set_ids(&tmp); - - rc = smb3_fs_context_dup(ctx, &tmp); - if (rc) { diff --git a/include/linux/efi.h b/include/linux/efi.h index 9cc5bf32f6f2..7462fb1fc99e 100644 --- a/include/linux/efi.h @@ -1493,7 +1306,7 @@ index 9cc5bf32f6f2..7462fb1fc99e 100644 enum efi_secureboot_mode efi_get_secureboot_mode(efi_get_variable_t *get_var) { diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h -index 472cb16458b0..7c0f6dd800cb 100644 +index ed3d517460f8..93ff72b07031 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -407,6 +407,8 @@ LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux) @@ -1773,183 +1586,8 @@ index a2ff4242e623..f0d2be1ee4f1 100644 } int module_sig_check(struct load_info *info, int flags) -diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c -index 88965e2068ac..ebc5728aab4e 100644 ---- a/net/openvswitch/flow_netlink.c -+++ b/net/openvswitch/flow_netlink.c -@@ -48,6 +48,7 @@ struct ovs_len_tbl { - - #define OVS_ATTR_NESTED -1 - #define OVS_ATTR_VARIABLE -2 -+#define OVS_COPY_ACTIONS_MAX_DEPTH 16 - - static bool actions_may_change_flow(const struct nlattr *actions) - { -@@ -2545,13 +2546,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - const struct sw_flow_key *key, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, -- u32 mpls_label_count, bool log); -+ u32 mpls_label_count, bool log, -+ u32 depth); - - static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, - const struct sw_flow_key *key, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, -- u32 mpls_label_count, bool log, bool last) -+ u32 mpls_label_count, bool log, bool last, -+ u32 depth) - { - const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; - const struct nlattr *probability, *actions; -@@ -2602,7 +2605,8 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, - return err; - - err = __ovs_nla_copy_actions(net, actions, key, sfa, -- eth_type, vlan_tci, mpls_label_count, log); -+ eth_type, vlan_tci, mpls_label_count, log, -+ depth + 1); - - if (err) - return err; -@@ -2617,7 +2621,8 @@ static int validate_and_copy_dec_ttl(struct net *net, - const struct sw_flow_key *key, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, -- u32 mpls_label_count, bool log) -+ u32 mpls_label_count, bool log, -+ u32 depth) - { - const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; - int start, action_start, err, rem; -@@ -2660,7 +2665,8 @@ static int validate_and_copy_dec_ttl(struct net *net, - return action_start; - - err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, -- vlan_tci, mpls_label_count, log); -+ vlan_tci, mpls_label_count, log, -+ depth + 1); - if (err) - return err; - -@@ -2674,7 +2680,8 @@ static int validate_and_copy_clone(struct net *net, - const struct sw_flow_key *key, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, -- u32 mpls_label_count, bool log, bool last) -+ u32 mpls_label_count, bool log, bool last, -+ u32 depth) - { - int start, err; - u32 exec; -@@ -2694,7 +2701,8 @@ static int validate_and_copy_clone(struct net *net, - return err; - - err = __ovs_nla_copy_actions(net, attr, key, sfa, -- eth_type, vlan_tci, mpls_label_count, log); -+ eth_type, vlan_tci, mpls_label_count, log, -+ depth + 1); - if (err) - return err; - -@@ -3063,7 +3071,7 @@ static int validate_and_copy_check_pkt_len(struct net *net, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, - u32 mpls_label_count, -- bool log, bool last) -+ bool log, bool last, u32 depth) - { - const struct nlattr *acts_if_greater, *acts_if_lesser_eq; - struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1]; -@@ -3111,7 +3119,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, - return nested_acts_start; - - err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa, -- eth_type, vlan_tci, mpls_label_count, log); -+ eth_type, vlan_tci, mpls_label_count, log, -+ depth + 1); - - if (err) - return err; -@@ -3124,7 +3133,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, - return nested_acts_start; - - err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa, -- eth_type, vlan_tci, mpls_label_count, log); -+ eth_type, vlan_tci, mpls_label_count, log, -+ depth + 1); - - if (err) - return err; -@@ -3152,12 +3162,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - const struct sw_flow_key *key, - struct sw_flow_actions **sfa, - __be16 eth_type, __be16 vlan_tci, -- u32 mpls_label_count, bool log) -+ u32 mpls_label_count, bool log, -+ u32 depth) - { - u8 mac_proto = ovs_key_mac_proto(key); - const struct nlattr *a; - int rem, err; - -+ if (depth > OVS_COPY_ACTIONS_MAX_DEPTH) -+ return -EOVERFLOW; -+ - nla_for_each_nested(a, attr, rem) { - /* Expected argument lengths, (u32)-1 for variable length. */ - static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { -@@ -3355,7 +3369,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - err = validate_and_copy_sample(net, a, key, sfa, - eth_type, vlan_tci, - mpls_label_count, -- log, last); -+ log, last, depth); - if (err) - return err; - skip_copy = true; -@@ -3426,7 +3440,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - err = validate_and_copy_clone(net, a, key, sfa, - eth_type, vlan_tci, - mpls_label_count, -- log, last); -+ log, last, depth); - if (err) - return err; - skip_copy = true; -@@ -3440,7 +3454,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - eth_type, - vlan_tci, - mpls_label_count, -- log, last); -+ log, last, -+ depth); - if (err) - return err; - skip_copy = true; -@@ -3450,7 +3465,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - case OVS_ACTION_ATTR_DEC_TTL: - err = validate_and_copy_dec_ttl(net, a, key, sfa, - eth_type, vlan_tci, -- mpls_label_count, log); -+ mpls_label_count, log, -+ depth); - if (err) - return err; - skip_copy = true; -@@ -3495,7 +3511,8 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - - (*sfa)->orig_len = nla_len(attr); - err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type, -- key->eth.vlan.tci, mpls_label_count, log); -+ key->eth.vlan.tci, mpls_label_count, log, -+ 0); - if (err) - ovs_nla_free_flow_actions(*sfa); - diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index cb6406f485a9..71e1f15d9dce 100644 +index f7c4d3fe4381..7fd1ef7930c6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -22,6 +22,7 @@ @@ -1960,7 +1598,7 @@ index cb6406f485a9..71e1f15d9dce 100644 static bool module_enabled; /* Are we using CONFIG_MODVERSIONS? */ -@@ -1987,6 +1988,12 @@ static void write_buf(struct buffer *b, const char *fname) +@@ -1988,6 +1989,12 @@ static void write_buf(struct buffer *b, const char *fname) } } @@ -1973,7 +1611,7 @@ index cb6406f485a9..71e1f15d9dce 100644 static void write_if_changed(struct buffer *b, const char *fname) { char *tmp; -@@ -2047,6 +2054,7 @@ static void write_mod_c_file(struct module *mod) +@@ -2048,6 +2055,7 @@ static void write_mod_c_file(struct module *mod) add_depends(&buf, mod); add_moddevtable(&buf, mod); add_srcversion(&buf, mod); @@ -2055,10 +1693,10 @@ index 68d19632aeb7..ef348935b6ff 100644 static int __init lockdown_lsm_init(void) diff --git a/security/security.c b/security/security.c -index 266cec94369b..c572a4da96b2 100644 +index 2cfecdb054c3..4e5fc4ec5896 100644 --- a/security/security.c +++ b/security/security.c -@@ -5248,6 +5248,18 @@ int security_locked_down(enum lockdown_reason what) +@@ -5283,6 +5283,18 @@ int security_locked_down(enum lockdown_reason what) } EXPORT_SYMBOL(security_locked_down); |