From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B35073C3B; Wed, 24 Jan 2024 00:58:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057920; cv=none; b=tvXEZDjXhg6sPCmyCHBaVIsjhF/0E7gVv9LXi04XSlke4kMm8q6NUyoQUWJxPyMx7yT5Plf0+f74xzYy3UajY0wDWg5x9bV6XyJCFOnWrHZ87DLMcJPkTO3ivYFA4QRfY+pj506q3ufPZC18s9Na22zclEM+618VXUFm6ctIdc0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057920; c=relaxed/simple; bh=0afrJ/uftX6Nq9Eow5vBIO/VvCEiQGqndgMtPqx2aco=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m49nn17HmjhVVIbg+obWHJJ59/jV3TiyH99G15+Nm5VvcN47b1p1Fr0YIagKQ5QzSkNTc4mDp4ncfRQBkWQRDI87+ktVPOzfTi1TG+DYBczU64djNdLX8YK3BQjn9Nhbdon+TSbOq+BA77d9ASHjzQRh8QfGPidFnhJomAICXWU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=iIP0o2mv; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="iIP0o2mv" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=oUXTx6PCjwpopSp5hsJS/fwxSNq/Qs+N3FA1Q73jh2c=; b=iIP0o2mvYtke4of5HpTYWx6VlE Sh6yOl5yvxhtSKUuhRSmREPdm5W47goV8nGyVpgZFxd+BCbGvztK6DtAcXympigwr/hYC+cZEY7gG 46JY3WLXYoos5DnuH8XFmofKKt2/K1dqYo+mUQtElj7AlREQp2XRRQBcna6nPTspsNvV3VLNUDoCN NfU56VZYnkIr2i5lf1a7vNIV9zUSWuI6AKToCVrHafYPS9+Gzbigtu1y+5uTDuhHy/2LR3Eb0/t/k AysYzbjiv9g+Ynrv3lZYI9juC64FRlQxtaYV9+wV/NP4TKZGYymut8MfURH3t+Fj9Q79d/+/yhweu cM/3TTiA==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-0r; Tue, 23 Jan 2024 18:42:05 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 1/9] ntsync: Introduce the ntsync driver and character device. Date: Tue, 23 Jan 2024 18:40:20 -0600 Message-ID: <20240124004028.16826-2-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ntsync uses a misc device as the simplest and least intrusive uAPI interfac= e. Each file description on the device represents an isolated NT instance, int= ended to correspond to a single NT virtual machine. Signed-off-by: Elizabeth Figura --- 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 4fb291f0bf7c..bdd8a71bd853 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -504,6 +504,15 @@ config OPEN_DICE measured boot flow. Userspace can use CDIs for remote attestation and sealing. =20 +config NTSYNC + tristate "NT synchronization primitive emulation" + help + 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 ntsync. + If unsure, say N. =20 config VCPU_STALL_DETECTOR diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ea6ea5bbbc9c..153a3f4837e8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PVPANIC) +=3D pvpanic/ obj-$(CONFIG_UACCE) +=3D uacce/ obj-$(CONFIG_XILINX_SDFEC) +=3D xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) +=3D hisi_hikey_usb.o +obj-$(CONFIG_NTSYNC) +=3D ntsync.o obj-$(CONFIG_HI6421V600_IRQ) +=3D hi6421v600-irq.o obj-$(CONFIG_OPEN_DICE) +=3D open-dice.o obj-$(CONFIG_GP_PCI1XXXX) +=3D mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 index 000000000000..9424c6210e51 --- /dev/null +++ b/drivers/misc/ntsync.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives + * + * Copyright (C) 2021-2022 Elizabeth Figura + */ + +#include +#include +#include + +#define NTSYNC_NAME "ntsync" + +static int ntsync_char_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +static int ntsync_char_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) +{ + switch (cmd) { + default: + return -ENOIOCTLCMD; + } +} + +static const struct file_operations ntsync_fops =3D { + .owner =3D THIS_MODULE, + .open =3D ntsync_char_open, + .release =3D ntsync_char_release, + .unlocked_ioctl =3D ntsync_char_ioctl, + .compat_ioctl =3D ntsync_char_ioctl, + .llseek =3D no_llseek, +}; + +static struct miscdevice ntsync_misc =3D { + .minor =3D MISC_DYNAMIC_MINOR, + .name =3D NTSYNC_NAME, + .fops =3D &ntsync_fops, +}; + +module_misc_device(ntsync_misc); + +MODULE_AUTHOR("Elizabeth Figura"); +MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("devname:" NTSYNC_NAME); --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B7FB25689; Wed, 24 Jan 2024 00:58:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057926; cv=none; b=pFvwEyrzaiqkD0iuya0dNXbJ/o2viS4Kkw3nqOUkiLPrtdirsA+/lPMa67BunSv9kv8CvznlWxjXpI9tsH8PcVR9o7FzmiUF8qaRY2cA9+0tIIr3HfzUG+6al8kbC8re3QzyZYfNfXoxIYwgYxR9UCDGMLB5mNdEpxoy1/qIs6k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057926; c=relaxed/simple; bh=bnDZ18PzZiaqrfIIydrSzNCN+uIZ5h48OVhffyfN5fk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DaLN30PNtvP3o8vmDRW4fGc2ZTQB7gli20Y0ne4eghnkBI2CUPXufHqXtQXzoJoI9pPL/WW5wofsBf/YCpkYX5H1GHmtWZDNM4W2APbyHf0r+fizAUzh5de28ECT7jbdyE5ZGZ0+zOXgcDmmQbWuU9CrdusLMbbxvAuhuId652U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=KSTIVbxI; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="KSTIVbxI" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=pCs+y0jFrd9vwNY8aF2JjaxuTN4JFwXk3TK7B1Y6y98=; b=KSTIVbxIiyc9Muc3XdvntahxwW zX4bLc6KLjak4Xc9XVYkeg8MCg6n0zXFgY4+AISWp9Dsa70hVb04dwZczqbF2EzaNXnr+x/XCgbS1 qK0gMvMHCXJ8i1J39IoajxkdN0NQkEi2NocMO5azudtu7EsER5PWX++ME0ovhQ5rR9hfJyF0UO1vX fm0Sx0p6wkk1Gp4FdXXlZX9SupKbhsUe2/dkmuKsORCPNolawLN2l7gn29yiccbZO3IBn1GZugVcA lfAca31W8mzpAmVEIYAQF9KKNR5rFkx7LyuwZK85Vw82b/b3fk1xIm5WcC1xmTewzzq08vaZ5pPTy 0N7fHRMA==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-1G; Tue, 23 Jan 2024 18:42:05 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 2/9] ntsync: Reserve a minor device number and ioctl range. Date: Tue, 23 Jan 2024 18:40:21 -0600 Message-ID: <20240124004028.16826-3-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: Elizabeth Figura --- Documentation/admin-guide/devices.txt | 3 ++- Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ drivers/misc/ntsync.c | 3 ++- include/linux/miscdevice.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-gu= ide/devices.txt index 94c98be1329a..041404397ee5 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -376,8 +376,9 @@ 240 =3D /dev/userio Serio driver testing device 241 =3D /dev/vhost-vsock Host kernel driver for virtio vsock 242 =3D /dev/rfkill Turning off radio transmissions (rfkill) + 243 =3D /dev/ntsync NT synchronization primitive device =20 - 243-254 Reserved for local use + 244-254 Reserved for local use 255 Reserved for MISC_DYNAMIC_MINOR =20 11 char Raw keyboard device (Linux/SPARC only) diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documenta= tion/userspace-api/ioctl/ioctl-number.rst index 457e16f06e04..a1326a5bc2e0 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -378,6 +378,8 @@ Code Seq# Include File = Comments 0xF6 all LTTng= Linux Trace Toolkit Next Generation +0xF7 00-1F uapi/linux/ntsync.h NT sy= nchronization primitives + 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD H= SMP EPYC system management interface driver 0xFD all linux/dm-ioctl.h diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 9424c6210e51..84b498e2b2d5 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -40,7 +40,7 @@ static const struct file_operations ntsync_fops =3D { }; =20 static struct miscdevice ntsync_misc =3D { - .minor =3D MISC_DYNAMIC_MINOR, + .minor =3D NTSYNC_MINOR, .name =3D NTSYNC_NAME, .fops =3D &ntsync_fops, }; @@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura"); MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); MODULE_LICENSE("GPL"); MODULE_ALIAS("devname:" NTSYNC_NAME); +MODULE_ALIAS_MISCDEV(NTSYNC_MINOR); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index c0fea6ca5076..fe5d9366fdf7 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -71,6 +71,7 @@ #define USERIO_MINOR 240 #define VHOST_VSOCK_MINOR 241 #define RFKILL_MINOR 242 +#define NTSYNC_MINOR 243 #define MISC_DYNAMIC_MINOR 255 =20 struct device; --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F02F1841; Wed, 24 Jan 2024 00:58:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057911; cv=none; b=FZau5uK8/Z1XLUczZuGcKM2u7n4iHBuxC/e3uyniWkgInJoCr1dBRz/7Snm0LPj/G4mk6iR1ks+KLuvnsMux6LheuOyO5TG0Ft/kkBVpOz8tRNQ3WaR4+L5JY26OKCjQb9fjusS09d0dwmkmssEbgYWIhhYe03VdHAqlCi3Bm2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057911; c=relaxed/simple; bh=gGRv5odUNhfX4VoV6kC+64r+PLYNEQB8KtgHYIT9nk8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q1F2lILSXUXNQ13HEBQ0EyEHuDYMEbFlz8wEWAnr3a1bGGpkyE64qWI/+0GJMu5Yw4lPGi3f0S9tvhKvcaU8UnqQ9A2FsAC+n7CU5O4z09t7pXd/x/ys3+M/wEa3r0+uUFewiADTUwLkHFbUVfby4jTQPT0LrYNkJA4260wOuEM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=l2HUwBKi; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="l2HUwBKi" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=IpiExmoWV0N5DWasqyp0qDuktw1Ruf47n+D+iWJ83/M=; b=l2HUwBKixJXPHnQ8DC/ZTyFzDF f1cDRO66MzSI54QY6M9+BhzcwlcisBFZ2+Etbg2/jeEjyjHQXZSdxzyHnErw8VoGIhsTYX7T5+Qy7 Idw6bNaBnRBok/idufHFDjVzpT9LzyMNApcaYe8KHDNGqOHDtLJX+Mh1i5YOrodAcO7csrScG+PPy P+2f/l+9K1mf3MWQiQJPnHRzoHlJMJ9spf9BV+YWjqj72+WfgNtvgSvIONcR/EIojDI15ncFlmR3t 6P9fG4NhS8WuXTTk4+DyDRWgAMP7y00JSsOBIb4SDEQcEHPwUXR67qE4uQkfLFPqUuhJHCYcsmfd9 8euWlbRg==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-1i; Tue, 23 Jan 2024 18:42:05 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 3/9] ntsync: Introduce NTSYNC_IOC_CREATE_SEM and NTSYNC_IOC_DELETE. Date: Tue, 23 Jan 2024 18:40:22 -0600 Message-ID: <20240124004028.16826-4-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" These correspond to the NT syscalls NtCreateSemaphore() and NtClose(). Unlike those functions, however, these ioctls do not handle object names, or lookup of existing objects, or handle reference counting, but simply create= the underlying primitive. The user space emulator is expected to implement those functions if they are required. Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/ntsync.h | 25 ++++++++ 2 files changed, 142 insertions(+) create mode 100644 include/uapi/linux/ntsync.h diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 84b498e2b2d5..3287b94be351 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -8,23 +8,140 @@ #include #include #include +#include +#include +#include =20 #define NTSYNC_NAME "ntsync" =20 +enum ntsync_type { + NTSYNC_TYPE_SEM, +}; + +struct ntsync_obj { + struct rcu_head rhead; + struct kref refcount; + + enum ntsync_type type; + + union { + struct { + __u32 count; + __u32 max; + } sem; + } u; +}; + +struct ntsync_device { + struct xarray objects; +}; + +static void destroy_obj(struct kref *ref) +{ + struct ntsync_obj *obj =3D container_of(ref, struct ntsync_obj, refcount); + + kfree_rcu(obj, rhead); +} + +static void put_obj(struct ntsync_obj *obj) +{ + kref_put(&obj->refcount, destroy_obj); +} + static int ntsync_char_open(struct inode *inode, struct file *file) { + struct ntsync_device *dev; + + dev =3D kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); + + file->private_data =3D dev; return nonseekable_open(inode, file); } =20 static int ntsync_char_release(struct inode *inode, struct file *file) { + struct ntsync_device *dev =3D file->private_data; + struct ntsync_obj *obj; + unsigned long id; + + xa_for_each(&dev->objects, id, obj) + put_obj(obj); + + xa_destroy(&dev->objects); + + kfree(dev); + + return 0; +} + +static void init_obj(struct ntsync_obj *obj) +{ + kref_init(&obj->refcount); +} + +static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_sem_args __user *user_args =3D argp; + struct ntsync_sem_args args; + struct ntsync_obj *sem; + __u32 id; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (args.count > args.max) + return -EINVAL; + + sem =3D kzalloc(sizeof(*sem), GFP_KERNEL); + if (!sem) + return -ENOMEM; + + init_obj(sem); + sem->type =3D NTSYNC_TYPE_SEM; + sem->u.sem.count =3D args.count; + sem->u.sem.max =3D args.max; + + ret =3D xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL); + if (ret < 0) { + kfree(sem); + return ret; + } + + return put_user(id, &user_args->sem); +} + +static int ntsync_delete(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_obj *obj; + __u32 id; + + if (get_user(id, (__u32 __user *)argp)) + return -EFAULT; + + obj =3D xa_erase(&dev->objects, id); + if (!obj) + return -EINVAL; + + put_obj(obj); return 0; } =20 static long ntsync_char_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { + struct ntsync_device *dev =3D file->private_data; + void __user *argp =3D (void __user *)parm; + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_DELETE: + return ntsync_delete(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h new file mode 100644 index 000000000000..d97afc138dcc --- /dev/null +++ b/include/uapi/linux/ntsync.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Kernel support for NT synchronization primitive emulation + * + * Copyright (C) 2021-2022 Elizabeth Figura + */ + +#ifndef __LINUX_NTSYNC_H +#define __LINUX_NTSYNC_H + +#include + +struct ntsync_sem_args { + __u32 sem; + __u32 count; + __u32 max; +}; + +#define NTSYNC_IOC_BASE 0xf7 + +#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ + struct ntsync_sem_args) +#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) + +#endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3158C1106; Wed, 24 Jan 2024 00:58:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057917; cv=none; b=cBZ2F2Y3Iw34KLN5NNgqgSbvdzBC9waRIRl2rri4jFiUW1gx8MU0eX10VWHwG6ACsEHN1WwCS20HgEY+4S2/ms84a+S1Jip+jELJtwx1jzvnkCSx0DUSUfxV4TCBks+fCI8oYYddWakCi+C/HqHtzYLH4639LqjiQMG4OfgT6N0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057917; c=relaxed/simple; bh=XM9GV8+sIMF5RW/KaB3HIusG5cMiPnVsHGK1IBjoex4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aciia/+kjrKlzr4yTxgvGqQZKPmUOc78gdmxTsNTeiHsQeMsCzk1Ic3yhEF89/kcK2H27bHRn5ppuPlF22Wak7s1VQwlUOQxXX51NR1SNHoO5zCGLye8L9pgbkr8uaRWRQ5Z5hLfndh4bZDIb5hJMQyvFxrZWO0U8Jmsfm6ut08= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=i4sXuuWK; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="i4sXuuWK" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=/+Jb+z9Ua1CTDoDCd/u+WQhU/PYvORg76KqM3L0CpVs=; b=i4sXuuWKHjKxS4FGq+K00nVbyd HlFC/HixOQ6zLd8hsht4H0sEAuy1eGn37NCPWHIEX+Eq1B88g53/FVvQNJqlXN3xkkSYB8ZSWA6q5 UWjhWjzJ4LkoEZt8Ohtp8mjy63flNZb0D6PZ6qsXAiwXRK8o6clyD/0MBE4FH1Dgzz82gbnYJnCv3 mw6lFvqXAfrG/ttBhTioQWRcbpDa31XtlA86Ir86L7GcES9HawtUN2gpzlUHApzOouXjq1Dy2ajQ3 yg2luBELKYi/4nhk81bFmZmxbIi+ZIUQdfC3KguyST03qarJGjn7T8CPnIwPC9YpIymuR6zhU6y+j b2SYn2Cw==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-2B; Tue, 23 Jan 2024 18:42:05 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 4/9] ntsync: Introduce NTSYNC_IOC_PUT_SEM. Date: Tue, 23 Jan 2024 18:40:23 -0600 Message-ID: <20240124004028.16826-5-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This corresponds to the NT syscall NtReleaseSemaphore(). Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/ntsync.h | 2 + 2 files changed, 78 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 3287b94be351..d1c91c2a4f1a 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -21,9 +21,11 @@ enum ntsync_type { struct ntsync_obj { struct rcu_head rhead; struct kref refcount; + spinlock_t lock; =20 enum ntsync_type type; =20 + /* The following fields are protected by the object lock. */ union { struct { __u32 count; @@ -36,6 +38,19 @@ struct ntsync_device { struct xarray objects; }; =20 +static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id) +{ + struct ntsync_obj *obj; + + rcu_read_lock(); + obj =3D xa_load(&dev->objects, id); + if (obj && !kref_get_unless_zero(&obj->refcount)) + obj =3D NULL; + rcu_read_unlock(); + + return obj; +} + static void destroy_obj(struct kref *ref) { struct ntsync_obj *obj =3D 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); } =20 +static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 i= d, + enum ntsync_type type) +{ + struct ntsync_obj *obj =3D get_obj(dev, id); + + if (obj && obj->type !=3D type) { + put_obj(obj); + return NULL; + } + return obj; +} + static int ntsync_char_open(struct inode *inode, struct file *file) { struct ntsync_device *dev; @@ -81,6 +108,7 @@ static int ntsync_char_release(struct inode *inode, stru= ct file *file) static void init_obj(struct ntsync_obj *obj) { kref_init(&obj->refcount); + spin_lock_init(&obj->lock); } =20 static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) @@ -131,6 +159,52 @@ static int ntsync_delete(struct ntsync_device *dev, vo= id __user *argp) return 0; } =20 +/* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. + */ +static int put_sem_state(struct ntsync_obj *sem, __u32 count) +{ + lockdep_assert_held(&sem->lock); + + if (sem->u.sem.count + count < sem->u.sem.count || + sem->u.sem.count + count > sem->u.sem.max) + return -EOVERFLOW; + + sem->u.sem.count +=3D count; + return 0; +} + +static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_sem_args __user *user_args =3D 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 =3D get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM); + if (!sem) + return -EINVAL; + + spin_lock(&sem->lock); + + prev_count =3D sem->u.sem.count; + ret =3D put_sem_state(sem, args.count); + + spin_unlock(&sem->lock); + + put_obj(sem); + + if (!ret && put_user(prev_count, &user_args->count)) + ret =3D -EFAULT; + + return ret; +} + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { @@ -142,6 +216,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed int cmd, return ntsync_create_sem(dev, argp); case NTSYNC_IOC_DELETE: return ntsync_delete(dev, argp); + case NTSYNC_IOC_PUT_SEM: + return ntsync_put_sem(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h index d97afc138dcc..8c610d65f8ef 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h @@ -21,5 +21,7 @@ struct ntsync_sem_args { #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ struct ntsync_sem_args) #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) +#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ + struct ntsync_sem_args) =20 #endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 133E24C78; Wed, 24 Jan 2024 00:58:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057923; cv=none; b=LLkN7N6cpP9SLBFcfqKIHq1H8uL3md/oU6+jyw0tsJcEHNUBsDkE3aaVpUalEllKBqpD5/wnfw+MQnVBP0PEW6jc0/q6fyF+8stYZ+kXXMUdCX56rXGLqFeYMXDYK4s2dvGBbrgZyIbhzsviwu6SEqJXskDKjJ/65akS15ATS7s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057923; c=relaxed/simple; bh=1PoVRiq9uKUZYi4V4WUdlXLfdCr9s7ZAFXEMf3qda60=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tqMTpBG4vBiYv2VSrq9/4rEOTRsTOLuWi76IOeB9raTjAsP/+lpOGu9r39Yi28Q769gMDK9VqN3zc5OHOAqQ6WWkYvF0O0YcL+NrWJscLdkVIu04rxgunoh43n5/h8xkkWtXGUtTjiKt8dEU8KeWoYp5pgPgxvEGmBXwowVE7HI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=IOGSE3p/; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="IOGSE3p/" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=eSHiOwdmwzGTK6aa3cqA4OMSW9jJsH6a23aKWFD9RUA=; b=IOGSE3p/uwf8X4MRPFrVuy34OR cTV/tLiFcYvqZeHWDkMeqpUGvvx5/ky+lA0R0TKqJLaS0PeE4naC6KBL1CiZeRTHq4neTCD0UKDt7 WzQKS452lpelJ9FjFLrUOVdQdvlWdeVJM7b6ci5MxmP5kYhyECzKWtfJB2SHWgB4AzHwQXWtgE6Z9 lIArIn0hJaQj37MG6sw3ovRCXeZulQulb+NWCs7LqcYj4tmjezvqDqKrxaEr0fged4vmbJnVvNX9F BIc22vz1k9kPmSoo9g+opjIkzzVlxDLLmF1F9k8b65TjLXuzqNzyrOjRzOsL6ajra7ZUIxpIm2aiZ KFJT1wrQ==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-2e; Tue, 23 Jan 2024 18:42:05 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 5/9] ntsync: Introduce NTSYNC_IOC_WAIT_ANY. Date: Tue, 23 Jan 2024 18:40:24 -0600 Message-ID: <20240124004028.16826-6-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 wai= ts. Those features have been split out into separate patches to ease review. Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/ntsync.h | 13 ++ 2 files changed, 242 insertions(+) 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; =20 + struct list_head any_waiters; + enum ntsync_type type; =20 /* The following fields are protected by the object lock. */ @@ -34,6 +36,28 @@ struct ntsync_obj { } u; }; =20 +struct ntsync_q_entry { + struct list_head node; + struct ntsync_q *q; + struct ntsync_obj *obj; + __u32 index; +}; + +struct ntsync_q { + struct task_struct *task; + __u32 owner; + + /* + * Protected via atomic_cmpxchg(). Only the thread that wins the + * compare-and-swap may actually change object states and wake this + * task. + */ + atomic_t signaled; + + __u32 count; + struct ntsync_q_entry entries[]; +}; + struct ntsync_device { struct xarray objects; }; @@ -109,6 +133,26 @@ static void init_obj(struct ntsync_obj *obj) { kref_init(&obj->refcount); spin_lock_init(&obj->lock); + INIT_LIST_HEAD(&obj->any_waiters); +} + +static void try_wake_any_sem(struct ntsync_obj *sem) +{ + struct ntsync_q_entry *entry; + + lockdep_assert_held(&sem->lock); + + list_for_each_entry(entry, &sem->any_waiters, node) { + struct ntsync_q *q =3D entry->q; + + if (!sem->u.sem.count) + break; + + if (atomic_cmpxchg(&q->signaled, -1, entry->index) =3D=3D -1) { + sem->u.sem.count--; + wake_up_process(q->task); + } + } } =20 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, vo= id __user *argp) =20 prev_count =3D sem->u.sem.count; ret =3D put_sem_state(sem, args.count); + if (!ret) + try_wake_any_sem(sem); =20 spin_unlock(&sem->lock); =20 @@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, = void __user *argp) return ret; } =20 +static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) +{ + int ret =3D 0; + + do { + if (signal_pending(current)) { + ret =3D -ERESTARTSYS; + break; + } + + set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read(&q->signaled) !=3D -1) { + ret =3D 0; + break; + } + ret =3D schedule_hrtimeout(timeout, HRTIMER_MODE_ABS); + } while (ret < 0); + __set_current_state(TASK_RUNNING); + + return ret; +} + +/* + * Allocate and initialize the ntsync_q structure, but do not queue us yet. + * Also, calculate the relative timeout. + */ +static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, + ktime_t *ret_timeout, struct ntsync_q **ret_q) +{ + const __u32 count =3D args->count; + struct ntsync_q *q; + ktime_t timeout =3D 0; + __u32 *ids; + __u32 i, j; + + if (!args->owner || args->pad) + return -EINVAL; + + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + + if (args->timeout) { + struct timespec64 to; + + if (get_timespec64(&to, u64_to_user_ptr(args->timeout))) + return -EFAULT; + if (!timespec64_valid(&to)) + return -EINVAL; + + timeout =3D timespec64_to_ns(&to); + } + + ids =3D kmalloc_array(count, sizeof(*ids), GFP_KERNEL); + if (!ids) + return -ENOMEM; + if (copy_from_user(ids, u64_to_user_ptr(args->objs), + array_size(count, sizeof(*ids)))) { + kfree(ids); + return -EFAULT; + } + + q =3D kmalloc(struct_size(q, entries, count), GFP_KERNEL); + if (!q) { + kfree(ids); + return -ENOMEM; + } + q->task =3D current; + q->owner =3D args->owner; + atomic_set(&q->signaled, -1); + q->count =3D count; + + for (i =3D 0; i < count; i++) { + struct ntsync_q_entry *entry =3D &q->entries[i]; + struct ntsync_obj *obj =3D get_obj(dev, ids[i]); + + if (!obj) + goto err; + + entry->obj =3D obj; + entry->q =3D q; + entry->index =3D i; + } + + kfree(ids); + + *ret_q =3D q; + *ret_timeout =3D timeout; + return 0; + +err: + for (j =3D 0; j < i; j++) + put_obj(q->entries[j].obj); + kfree(ids); + kfree(q); + return -EINVAL; +} + +static void try_wake_any_obj(struct ntsync_obj *obj) +{ + switch (obj->type) { + case NTSYNC_TYPE_SEM: + try_wake_any_sem(obj); + break; + } +} + +static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_wait_args args; + struct ntsync_q *q; + ktime_t timeout; + int signaled; + __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + ret =3D setup_wait(dev, &args, &timeout, &q); + if (ret < 0) + return ret; + + /* queue ourselves */ + + for (i =3D 0; i < args.count; i++) { + struct ntsync_q_entry *entry =3D &q->entries[i]; + struct ntsync_obj *obj =3D entry->obj; + + spin_lock(&obj->lock); + list_add_tail(&entry->node, &obj->any_waiters); + spin_unlock(&obj->lock); + } + + /* check if we are already signaled */ + + for (i =3D 0; i < args.count; i++) { + struct ntsync_obj *obj =3D q->entries[i].obj; + + if (atomic_read(&q->signaled) !=3D -1) + break; + + spin_lock(&obj->lock); + try_wake_any_obj(obj); + spin_unlock(&obj->lock); + } + + /* sleep */ + + ret =3D ntsync_schedule(q, args.timeout ? &timeout : NULL); + + /* and finally, unqueue */ + + for (i =3D 0; i < args.count; i++) { + struct ntsync_q_entry *entry =3D &q->entries[i]; + struct ntsync_obj *obj =3D entry->obj; + + spin_lock(&obj->lock); + list_del(&entry->node); + spin_unlock(&obj->lock); + + put_obj(obj); + } + + signaled =3D atomic_read(&q->signaled); + if (signaled !=3D -1) { + struct ntsync_wait_args __user *user_args =3D argp; + + /* even if we caught a signal, we need to communicate success */ + ret =3D 0; + + if (put_user(signaled, &user_args->index)) + ret =3D -EFAULT; + } else if (!ret) { + ret =3D -ETIMEDOUT; + } + + kfree(q); + return ret; +} + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { @@ -218,6 +445,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed 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 -ENOIOCTLCMD; } 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; }; =20 +struct ntsync_wait_args { + __u64 timeout; + __u64 objs; + __u32 count; + __u32 owner; + __u32 index; + __u32 pad; +}; + +#define NTSYNC_MAX_WAIT_COUNT 64 + #define NTSYNC_IOC_BASE 0xf7 =20 #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) =20 #endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F69B1FB9; Wed, 24 Jan 2024 00:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057915; cv=none; b=sDvtwMzULQcjUttm/VW5Q2M4gMrHcfm3AOvs6Uy/U4SsSB23yLaSMVjDDCf7d/COV2f1tgEakgiHZI2v/n+D7JQxY+kAbcX3ekhJFmYyNSXsNJWfSK4c5Upk0tjmO5SNvWaIuVG/WeuqbW8v6N+nGwPt7I4VRMHypQ/xAHffkio= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057915; c=relaxed/simple; bh=+AtNfFRSJOpH18CKVrmuF/scPXxsWAx8Z+SsFLD/Qcg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=urhPOF5ln6j3Ppsyx/qsRUioaOixhHOsoyzAeH2K3LWxepCklVnKjVo2wtT7lHSsMmOjOVkT23x8eM466bdDoVXknVX3ofFiDgCStQfrHXYwE64oboTYmuCx63lVFnjBRAKWrDw9Tq/bDMMbVcEddABIGEEZUxlz6P4dtvbg5x0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=QqicEDN6; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="QqicEDN6" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=xmPpmTCXC+l3vmysIVkGD33uWqyaTP5tz/rZDAydbXw=; b=QqicEDN6a6NscS8Xpc9ph1ELqE ppKYoQTth4+CdTkYZIYhMYyBKzL8rJpTsqP21DcOQ9zH7BLT0Z4lZlYg1b8e1t+Ul4RHhI8WNOCZZ JPj5JdNLhcLeldRvy/vvBAPFlWPC/UcZT3uN0zjLpwDOpJYcrmF/TXTnDFoJXkC4vSewP2MDmxK4p 3fLwQZ3WrAdrZiQNDfspkItCuX014Olj8fh5lyxiELNJ/2TnffPAzx/FC1qohz2oMG+SeKre3UK1D 8lBI9oTvGMUpVmuzc3sZFEcdcPCSK0Q3NopbjxkcyQyQMFnM4C7EzNfh0QKu9LiiiBE7uewX4m4vg nD+q+MQQ==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLB-00DVeW-38; Tue, 23 Jan 2024 18:42:06 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 6/9] ntsync: Introduce NTSYNC_IOC_WAIT_ALL. Date: Tue, 23 Jan 2024 18:40:25 -0600 Message-ID: <20240124004028.16826-7-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++-- include/uapi/linux/ntsync.h | 2 + 2 files changed, 235 insertions(+), 8 deletions(-) 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; =20 + /* + * any_waiters is protected by the object lock, but all_waiters is + * protected by the device wait_all_lock. + */ struct list_head any_waiters; + struct list_head all_waiters; + + /* + * Hint describing how many tasks are queued on this object in a + * wait-all operation. + * + * Any time we do a wake, we may need to wake "all" waiters as well as + * "any" waiters. In order to atomically wake "all" waiters, we must + * lock all of the objects, and that means grabbing the wait_all_lock + * below (and, due to lock ordering rules, before locking this object). + * However, wait-all is a rare operation, and grabbing the wait-all + * lock for every wake would create unnecessary contention. Therefore we + * first check whether all_hint is zero, and, if it is, we skip trying + * to wake "all" waiters. + * + * This hint isn't protected by any lock. It might change during the + * course of a wake, but there's no meaningful race there; it's only a + * hint. + * + * Since wait requests must originate from user-space threads, we're + * limited here by PID_MAX_LIMIT, so there's no risk of saturation. + */ + atomic_t all_hint; =20 enum ntsync_type type; =20 @@ -54,11 +81,25 @@ struct ntsync_q { */ atomic_t signaled; =20 + bool all; __u32 count; struct ntsync_q_entry entries[]; }; =20 struct ntsync_device { + /* + * Wait-all operations must atomically grab all objects, and be totally + * ordered with respect to each other and wait-any operations. If one + * thread is trying to acquire several objects, another thread cannot + * touch the object at the same time. + * + * We achieve this by grabbing multiple object locks at the same time. + * However, this creates a lock ordering problem. To solve that problem, + * wait_all_lock is taken first whenever multiple objects must be locked + * at the same time. + */ + spinlock_t wait_all_lock; + struct xarray objects; }; =20 @@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct= file *file) if (!dev) return -ENOMEM; =20 + spin_lock_init(&dev->wait_all_lock); + xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); =20 file->private_data =3D dev; @@ -132,8 +175,81 @@ static int ntsync_char_release(struct inode *inode, st= ruct file *file) static void init_obj(struct ntsync_obj *obj) { kref_init(&obj->refcount); + atomic_set(&obj->all_hint, 0); spin_lock_init(&obj->lock); INIT_LIST_HEAD(&obj->any_waiters); + INIT_LIST_HEAD(&obj->all_waiters); +} + +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ + lockdep_assert_held(&obj->lock); + + switch (obj->type) { + case NTSYNC_TYPE_SEM: + return !!obj->u.sem.count; + } + + WARN(1, "bad object type %#x\n", obj->type); + return false; +} + +/* + * "locked_obj" is an optional pointer to an object which is already locke= d and + * should not be locked again. This is necessary so that changing an objec= t's + * state and waking it can be a single atomic operation. + */ +static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + struct ntsync_obj *locked_obj) +{ + __u32 count =3D q->count; + bool can_wake =3D true; + __u32 i; + + lockdep_assert_held(&dev->wait_all_lock); + if (locked_obj) + lockdep_assert_held(&locked_obj->lock); + + for (i =3D 0; i < count; i++) { + if (q->entries[i].obj !=3D locked_obj) + spin_lock_nest_lock(&q->entries[i].obj->lock, &dev->wait_all_lock); + } + + for (i =3D 0; i < count; i++) { + if (!is_signaled(q->entries[i].obj, q->owner)) { + can_wake =3D false; + break; + } + } + + if (can_wake && atomic_cmpxchg(&q->signaled, -1, 0) =3D=3D -1) { + for (i =3D 0; i < count; i++) { + struct ntsync_obj *obj =3D q->entries[i].obj; + + switch (obj->type) { + case NTSYNC_TYPE_SEM: + obj->u.sem.count--; + break; + } + } + wake_up_process(q->task); + } + + for (i =3D 0; i < count; i++) { + if (q->entries[i].obj !=3D locked_obj) + spin_unlock(&q->entries[i].obj->lock); + } +} + +static void try_wake_all_obj(struct ntsync_device *dev, struct ntsync_obj = *obj) +{ + struct ntsync_q_entry *entry; + + lockdep_assert_held(&dev->wait_all_lock); + lockdep_assert_held(&obj->lock); + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); } =20 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; =20 - spin_lock(&sem->lock); + if (atomic_read(&sem->all_hint) > 0) { + spin_lock(&dev->wait_all_lock); + spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); =20 - prev_count =3D sem->u.sem.count; - ret =3D put_sem_state(sem, args.count); - if (!ret) - try_wake_any_sem(sem); + prev_count =3D sem->u.sem.count; + ret =3D put_sem_state(sem, args.count); + if (!ret) { + try_wake_all_obj(dev, sem); + try_wake_any_sem(sem); + } =20 - spin_unlock(&sem->lock); + spin_unlock(&sem->lock); + spin_unlock(&dev->wait_all_lock); + } else { + spin_lock(&sem->lock); + + prev_count =3D sem->u.sem.count; + ret =3D put_sem_state(sem, args.count); + if (!ret) + try_wake_any_sem(sem); + + spin_unlock(&sem->lock); + } =20 put_obj(sem); =20 @@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, kt= ime_t *timeout) * Also, calculate the relative timeout. */ 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 =3D args->count; @@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, q->task =3D current; q->owner =3D args->owner; atomic_set(&q->signaled, -1); + q->all =3D all; q->count =3D count; =20 for (i =3D 0; i < count; i++) { @@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, if (!obj) goto err; =20 + if (all) { + /* Check that the objects are all distinct. */ + for (j =3D 0; j < i; j++) { + if (obj =3D=3D q->entries[j].obj) { + put_obj(obj); + goto err; + } + } + } + entry->obj =3D obj; entry->q =3D q; entry->index =3D i; @@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, v= oid __user *argp) if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; =20 - ret =3D setup_wait(dev, &args, &timeout, &q); + ret =3D setup_wait(dev, &args, false, &timeout, &q); if (ret < 0) return ret; =20 @@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, = void __user *argp) return ret; } =20 +static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_wait_args args; + struct ntsync_q *q; + ktime_t timeout; + int signaled; + __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + ret =3D setup_wait(dev, &args, true, &timeout, &q); + if (ret < 0) + return ret; + + /* queue ourselves */ + + spin_lock(&dev->wait_all_lock); + + for (i =3D 0; i < args.count; i++) { + struct ntsync_q_entry *entry =3D &q->entries[i]; + struct ntsync_obj *obj =3D entry->obj; + + atomic_inc(&obj->all_hint); + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather + * than obj->lock, so there is no need to acquire it here. + */ + list_add_tail(&entry->node, &obj->all_waiters); + } + + /* check if we are already signaled */ + + try_wake_all(dev, q, NULL); + + spin_unlock(&dev->wait_all_lock); + + /* sleep */ + + ret =3D ntsync_schedule(q, args.timeout ? &timeout : NULL); + + /* and finally, unqueue */ + + spin_lock(&dev->wait_all_lock); + + for (i =3D 0; i < args.count; i++) { + struct ntsync_q_entry *entry =3D &q->entries[i]; + struct ntsync_obj *obj =3D entry->obj; + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather + * than obj->lock, so there is no need to acquire it here. + */ + list_del(&entry->node); + + atomic_dec(&obj->all_hint); + + put_obj(obj); + } + + spin_unlock(&dev->wait_all_lock); + + signaled =3D atomic_read(&q->signaled); + if (signaled !=3D -1) { + struct ntsync_wait_args __user *user_args =3D argp; + + /* even if we caught a signal, we need to communicate success */ + ret =3D 0; + + if (put_user(signaled, &user_args->index)) + ret =3D -EFAULT; + } else if (!ret) { + ret =3D -ETIMEDOUT; + } + + kfree(q); + return ret; +} + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { @@ -445,6 +668,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed 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/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) =20 #endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AAE9CC158; Wed, 24 Jan 2024 00:58:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057934; cv=none; b=imfcRKbgvdL0oO5N8+2k82K/xlWlK/s2tMFCw0ZxLE++MFjNpRZ9CKWRH09i2BlAymzwPQDzCiL8YVZ/M3Qddr56jyn1/U+Q1GCjB0eCLC5QJcePuc8BdomDVqn69KQzIUHxBx9G3/eSGYIdfr7or9eYjfJXcORUSY97s9THnc8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057934; c=relaxed/simple; bh=OK38CsfmTQ/+2qSV1J4hYuKjCcXbFCVQw/NRr4ahxMo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tTKI9cgqYK7Y+fI/AtqzoeK5XbaRO6HKpuGRnIy+qkIkT8I3MoXHhgHNHrObKBEe8YTfK/Lyd7sNeyE8zw1dahteFOHnZaXWBRlkWx4GX5ivrg8Dy9krd5kYck3sIPU2CRDzMxHhVuw/GWiXhZCiXRmKey1AmGvjI2ea7kiLdKM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=Jig3bTtu; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="Jig3bTtu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=n18n/Dm5XC6gbUFhjKBhHb8lqgVEir8MGaSOOm77plw=; b=Jig3bTtunFQFejUo6b+UvK6XZF 7SgxJtpxArTsO4cbvnNbOIvIMo/QGA5gArDGz5JtNA6ry5L2pt/CCiH6HjGwck0+X0b43/Gslh9g2 vg1y3MvizpW+KlPcFJalkc/qzzfjIe1lhgfzD4kqE2tc2DCDzItFsu2TNrajxp7H11asQ0Lz9zaY8 3zldhzmOHX85FHXvneXHHk0kK3l2HGF4xl5D7jAUPI+sCDSPuwGBOBLC4nfMB2xCtzYXKAIwjFVD6 K4J9qAEXgW/wFMhlWUhGrBkJX4M/4RtcLIiYrZ5xpEvQMxUHYEg939uG9ym9EZXiJALrjelKkCMEm o+169QSw==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLC-00DVeW-0c; Tue, 23 Jan 2024 18:42:06 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 7/9] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX. Date: Tue, 23 Jan 2024 18:40:26 -0600 Message-ID: <20240124004028.16826-8-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This corresponds to the NT syscall NtCreateMutant(). Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/ntsync.h | 8 +++++ 2 files changed, 80 insertions(+) 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 @@ =20 enum ntsync_type { NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, }; =20 struct ntsync_obj { @@ -60,6 +61,10 @@ struct ntsync_obj { __u32 count; __u32 max; } sem; + struct { + __u32 count; + __u32 owner; + } mutex; } u; }; =20 @@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 = owner) switch (obj->type) { case NTSYNC_TYPE_SEM: return !!obj->u.sem.count; + case NTSYNC_TYPE_MUTEX: + if (obj->u.mutex.owner && obj->u.mutex.owner !=3D owner) + return false; + return obj->u.mutex.count < UINT_MAX; } =20 WARN(1, "bad object type %#x\n", obj->type); @@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, st= ruct ntsync_q *q, case NTSYNC_TYPE_SEM: obj->u.sem.count--; break; + case NTSYNC_TYPE_MUTEX: + obj->u.mutex.count++; + obj->u.mutex.owner =3D q->owner; + break; } } wake_up_process(q->task); @@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) } } =20 +static void try_wake_any_mutex(struct ntsync_obj *mutex) +{ + struct ntsync_q_entry *entry; + + lockdep_assert_held(&mutex->lock); + + list_for_each_entry(entry, &mutex->any_waiters, node) { + struct ntsync_q *q =3D entry->q; + + if (mutex->u.mutex.count =3D=3D UINT_MAX) + break; + if (mutex->u.mutex.owner && mutex->u.mutex.owner !=3D q->owner) + continue; + + if (atomic_cmpxchg(&q->signaled, -1, entry->index) =3D=3D -1) { + mutex->u.mutex.count++; + mutex->u.mutex.owner =3D q->owner; + wake_up_process(q->task); + } + } +} + static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) { struct ntsync_sem_args __user *user_args =3D argp; @@ -303,6 +338,38 @@ static int ntsync_create_sem(struct ntsync_device *dev= , void __user *argp) return put_user(id, &user_args->sem); } =20 +static int ntsync_create_mutex(struct ntsync_device *dev, void __user *arg= p) +{ + struct ntsync_mutex_args __user *user_args =3D argp; + struct ntsync_mutex_args args; + struct ntsync_obj *mutex; + __u32 id; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (!args.owner !=3D !args.count) + return -EINVAL; + + mutex =3D kzalloc(sizeof(*mutex), GFP_KERNEL); + if (!mutex) + return -ENOMEM; + + init_obj(mutex); + mutex->type =3D NTSYNC_TYPE_MUTEX; + mutex->u.mutex.count =3D args.count; + mutex->u.mutex.owner =3D args.owner; + + ret =3D xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL); + if (ret < 0) { + kfree(mutex); + return ret; + } + + return put_user(id, &user_args->mutex); +} + static int ntsync_delete(struct ntsync_device *dev, void __user *argp) { 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 NTSYNC_TYPE_MUTEX: + try_wake_any_mutex(obj); + break; } } =20 @@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed int cmd, void __user *argp =3D (void __user *)parm; =20 switch (cmd) { + 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; }; =20 +struct ntsync_mutex_args { + __u32 mutex; + __u32 owner; + __u32 count; +}; + struct ntsync_wait_args { __u64 timeout; __u64 objs; @@ -38,5 +44,7 @@ struct ntsync_wait_args { struct ntsync_wait_args) #define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ struct ntsync_wait_args) +#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ + struct ntsync_mutex_args) =20 #endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73277AD38; Wed, 24 Jan 2024 00:58:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057928; cv=none; b=XYPNQ4L3zrFtO9kCGPNn0BHvjn+XOfD+4OH/PtE92EPw1zveqRXtGrMht0H6on/BjE8u42TVrCFfd49HzPUtTtQV7eU4qFeqcAu8r/kRL6JbJHKe1xaegqvTqmffPMsl7geoBnxjihGVA9/+XufleI3/qlH/DI+0+J28FuoUHWE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057928; c=relaxed/simple; bh=iT0r2RJsto1epLipUV7SicZlac1/9HjZGJBM22ZpeMI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bcFhJSD0+/GgfvDm/ZFeFwOCYTEn0f6Ul4jG2g/MRDE4GFTVdsnQeOGqdi6enb+IcKuy4RKcaaQg1pTLH+rNKEPm9TTb0oS9Q1I90ZyHx+1715F0YoqkoKYZmkZqsTD0L8zVc6un4lXReTOr28unhSVzwIuqsCWJOo1GjQy98sM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=nCD3x1+s; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="nCD3x1+s" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=eZKiIoLdsYnVqMY14FeAEuF83BaQKKBYG8kS3hI8OEQ=; b=nCD3x1+skIr64JObiGTnvjAR3J BXBdGr7y/1cAZYqhITSnQ73PPPQczXmXiJHZYDM194xUMoZbjkba2sgi9WQBDEIiDIWny/sixH4Oi qEPN8oCIqY5huhGeMpPCw5yQdYLBuQ3IOTkkPXUdSrO9dWj7UIjpNmAQKOdNASbqVKLluZA7rXTYk lH0a2i0YMkQyg/JPey0al9TplGpw7LaTIvFA8edL1SCcWEu5yN6JCx4fM5VZ7Y1zXmWcR0ghh75Xz Xh1FiCdUlZa5l+kVBa6sHZ7y4UUC7bUEw8z8ZlavNUsLjuiRHBNp3oZaoTX3JAng4J4+nGO7OIRWY dusaE1xQ==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLC-00DVeW-18; Tue, 23 Jan 2024 18:42:06 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 8/9] ntsync: Introduce NTSYNC_IOC_PUT_MUTEX. Date: Tue, 23 Jan 2024 18:40:27 -0600 Message-ID: <20240124004028.16826-9-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This corresponds to the NT syscall NtReleaseMutant(). Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/ntsync.h | 2 ++ 2 files changed, 69 insertions(+) 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, v= oid __user *argp) return ret; } =20 +/* + * Actually change the mutex state, returning -EPERM if not the owner. + */ +static int put_mutex_state(struct ntsync_obj *mutex, + const struct ntsync_mutex_args *args) +{ + lockdep_assert_held(&mutex->lock); + + if (mutex->u.mutex.owner !=3D args->owner) + return -EPERM; + + if (!--mutex->u.mutex.count) + mutex->u.mutex.owner =3D 0; + return 0; +} + +static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_mutex_args __user *user_args =3D argp; + struct ntsync_mutex_args args; + struct ntsync_obj *mutex; + __u32 prev_count; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + if (!args.owner) + return -EINVAL; + + mutex =3D 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_nest_lock(&mutex->lock, &dev->wait_all_lock); + + prev_count =3D mutex->u.mutex.count; + ret =3D put_mutex_state(mutex, &args); + if (!ret) { + try_wake_all_obj(dev, mutex); + try_wake_any_mutex(mutex); + } + + spin_unlock(&mutex->lock); + spin_unlock(&dev->wait_all_lock); + } else { + spin_lock(&mutex->lock); + + prev_count =3D mutex->u.mutex.count; + ret =3D put_mutex_state(mutex, &args); + if (!ret) + try_wake_any_mutex(mutex); + + spin_unlock(&mutex->lock); + } + + put_obj(mutex); + + if (!ret && put_user(prev_count, &user_args->count)) + ret =3D -EFAULT; + + return ret; +} + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) { int ret =3D 0; @@ -738,6 +803,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed 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) =20 #endif --=20 2.43.0 From nobody Wed Dec 24 19:49:26 2025 Received: from mail.codeweavers.com (mail.codeweavers.com [4.36.192.163]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6971CBE69; Wed, 24 Jan 2024 00:58:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=4.36.192.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057931; cv=none; b=aFPmwHUxnewYEqfYlJe1QmLPlfW16+70cs8PzoIi59plcR42SdvaJRYrW0XnqjutpJ3pg+/Yv/6SQkQIlktLZTnJF7A/B3rtX8lJFX8kIz+rDwu0aTI2YgvITVmSRfTVKIBNYk8JS4Qt7XNI4vbVuJ3HCusDYkJYm4SpmhEwvtE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706057931; c=relaxed/simple; bh=L53s4XKugQkrOf4wmM10ZZtY0u5t5bfPYmQ5sniUf08=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aS7c4cZxpQTo5KdkZ2ubuGM2hkzukKB+V/bt3UaE3mtUffuWF92uuILtqM+ACnzJAoMuRpcVWmOyP9mwNsmozeu0+ATvFxf3rix91ahwAT93sTNqUiwxVevs6o49L5WpLJCtsc5PX41qHw6mWcyFAtYdvb852cA1MXU24I4btfE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com; spf=pass smtp.mailfrom=codeweavers.com; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b=NqaDxTmj; arc=none smtp.client-ip=4.36.192.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=codeweavers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=codeweavers.com header.i=@codeweavers.com header.b="NqaDxTmj" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=s1; h=Message-ID:Date:Subject:Cc:To:From:Sender; bh=B8C2ooCSc+NBhSvPUGlWB1ForKDdhBTvYMz91+iwYYc=; b=NqaDxTmjeEQD25eSN/50W62HSZ Ip3tzc4B99p+kiJnGG4moYcCYrHf6ylTC9sC8tsfbRfJ9REIkLjaK7idJnz3tYGRN4obzWh6IhgkL vG9NPIQIS/nKADUqkbPle4Dk1IaZl/3JsGnc+jQy+U+EpKYEQ3/yl+xwKWBNazd8qwTtqcara6cW2 OCGv/QdsXDs6r/lxzlPo9je68MvbtV4iVOmO8jdEpaGIb46uK8OVAoNDEsCUAPkthyxN1wTI81yRJ t4W4MP/76sk5k0f31yPXhfEshycKBNwPosxqnExeSe4Jl8fsvs/sEO2OmNl5OeTokjch1g+j/2E3S zvws5ZzQ==; Received: from cw137ip160.mn.codeweavers.com ([10.69.137.160] helo=camazotz.mn.codeweavers.com) by mail.codeweavers.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rSRLC-00DVeW-1Z; Tue, 23 Jan 2024 18:42:06 -0600 From: Elizabeth Figura To: Arnd Bergmann , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org Cc: wine-devel@winehq.org, =?UTF-8?q?Andr=C3=A9=20Almeida?= , Wolfram Sang , Arkadiusz Hiler , Peter Zijlstra , Elizabeth Figura Subject: [RFC PATCH 9/9] ntsync: Introduce NTSYNC_IOC_KILL_OWNER. Date: Tue, 23 Jan 2024 18:40:28 -0600 Message-ID: <20240124004028.16826-10-zfigura@codeweavers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240124004028.16826-1-zfigura@codeweavers.com> References: <20240124004028.16826-1-zfigura@codeweavers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This does not correspond to any NT syscall, but rather should be called by = the user-space NT emulator when a thread dies. It is responsible for marking any mutexes owned by that thread as abandoned. Signed-off-by: Elizabeth Figura --- drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++- include/uapi/linux/ntsync.h | 1 + 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 28f43768d1c3..1173c750c106 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -64,6 +64,7 @@ struct ntsync_obj { struct { __u32 count; __u32 owner; + bool ownerdead; } mutex; } u; }; @@ -87,6 +88,7 @@ struct ntsync_q { atomic_t signaled; =20 bool all; + bool ownerdead; __u32 count; struct ntsync_q_entry entries[]; }; @@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, str= uct ntsync_q *q, obj->u.sem.count--; break; case NTSYNC_TYPE_MUTEX: + if (obj->u.mutex.ownerdead) + q->ownerdead =3D true; + obj->u.mutex.ownerdead =3D false; obj->u.mutex.count++; obj->u.mutex.owner =3D q->owner; break; @@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) continue; =20 if (atomic_cmpxchg(&q->signaled, -1, entry->index) =3D=3D -1) { + if (mutex->u.mutex.ownerdead) + q->ownerdead =3D true; + mutex->u.mutex.ownerdead =3D false; mutex->u.mutex.count++; mutex->u.mutex.owner =3D q->owner; wake_up_process(q->task); @@ -514,6 +522,71 @@ static int ntsync_put_mutex(struct ntsync_device *dev,= void __user *argp) return ret; } =20 +/* + * Actually change the mutex state to mark its owner as dead. + */ +static void put_mutex_ownerdead_state(struct ntsync_obj *mutex) +{ + lockdep_assert_held(&mutex->lock); + + mutex->u.mutex.ownerdead =3D true; + mutex->u.mutex.owner =3D 0; + mutex->u.mutex.count =3D 0; +} + +static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_obj *obj; + unsigned long id; + __u32 owner; + + if (get_user(owner, (__u32 __user *)argp)) + return -EFAULT; + if (!owner) + return -EINVAL; + + rcu_read_lock(); + + xa_for_each(&dev->objects, id, obj) { + if (!kref_get_unless_zero(&obj->refcount)) + continue; + + if (obj->type !=3D NTSYNC_TYPE_MUTEX) { + put_obj(obj); + continue; + } + + if (atomic_read(&obj->all_hint) > 0) { + spin_lock(&dev->wait_all_lock); + spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); + + if (obj->u.mutex.owner =3D=3D owner) { + put_mutex_ownerdead_state(obj); + try_wake_all_obj(dev, obj); + try_wake_any_mutex(obj); + } + + spin_unlock(&obj->lock); + spin_unlock(&dev->wait_all_lock); + } else { + spin_lock(&obj->lock); + + if (obj->u.mutex.owner =3D=3D owner) { + put_mutex_ownerdead_state(obj); + try_wake_any_mutex(obj); + } + + spin_unlock(&obj->lock); + } + + put_obj(obj); + } + + rcu_read_unlock(); + + return 0; +} + static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) { int ret =3D 0; @@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev, q->owner =3D args->owner; atomic_set(&q->signaled, -1); q->all =3D all; + q->ownerdead =3D false; q->count =3D count; =20 for (i =3D 0; i < count; i++) { @@ -697,7 +771,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, v= oid __user *argp) struct ntsync_wait_args __user *user_args =3D argp; =20 /* even if we caught a signal, we need to communicate success */ - ret =3D 0; + ret =3D q->ownerdead ? -EOWNERDEAD : 0; =20 if (put_user(signaled, &user_args->index)) ret =3D -EFAULT; @@ -778,7 +852,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, v= oid __user *argp) struct ntsync_wait_args __user *user_args =3D argp; =20 /* even if we caught a signal, we need to communicate success */ - ret =3D 0; + ret =3D q->ownerdead ? -EOWNERDEAD : 0; =20 if (put_user(signaled, &user_args->index)) ret =3D -EFAULT; @@ -803,6 +877,8 @@ static long ntsync_char_ioctl(struct file *file, unsign= ed 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) =20 #endif --=20 2.43.0