diff options
author | Matteo De Carlo | 2021-11-18 11:53:12 +0100 |
---|---|---|
committer | Matteo De Carlo | 2021-11-18 11:53:12 +0100 |
commit | 2ebb568529d8e9e397a8e903d5d939dd9d200abe (patch) | |
tree | cb54b4c54a07f67dad1916050c0a819dbbb9875a | |
parent | 369d0a009322715c647adc417a5e110876a822ae (diff) | |
download | aur-2ebb568529d8e9e397a8e903d5d939dd9d200abe.tar.gz |
update to 5.15.2
-rw-r--r-- | .SRCINFO | 22 | ||||
-rw-r--r-- | PKGBUILD | 19 | ||||
-rw-r--r-- | config | 346 | ||||
-rw-r--r-- | futex2-tkg.patch | 4327 |
4 files changed, 219 insertions, 4495 deletions
@@ -1,8 +1,8 @@ pkgbase = linux-covolunablu-gaming pkgdesc = Linux - pkgver = 5.14.16.arch1 + pkgver = 5.15.2.arch1 pkgrel = 1 - url = https://github.com/archlinux/linux/commits/v5.14.16-arch1 + url = https://github.com/archlinux/linux/commits/v5.15.2-arch1 arch = x86_64 license = GPL2 makedepends = bc @@ -20,25 +20,25 @@ pkgbase = linux-covolunablu-gaming makedepends = imagemagick makedepends = git options = !strip - source = archlinux-linux::git+https://github.com/archlinux/linux?signed#tag=v5.14.16-arch1 + source = archlinux-linux::git+https://github.com/archlinux/linux?signed#tag=v5.15.2-arch1 source = config source = bfq-default.patch - source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-fsync.patch - source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-futex2_interface.patch - source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-winesync.patch + source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/ba636511f4862466b11ea69264cab70b7ccb3459/linux-tkg-patches/5.15/0007-v5.15-futex_waitv.patch + source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/ba636511f4862466b11ea69264cab70b7ccb3459/linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch + source = https://raw.githubusercontent.com/Frogging-Family/linux-tkg/ba636511f4862466b11ea69264cab70b7ccb3459/linux-tkg-patches/5.15/0007-v5.15-winesync.patch validpgpkeys = ABAF11C65A2970B130ABE3C479BE3E4300411886 validpgpkeys = 647F28654894E3BD457199BE38DBBDC86092693E validpgpkeys = A2FF3A36AAA56654109064AB19802F8B0D70FC30 validpgpkeys = C7E7849466FE2358343588377258734B41C31549 sha256sums = SKIP - sha256sums = 29f1d67f358a610e9fe821e27c5a093a192a38c57b1c9d531476da636234de79 + sha256sums = d75d9ebddf7b9146a15b17ce2a46933333c3584a4cd39175328e44e5bb0b59af sha256sums = f6701a4b9ed60ad98396606a4c7db26c7197e76d00a28f5299d2567bf6d17d3d - sha256sums = aa67e81a27d9062e463594acb91eca6dd13388f23cbe53ca56298f9dba61cc10 - sha256sums = efe5e21706fdf64559ead866c85a5d88c5c3f743d814410df3810ca61cc5b966 - sha256sums = 034d12a73b507133da2c69a34d61efd2f6b6618549650aa26d748142d22002e1 + sha256sums = c8f7c50d9b1418ba22b5ca735c47111a162be416109714d26a674162e5b2cb97 + sha256sums = 63a2ddf7ca9d3922f4eac3ac66bc37ffb10ad8b18b3e596832d3faa66b93dfa6 + sha256sums = a71ea523f0a7bcd24e2ad144ff12160aa03dc3f0c64daceac8dc1aae523d4491 pkgname = linux-covolunablu-gaming - pkgdesc = The Linux kernel and modules; it includes BFQ as default scheduler and Valve futex2 patches. + pkgdesc = The Linux kernel and modules; it includes BFQ as default scheduler and Valve futex2 patches. Thanks to linux-tkg for the futex patches. depends = coreutils depends = kmod depends = initramfs @@ -3,10 +3,11 @@ # Contributor: Jan Alexander Steffens (heftig) <jan dot steffens at gmail dot com> pkgbase=linux-covolunablu-gaming -pkgver=5.14.16.arch1 +pkgver=5.15.2.arch1 pkgrel=1 pkgdesc='Linux' _srctag=v${pkgver%.*}-${pkgver##*.} +_linux_tkg_commit="ba636511f4862466b11ea69264cab70b7ccb3459" url="https://github.com/archlinux/linux/commits/$_srctag" arch=(x86_64) license=(GPL2) @@ -21,9 +22,9 @@ source=( "$_srcname::git+https://github.com/archlinux/linux?signed#tag=$_srctag" config # the main kernel config file bfq-default.patch - 'https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-fsync.patch' - 'https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-futex2_interface.patch' - 'https://raw.githubusercontent.com/Frogging-Family/linux-tkg/67c26a6228341deb4a85484e50971897dc93d841/linux-tkg-patches/5.14/0007-v5.14-winesync.patch' + "https://raw.githubusercontent.com/Frogging-Family/linux-tkg/${_linux_tkg_commit}/linux-tkg-patches/5.15/0007-v5.15-futex_waitv.patch" + "https://raw.githubusercontent.com/Frogging-Family/linux-tkg/${_linux_tkg_commit}/linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch" + "https://raw.githubusercontent.com/Frogging-Family/linux-tkg/${_linux_tkg_commit}/linux-tkg-patches/5.15/0007-v5.15-winesync.patch" ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds @@ -32,12 +33,12 @@ validpgpkeys=( 'C7E7849466FE2358343588377258734B41C31549' # David Runge <dvzrv@archlinux.org> ) sha256sums=('SKIP' - '29f1d67f358a610e9fe821e27c5a093a192a38c57b1c9d531476da636234de79' + 'd75d9ebddf7b9146a15b17ce2a46933333c3584a4cd39175328e44e5bb0b59af' # -- covolunablu-gaming patches -- 'f6701a4b9ed60ad98396606a4c7db26c7197e76d00a28f5299d2567bf6d17d3d' - 'aa67e81a27d9062e463594acb91eca6dd13388f23cbe53ca56298f9dba61cc10' - 'efe5e21706fdf64559ead866c85a5d88c5c3f743d814410df3810ca61cc5b966' - '034d12a73b507133da2c69a34d61efd2f6b6618549650aa26d748142d22002e1' + 'c8f7c50d9b1418ba22b5ca735c47111a162be416109714d26a674162e5b2cb97' + '63a2ddf7ca9d3922f4eac3ac66bc37ffb10ad8b18b3e596832d3faa66b93dfa6' + 'a71ea523f0a7bcd24e2ad144ff12160aa03dc3f0c64daceac8dc1aae523d4491' ) export KBUILD_BUILD_HOST=covolunablu @@ -76,7 +77,7 @@ build() { } _package() { - pkgdesc="The $pkgdesc kernel and modules; it includes BFQ as default scheduler and Valve futex2 patches." + pkgdesc="The $pkgdesc kernel and modules; it includes BFQ as default scheduler and Valve futex2 patches. Thanks to linux-tkg for the futex patches." depends=(coreutils kmod initramfs) optdepends=('crda: to set the correct wireless channels of your country' 'linux-firmware: firmware images needed for some devices') @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 5.14.12-arch1 Kernel Configuration +# Linux/x86 5.15.2-arch1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 11.1.0" CONFIG_CC_IS_GCC=y @@ -26,6 +26,7 @@ CONFIG_THREAD_INFO_IN_TASK=y # CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_COMPILE_TEST is not set +# CONFIG_WERROR is not set CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_BUILD_SALT="" @@ -179,6 +180,7 @@ CONFIG_IKHEADERS=m CONFIG_LOG_BUF_SHIFT=17 CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_PRINTK_INDEX=y CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y # @@ -256,7 +258,6 @@ CONFIG_SYSFS_SYSCALL=y CONFIG_FHANDLE=y CONFIG_POSIX_TIMERS=y CONFIG_PRINTK=y -CONFIG_PRINTK_NMI=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y @@ -331,6 +332,7 @@ CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_NR_GPIO=1024 CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_ARCH_WANT_GENERAL_HUGETLB=y CONFIG_AUDIT_ARCH=y @@ -369,13 +371,14 @@ CONFIG_XEN=y CONFIG_XEN_PV=y CONFIG_XEN_512GB=y CONFIG_XEN_PV_SMP=y -CONFIG_XEN_DOM0=y +CONFIG_XEN_PV_DOM0=y CONFIG_XEN_PVHVM=y CONFIG_XEN_PVHVM_SMP=y CONFIG_XEN_PVHVM_GUEST=y CONFIG_XEN_SAVE_RESTORE=y # CONFIG_XEN_DEBUG_FS is not set CONFIG_XEN_PVH=y +CONFIG_XEN_DOM0=y CONFIG_KVM_GUEST=y CONFIG_ARCH_CPUIDLE_HALTPOLL=y CONFIG_PVH=y @@ -431,6 +434,7 @@ CONFIG_PERF_EVENTS_INTEL_UNCORE=m CONFIG_PERF_EVENTS_INTEL_RAPL=m CONFIG_PERF_EVENTS_INTEL_CSTATE=m CONFIG_PERF_EVENTS_AMD_POWER=m +CONFIG_PERF_EVENTS_AMD_UNCORE=m # end of Performance monitoring CONFIG_X86_16BIT=y @@ -674,7 +678,6 @@ CONFIG_PCI_XEN=y CONFIG_MMCONF_FAM10H=y CONFIG_ISA_DMA_API=y CONFIG_AMD_NB=y -# CONFIG_X86_SYSFB is not set # end of Bus options (PCI etc.) # @@ -688,62 +691,6 @@ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y CONFIG_SYSVIPC_COMPAT=y # end of Binary Emulations -# -# Firmware Drivers -# -CONFIG_EDD=m -# CONFIG_EDD_OFF is not set -CONFIG_FIRMWARE_MEMMAP=y -CONFIG_DMIID=y -CONFIG_DMI_SYSFS=y -CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y -CONFIG_ISCSI_IBFT_FIND=y -CONFIG_ISCSI_IBFT=m -CONFIG_FW_CFG_SYSFS=m -# CONFIG_FW_CFG_SYSFS_CMDLINE is not set -CONFIG_GOOGLE_FIRMWARE=y -# CONFIG_GOOGLE_SMI is not set -CONFIG_GOOGLE_COREBOOT_TABLE=m -CONFIG_GOOGLE_MEMCONSOLE=m -# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set -CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT=m -CONFIG_GOOGLE_MEMCONSOLE_COREBOOT=m -CONFIG_GOOGLE_VPD=m - -# -# EFI (Extensible Firmware Interface) Support -# -# CONFIG_EFI_VARS is not set -CONFIG_EFI_ESRT=y -CONFIG_EFI_VARS_PSTORE=y -CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=y -CONFIG_EFI_RUNTIME_MAP=y -# CONFIG_EFI_FAKE_MEMMAP is not set -CONFIG_EFI_SOFT_RESERVE=y -CONFIG_EFI_RUNTIME_WRAPPERS=y -CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y -CONFIG_EFI_BOOTLOADER_CONTROL=m -CONFIG_EFI_CAPSULE_LOADER=m -# CONFIG_EFI_TEST is not set -CONFIG_APPLE_PROPERTIES=y -# CONFIG_RESET_ATTACK_MITIGATION is not set -CONFIG_EFI_RCI2_TABLE=y -# CONFIG_EFI_DISABLE_PCI_DMA is not set -# end of EFI (Extensible Firmware Interface) Support - -CONFIG_EFI_EMBEDDED_FIRMWARE=y -CONFIG_UEFI_CPER=y -CONFIG_UEFI_CPER_X86=y -CONFIG_EFI_DEV_PATH_PARSER=y -CONFIG_EFI_EARLYCON=y -CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y - -# -# Tegra firmware driver -# -# end of Tegra firmware driver -# end of Firmware Drivers - CONFIG_HAVE_KVM=y CONFIG_HAVE_KVM_IRQCHIP=y CONFIG_HAVE_KVM_IRQFD=y @@ -798,6 +745,7 @@ CONFIG_HAVE_OPTPROBES=y CONFIG_HAVE_KPROBES_ON_FTRACE=y CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y CONFIG_HAVE_NMI=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HAVE_ARCH_TRACEHOOK=y CONFIG_HAVE_DMA_CONTIGUOUS=y CONFIG_GENERIC_SMP_IDLE_THREAD=y @@ -887,6 +835,7 @@ CONFIG_HAVE_PREEMPT_DYNAMIC=y CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y CONFIG_ARCH_HAS_ELFCORE_COMPAT=y +CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y # # GCOV-based kernel profiling @@ -928,16 +877,14 @@ CONFIG_MODPROBE_PATH="/sbin/modprobe" CONFIG_MODULES_TREE_LOOKUP=y CONFIG_BLOCK=y CONFIG_BLK_RQ_ALLOC_TIME=y -CONFIG_BLK_SCSI_REQUEST=y CONFIG_BLK_CGROUP_RWSTAT=y -CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSG_COMMON=y CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_INTEGRITY_T10=y CONFIG_BLK_DEV_ZONED=y CONFIG_BLK_DEV_THROTTLING=y CONFIG_BLK_DEV_THROTTLING_LOW=y -# CONFIG_BLK_CMDLINE_PARSER is not set CONFIG_BLK_WBT=y CONFIG_BLK_WBT_MQ=y CONFIG_BLK_CGROUP_IOLATENCY=y @@ -981,6 +928,7 @@ CONFIG_BLK_MQ_PCI=y CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_MQ_RDMA=y CONFIG_BLK_PM=y +CONFIG_BLOCK_HOLDER_DEPRECATED=y # # IO Schedulers @@ -1092,6 +1040,7 @@ CONFIG_ZSMALLOC=y # CONFIG_ZSMALLOC_STAT is not set CONFIG_GENERIC_EARLY_IOREMAP=y # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +CONFIG_PAGE_IDLE_FLAG=y CONFIG_IDLE_PAGE_TRACKING=y CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y CONFIG_ARCH_HAS_PTE_DEVMAP=y @@ -1110,6 +1059,12 @@ CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_ARCH_HAS_PTE_SPECIAL=y CONFIG_MAPPING_DIRTY_HELPERS=y CONFIG_SECRETMEM=y + +# +# Data Access Monitoring +# +# CONFIG_DAMON is not set +# end of Data Access Monitoring # end of Memory Management options CONFIG_NET=y @@ -1126,6 +1081,7 @@ CONFIG_PACKET=y CONFIG_PACKET_DIAG=m CONFIG_UNIX=y CONFIG_UNIX_SCM=y +CONFIG_AF_UNIX_OOB=y CONFIG_UNIX_DIAG=m CONFIG_TLS=m CONFIG_TLS_DEVICE=y @@ -1236,6 +1192,7 @@ CONFIG_IPV6_SEG6_LWTUNNEL=y CONFIG_IPV6_SEG6_HMAC=y CONFIG_IPV6_SEG6_BPF=y CONFIG_IPV6_RPL_LWTUNNEL=y +CONFIG_IPV6_IOAM6_LWTUNNEL=y CONFIG_NETLABEL=y CONFIG_MPTCP=y CONFIG_INET_MPTCP_DIAG=m @@ -2008,6 +1965,7 @@ CONFIG_AF_RXRPC_DEBUG=y CONFIG_RXKAD=y CONFIG_AF_KCM=m CONFIG_STREAM_PARSER=y +CONFIG_MCTP=m CONFIG_FIB_RULES=y CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -2280,6 +2238,70 @@ CONFIG_MHI_BUS_PCI_GENERIC=m CONFIG_CONNECTOR=y CONFIG_PROC_EVENTS=y + +# +# Firmware Drivers +# + +# +# ARM System Control and Management Interface Protocol +# +# end of ARM System Control and Management Interface Protocol + +CONFIG_EDD=m +# CONFIG_EDD_OFF is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +CONFIG_DMI_SYSFS=y +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +CONFIG_ISCSI_IBFT_FIND=y +CONFIG_ISCSI_IBFT=m +CONFIG_FW_CFG_SYSFS=m +# CONFIG_FW_CFG_SYSFS_CMDLINE is not set +CONFIG_SYSFB=y +# CONFIG_SYSFB_SIMPLEFB is not set +CONFIG_GOOGLE_FIRMWARE=y +# CONFIG_GOOGLE_SMI is not set +CONFIG_GOOGLE_COREBOOT_TABLE=m +CONFIG_GOOGLE_MEMCONSOLE=m +# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set +CONFIG_GOOGLE_MEMCONSOLE_COREBOOT=m +CONFIG_GOOGLE_VPD=m + +# +# EFI (Extensible Firmware Interface) Support +# +# CONFIG_EFI_VARS is not set +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=y +CONFIG_EFI_RUNTIME_MAP=y +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_SOFT_RESERVE=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +# CONFIG_EFI_TEST is not set +CONFIG_APPLE_PROPERTIES=y +# CONFIG_RESET_ATTACK_MITIGATION is not set +CONFIG_EFI_RCI2_TABLE=y +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EMBEDDED_FIRMWARE=y +CONFIG_UEFI_CPER=y +CONFIG_UEFI_CPER_X86=y +CONFIG_EFI_DEV_PATH_PARSER=y +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + CONFIG_GNSS=m CONFIG_GNSS_SERIAL=m CONFIG_GNSS_MTK_SERIAL=m @@ -2302,6 +2324,10 @@ CONFIG_MTD=m CONFIG_MTD_BLKDEVS=m CONFIG_MTD_BLOCK=m # CONFIG_MTD_BLOCK_RO is not set + +# +# Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK. +# # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set @@ -2571,6 +2597,7 @@ CONFIG_PVPANIC_PCI=m # CONFIG_SCSI_MOD=y CONFIG_RAID_ATTRS=m +CONFIG_SCSI_COMMON=y CONFIG_SCSI=y CONFIG_SCSI_DMA=y CONFIG_SCSI_NETLINK=y @@ -2583,6 +2610,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=m +CONFIG_BLK_DEV_BSG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m CONFIG_SCSI_CONSTANTS=y @@ -2657,6 +2685,7 @@ CONFIG_SCSI_UFS_CDNS_PLATFORM=m # CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set CONFIG_SCSI_UFS_BSG=y CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_HPB=y CONFIG_SCSI_HPTIOP=m CONFIG_SCSI_BUSLOGIC=m CONFIG_SCSI_FLASHPOINT=y @@ -3165,6 +3194,7 @@ CONFIG_IGC=m CONFIG_NET_VENDOR_MICROSOFT=y CONFIG_MICROSOFT_MANA=m CONFIG_JME=m +CONFIG_NET_VENDOR_LITEX=y CONFIG_NET_VENDOR_MARVELL=y CONFIG_MVMDIO=m CONFIG_SKGE=m @@ -3382,6 +3412,7 @@ CONFIG_LSI_ET1011C_PHY=m CONFIG_MARVELL_PHY=m CONFIG_MARVELL_10G_PHY=m CONFIG_MARVELL_88X2222_PHY=m +CONFIG_MAXLINEAR_GPHY=m CONFIG_MEDIATEK_GE_PHY=m CONFIG_MICREL_PHY=m CONFIG_MICROCHIP_PHY=m @@ -3407,6 +3438,10 @@ CONFIG_DP83869_PHY=m CONFIG_VITESSE_PHY=m CONFIG_XILINX_GMII2RGMII=m CONFIG_MICREL_KS8995MA=m + +# +# MCTP Device Drivers +# CONFIG_MDIO_DEVICE=m CONFIG_MDIO_BUS=m CONFIG_FWNODE_MDIO=m @@ -3667,7 +3702,6 @@ CONFIG_P54_PCI=m CONFIG_P54_SPI=m # CONFIG_P54_SPI_DEFAULT_EEPROM is not set CONFIG_P54_LEDS=y -CONFIG_PRISM54=m CONFIG_WLAN_VENDOR_MARVELL=y CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m @@ -3829,6 +3863,7 @@ CONFIG_IEEE802154_HWSIM=m CONFIG_WWAN=y CONFIG_WWAN_HWSIM=m CONFIG_MHI_WWAN_CTRL=m +CONFIG_MHI_WWAN_MBIM=m CONFIG_RPMSG_WWAN_CTRL=m CONFIG_IOSM=m # end of Wireless WAN @@ -3863,9 +3898,6 @@ CONFIG_MISDN_NETJET=m CONFIG_MISDN_HDLC=m CONFIG_MISDN_IPAC=m CONFIG_MISDN_ISAR=m -CONFIG_NVM=y -CONFIG_NVM_PBLK=m -# CONFIG_NVM_PBLK_DEBUG is not set # # Input device support @@ -4355,10 +4387,9 @@ CONFIG_XILLYBUS_CLASS=m CONFIG_XILLYBUS=m CONFIG_XILLYBUS_PCIE=m CONFIG_XILLYUSB=m -# end of Character devices - # CONFIG_RANDOM_TRUST_CPU is not set # CONFIG_RANDOM_TRUST_BOOTLOADER is not set +# end of Character devices # # I2C support @@ -4383,7 +4414,7 @@ CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_HELPER_AUTO=y CONFIG_I2C_SMBUS=m -CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOBIT=y CONFIG_I2C_ALGOPCA=m # @@ -4454,6 +4485,7 @@ CONFIG_I2C_VIPERBOARD=m # CONFIG_I2C_MLXCPLD=m CONFIG_I2C_CROS_EC_TUNNEL=m +CONFIG_I2C_VIRTIO=m # end of I2C Hardware Bus support CONFIG_I2C_STUB=m @@ -4538,6 +4570,7 @@ CONFIG_PPS_CLIENT_GPIO=m # PTP clock support # CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y CONFIG_DP83640_PHY=m CONFIG_PTP_1588_CLOCK_INES=m CONFIG_PTP_1588_CLOCK_KVM=m @@ -4700,6 +4733,7 @@ CONFIG_GPIO_VIPERBOARD=m # CONFIG_GPIO_AGGREGATOR=m CONFIG_GPIO_MOCKUP=m +CONFIG_GPIO_VIRTIO=m # end of Virtual GPIO drivers CONFIG_W1=m @@ -4744,6 +4778,7 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_ATC260X=m CONFIG_POWER_RESET_MT6323=y CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_TPS65086=y CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set CONFIG_POWER_SUPPLY_HWMON=y @@ -4798,6 +4833,7 @@ CONFIG_CHARGER_MAX77693=m CONFIG_CHARGER_MAX8997=m CONFIG_CHARGER_MAX8998=m CONFIG_CHARGER_MP2629=m +CONFIG_CHARGER_MT6360=m CONFIG_CHARGER_BQ2415X=m CONFIG_CHARGER_BQ24190=m CONFIG_CHARGER_BQ24257=m @@ -4813,6 +4849,7 @@ CONFIG_BATTERY_GOLDFISH=m CONFIG_BATTERY_RT5033=m CONFIG_CHARGER_RT9455=m CONFIG_CHARGER_CROS_USBPD=m +CONFIG_CHARGER_CROS_PCHG=m CONFIG_CHARGER_BD99954=m CONFIG_CHARGER_WILCO=m CONFIG_BATTERY_SURFACE=m @@ -4844,6 +4881,7 @@ CONFIG_SENSORS_ADT7462=m CONFIG_SENSORS_ADT7470=m CONFIG_SENSORS_ADT7475=m CONFIG_SENSORS_AHT10=m +CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m CONFIG_SENSORS_AS370=m CONFIG_SENSORS_ASC7621=m CONFIG_SENSORS_AXI_FAN_CONTROL=m @@ -4983,6 +5021,7 @@ CONFIG_SENSORS_UCD9200=m CONFIG_SENSORS_XDPE122=m CONFIG_SENSORS_ZL6100=m CONFIG_SENSORS_SBTSI=m +CONFIG_SENSORS_SBRMI=m CONFIG_SENSORS_SHT15=m CONFIG_SENSORS_SHT21=m CONFIG_SENSORS_SHT3x=m @@ -5080,6 +5119,7 @@ CONFIG_PROC_THERMAL_MMIO_RAPL=m CONFIG_INTEL_BXT_PMIC_THERMAL=m CONFIG_INTEL_PCH_THERMAL=m CONFIG_INTEL_TCC_COOLING=m +CONFIG_INTEL_MENLOW=m # end of Intel thermal drivers CONFIG_GENERIC_ADC_THERMAL=m @@ -5399,7 +5439,9 @@ CONFIG_REGULATOR_RT4831=m CONFIG_REGULATOR_RT5033=m CONFIG_REGULATOR_RT6160=m CONFIG_REGULATOR_RT6245=m +CONFIG_REGULATOR_RTQ2134=m CONFIG_REGULATOR_RTMV20=m +CONFIG_REGULATOR_RTQ6752=m CONFIG_REGULATOR_SKY81452=m CONFIG_REGULATOR_SLG51000=m CONFIG_REGULATOR_TPS51632=m @@ -5457,7 +5499,7 @@ CONFIG_IR_SERIAL_TRANSMITTER=y CONFIG_IR_SIR=m CONFIG_RC_XBOX_DVD=m CONFIG_IR_TOY=m -CONFIG_CEC_CORE=m +CONFIG_CEC_CORE=y CONFIG_CEC_NOTIFIER=y CONFIG_CEC_PIN=y CONFIG_MEDIA_CEC_RC=y @@ -5708,8 +5750,7 @@ CONFIG_VIDEO_TW686X=m # CONFIG_VIDEO_IVTV=m CONFIG_VIDEO_IVTV_ALSA=m -CONFIG_VIDEO_FB_IVTV=m -# CONFIG_VIDEO_FB_IVTV_FORCE_PAT is not set +# CONFIG_VIDEO_FB_IVTV is not set CONFIG_VIDEO_HEXIUM_GEMINI=m CONFIG_VIDEO_HEXIUM_ORION=m CONFIG_VIDEO_MXB=m @@ -6186,7 +6227,7 @@ CONFIG_DVB_DUMMY_FE=m # # Graphics support # -CONFIG_AGP=m +CONFIG_AGP=y CONFIG_AGP_AMD64=m CONFIG_AGP_INTEL=m CONFIG_AGP_SIS=m @@ -6195,12 +6236,13 @@ CONFIG_INTEL_GTT=m CONFIG_VGA_ARB=y CONFIG_VGA_ARB_MAX_GPUS=10 CONFIG_VGA_SWITCHEROO=y -CONFIG_DRM=m +CONFIG_DRM=y CONFIG_DRM_MIPI_DBI=m CONFIG_DRM_MIPI_DSI=y CONFIG_DRM_DP_AUX_CHARDEV=y +# CONFIG_DRM_DEBUG_MM is not set # CONFIG_DRM_DEBUG_SELFTEST is not set -CONFIG_DRM_KMS_HELPER=m +CONFIG_DRM_KMS_HELPER=y CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_LOAD_EDID_FIRMWARE=y @@ -6279,12 +6321,12 @@ CONFIG_DRM_VGEM=m CONFIG_DRM_VKMS=m CONFIG_DRM_VMWGFX=m CONFIG_DRM_VMWGFX_FBCON=y +CONFIG_DRM_VMWGFX_MKSSTATS=y CONFIG_DRM_GMA500=m CONFIG_DRM_UDL=m CONFIG_DRM_AST=m CONFIG_DRM_MGAG200=m CONFIG_DRM_QXL=m -CONFIG_DRM_BOCHS=m CONFIG_DRM_VIRTIO_GPU=m CONFIG_DRM_PANEL=y @@ -6292,6 +6334,7 @@ CONFIG_DRM_PANEL=y # Display Panels # CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +CONFIG_DRM_PANEL_WIDECHIPS_WS2401=m # end of Display Panels CONFIG_DRM_BRIDGE=y @@ -6305,9 +6348,10 @@ CONFIG_DRM_ANALOGIX_DP=m # end of Display Interface Bridges # CONFIG_DRM_ETNAVIV is not set +CONFIG_DRM_BOCHS=m CONFIG_DRM_CIRRUS_QEMU=m CONFIG_DRM_GM12U320=m -CONFIG_DRM_SIMPLEDRM=m +CONFIG_DRM_SIMPLEDRM=y CONFIG_TINYDRM_HX8357D=m CONFIG_TINYDRM_ILI9225=m CONFIG_TINYDRM_ILI9341=m @@ -6335,11 +6379,11 @@ CONFIG_FB_BOOT_VESA_SUPPORT=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SYS_FILLRECT=m -CONFIG_FB_SYS_COPYAREA=m -CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y # CONFIG_FB_FOREIGN_ENDIAN is not set -CONFIG_FB_SYS_FOPS=m +CONFIG_FB_SYS_FOPS=y CONFIG_FB_DEFERRED_IO=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y @@ -6354,7 +6398,7 @@ CONFIG_FB_TILEBLITTING=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set # CONFIG_FB_VGA16 is not set -CONFIG_FB_UVESA=m +# CONFIG_FB_UVESA is not set CONFIG_FB_VESA=y CONFIG_FB_EFI=y # CONFIG_FB_N411 is not set @@ -6387,11 +6431,10 @@ CONFIG_FB_EFI=y # CONFIG_FB_UDL is not set # CONFIG_FB_IBM_GXT4500 is not set # CONFIG_FB_VIRTUAL is not set -CONFIG_XEN_FBDEV_FRONTEND=m +# CONFIG_XEN_FBDEV_FRONTEND is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set # CONFIG_FB_HYPERV is not set -CONFIG_FB_SIMPLE=m # CONFIG_FB_SSD1307 is not set # CONFIG_FB_SM712 is not set # end of Frame buffer Devices @@ -6615,6 +6658,7 @@ CONFIG_SND_HDA_CODEC_SIGMATEL=m CONFIG_SND_HDA_CODEC_VIA=m CONFIG_SND_HDA_CODEC_HDMI=m CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CS8409=m CONFIG_SND_HDA_CODEC_CONEXANT=m CONFIG_SND_HDA_CODEC_CA0110=m CONFIG_SND_HDA_CODEC_CA0132=m @@ -6683,6 +6727,7 @@ CONFIG_SND_SOC_AMD_ACP3x=m CONFIG_SND_SOC_AMD_RV_RT5682_MACH=m CONFIG_SND_SOC_AMD_RENOIR=m CONFIG_SND_SOC_AMD_RENOIR_MACH=m +CONFIG_SND_SOC_AMD_ACP5x=m CONFIG_SND_ATMEL_SOC=m # CONFIG_SND_BCM63XX_I2S_WHISTLER is not set CONFIG_SND_DESIGNWARE_I2S=m @@ -6811,7 +6856,6 @@ CONFIG_SND_SOC_SOF_ALDERLAKE=m CONFIG_SND_SOC_SOF_HDA_COMMON=m CONFIG_SND_SOC_SOF_HDA_LINK=y CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y -# CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 is not set CONFIG_SND_SOC_SOF_HDA_LINK_BASELINE=m CONFIG_SND_SOC_SOF_HDA=m CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE=m @@ -6897,6 +6941,7 @@ CONFIG_SND_SOC_ES8328_SPI=m CONFIG_SND_SOC_GTM601=m CONFIG_SND_SOC_HDAC_HDMI=m CONFIG_SND_SOC_HDAC_HDA=m +CONFIG_SND_SOC_ICS43432=m CONFIG_SND_SOC_INNO_RK3036=m CONFIG_SND_SOC_MAX98088=m CONFIG_SND_SOC_MAX98090=m @@ -6964,6 +7009,7 @@ CONFIG_SND_SOC_RT711_SDCA_SDW=m CONFIG_SND_SOC_RT715=m CONFIG_SND_SOC_RT715_SDW=m CONFIG_SND_SOC_RT715_SDCA_SDW=m +# CONFIG_SND_SOC_SDW_MOCKUP is not set CONFIG_SND_SOC_SGTL5000=m CONFIG_SND_SOC_SI476X=m CONFIG_SND_SOC_SIGMADSP=m @@ -7704,12 +7750,10 @@ CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y # CONFIG_LEDS_88PM860X=m CONFIG_LEDS_APU=m -CONFIG_LEDS_AS3645A=m CONFIG_LEDS_LM3530=m CONFIG_LEDS_LM3532=m CONFIG_LEDS_LM3533=m CONFIG_LEDS_LM3642=m -CONFIG_LEDS_LM3601X=m CONFIG_LEDS_MT6323=m CONFIG_LEDS_PCA9532=m CONFIG_LEDS_PCA9532_GPIO=y @@ -7751,12 +7795,14 @@ CONFIG_LEDS_NIC78BX=m CONFIG_LEDS_TI_LMU_COMMON=m CONFIG_LEDS_LM36274=m CONFIG_LEDS_TPS6105X=m -CONFIG_LEDS_SGM3140=m # # Flash and Torch LED drivers # +CONFIG_LEDS_AS3645A=m +CONFIG_LEDS_LM3601X=m CONFIG_LEDS_RT8515=m +CONFIG_LEDS_SGM3140=m # # LED Triggers @@ -8018,11 +8064,14 @@ CONFIG_DMA_VIRTUAL_CHANNELS=y CONFIG_DMA_ACPI=y CONFIG_ALTERA_MSGDMA=m CONFIG_INTEL_IDMA64=m +CONFIG_INTEL_IDXD_BUS=m CONFIG_INTEL_IDXD=m +# CONFIG_INTEL_IDXD_COMPAT is not set CONFIG_INTEL_IDXD_SVM=y CONFIG_INTEL_IDXD_PERFMON=y CONFIG_INTEL_IOATDMA=m CONFIG_PLX_DMA=m +CONFIG_AMD_PTDMA=m CONFIG_QCOM_HIDMA_MGMT=m CONFIG_QCOM_HIDMA=m CONFIG_DW_DMAC_CORE=y @@ -8051,30 +8100,14 @@ CONFIG_UDMABUF=y # CONFIG_DMABUF_DEBUG is not set # CONFIG_DMABUF_SELFTESTS is not set CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_SYSFS_STATS=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMABUF_HEAPS_CMA=y # end of DMABUF options CONFIG_DCA=m -CONFIG_AUXDISPLAY=y -CONFIG_CHARLCD=m -CONFIG_HD44780_COMMON=m -CONFIG_HD44780=m -CONFIG_KS0108=m -CONFIG_KS0108_PORT=0x378 -CONFIG_KS0108_DELAY=2 -CONFIG_CFAG12864B=m -CONFIG_CFAG12864B_RATE=20 -CONFIG_IMG_ASCII_LCD=m -CONFIG_LCD2S=m -CONFIG_PARPORT_PANEL=m -CONFIG_PANEL_PARPORT=0 -CONFIG_PANEL_PROFILE=5 -# CONFIG_PANEL_CHANGE_MESSAGE is not set -# CONFIG_CHARLCD_BL_OFF is not set -# CONFIG_CHARLCD_BL_ON is not set -CONFIG_CHARLCD_BL_FLASH=y -CONFIG_PANEL=m +# CONFIG_AUXDISPLAY is not set +# CONFIG_PANEL is not set CONFIG_UIO=m CONFIG_UIO_CIF=m CONFIG_UIO_PDRV_GENIRQ=m @@ -8087,14 +8120,15 @@ CONFIG_UIO_PRUSS=m CONFIG_UIO_MF624=m CONFIG_UIO_HV_GENERIC=m CONFIG_UIO_DFL=m +CONFIG_VFIO=m CONFIG_VFIO_IOMMU_TYPE1=m CONFIG_VFIO_VIRQFD=m -CONFIG_VFIO=m # CONFIG_VFIO_NOIOMMU is not set -CONFIG_VFIO_PCI=m -CONFIG_VFIO_PCI_VGA=y +CONFIG_VFIO_PCI_CORE=m CONFIG_VFIO_PCI_MMAP=y CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_VGA=y CONFIG_VFIO_PCI_IGD=y CONFIG_VFIO_MDEV=m CONFIG_IRQ_BYPASS_MANAGER=m @@ -8120,6 +8154,7 @@ CONFIG_VDPA=m CONFIG_VDPA_SIM=m CONFIG_VDPA_SIM_NET=m CONFIG_VDPA_SIM_BLOCK=m +CONFIG_VDPA_USER=m CONFIG_IFCVF=m CONFIG_MLX5_VDPA=y CONFIG_MLX5_VDPA_NET=m @@ -8305,8 +8340,6 @@ CONFIG_X86_PLATFORM_DEVICES=y CONFIG_ACPI_WMI=m CONFIG_WMI_BMOF=m CONFIG_HUAWEI_WMI=m -CONFIG_INTEL_WMI_SBL_FW_UPDATE=m -CONFIG_INTEL_WMI_THUNDERBOLT=m CONFIG_MXM_WMI=m CONFIG_PEAQ_WMI=m CONFIG_XIAOMI_WMI=m @@ -8321,6 +8354,7 @@ CONFIG_ASUS_LAPTOP=m CONFIG_ASUS_WIRELESS=m CONFIG_ASUS_WMI=m CONFIG_ASUS_NB_WMI=m +CONFIG_MERAKI_MX100=m CONFIG_EEEPC_LAPTOP=m CONFIG_EEEPC_WMI=m CONFIG_X86_PLATFORM_DRIVERS_DELL=y @@ -8358,14 +8392,38 @@ CONFIG_THINKPAD_ACPI_VIDEO=y CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y CONFIG_THINKPAD_LMI=m CONFIG_X86_PLATFORM_DRIVERS_INTEL=y +CONFIG_INTEL_ATOMISP2_PDX86=y +CONFIG_INTEL_ATOMISP2_LED=m +CONFIG_INTEL_SAR_INT1092=m CONFIG_INTEL_CHT_INT33FE=m CONFIG_INTEL_SKL_INT3472=m -CONFIG_INTEL_ATOMISP2_LED=m +CONFIG_INTEL_PMC_CORE=y +CONFIG_INTEL_PMT_CLASS=m +CONFIG_INTEL_PMT_TELEMETRY=m +CONFIG_INTEL_PMT_CRASHLOG=m + +# +# Intel Speed Select Technology interface support +# +CONFIG_INTEL_SPEED_SELECT_INTERFACE=m +# end of Intel Speed Select Technology interface support + +CONFIG_INTEL_TELEMETRY=m +CONFIG_INTEL_WMI=y +CONFIG_INTEL_WMI_SBL_FW_UPDATE=m +CONFIG_INTEL_WMI_THUNDERBOLT=m CONFIG_INTEL_HID_EVENT=m +CONFIG_INTEL_VBTN=m CONFIG_INTEL_INT0002_VGPIO=m -CONFIG_INTEL_MENLOW=m CONFIG_INTEL_OAKTRAIL=m -CONFIG_INTEL_VBTN=m +CONFIG_INTEL_BXTWC_PMIC_TMU=m +CONFIG_INTEL_CHTDC_TI_PWRBTN=m +CONFIG_INTEL_MRFLD_PWRBTN=m +CONFIG_INTEL_PUNIT_IPC=m +CONFIG_INTEL_RST=m +CONFIG_INTEL_SMARTCONNECT=m +CONFIG_INTEL_TURBO_MAX_3=y +CONFIG_INTEL_UNCORE_FREQ_CONTROL=m CONFIG_MSI_LAPTOP=m CONFIG_MSI_WMI=m CONFIG_PCENGINES_APU2=m @@ -8388,31 +8446,11 @@ CONFIG_MLX_PLATFORM=m CONFIG_TOUCHSCREEN_DMI=y CONFIG_FW_ATTR_CLASS=m CONFIG_INTEL_IPS=m -CONFIG_INTEL_RST=m -CONFIG_INTEL_SMARTCONNECT=m - -# -# Intel Speed Select Technology interface support -# -CONFIG_INTEL_SPEED_SELECT_INTERFACE=m -# end of Intel Speed Select Technology interface support - -CONFIG_INTEL_TURBO_MAX_3=y -CONFIG_INTEL_UNCORE_FREQ_CONTROL=m -CONFIG_INTEL_BXTWC_PMIC_TMU=m -CONFIG_INTEL_CHTDC_TI_PWRBTN=m -CONFIG_INTEL_MRFLD_PWRBTN=m -CONFIG_INTEL_PMC_CORE=y -CONFIG_INTEL_PMT_CLASS=m -CONFIG_INTEL_PMT_TELEMETRY=m -CONFIG_INTEL_PMT_CRASHLOG=m -CONFIG_INTEL_PUNIT_IPC=m CONFIG_INTEL_SCU_IPC=y CONFIG_INTEL_SCU=y CONFIG_INTEL_SCU_PCI=y CONFIG_INTEL_SCU_PLATFORM=m CONFIG_INTEL_SCU_IPC_UTIL=m -CONFIG_INTEL_TELEMETRY=m CONFIG_PMC_ATOM=y CONFIG_CHROME_PLATFORMS=y CONFIG_CHROMEOS_LAPTOP=m @@ -8503,6 +8541,8 @@ CONFIG_IOMMU_IO_PGTABLE=y # end of Generic IOMMU Pagetable Support # CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set +CONFIG_IOMMU_DEFAULT_DMA_LAZY=y # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set CONFIG_IOMMU_DMA=y CONFIG_IOMMU_SVA_LIB=y @@ -8799,6 +8839,7 @@ CONFIG_SCD30_CORE=m CONFIG_SCD30_I2C=m CONFIG_SCD30_SERIAL=m CONFIG_SENSIRION_SGP30=m +CONFIG_SENSIRION_SGP40=m CONFIG_SPS30=m CONFIG_SPS30_I2C=m CONFIG_SPS30_SERIAL=m @@ -9094,6 +9135,7 @@ CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m # # Digital potentiometers # +CONFIG_AD5110=m CONFIG_AD5272=m CONFIG_DS1803=m CONFIG_MAX5432=m @@ -9430,10 +9472,11 @@ CONFIG_F2FS_CHECK_FS=y # CONFIG_F2FS_FAULT_INJECTION is not set CONFIG_F2FS_FS_COMPRESSION=y CONFIG_F2FS_FS_LZO=y +CONFIG_F2FS_FS_LZORLE=y CONFIG_F2FS_FS_LZ4=y CONFIG_F2FS_FS_LZ4HC=y CONFIG_F2FS_FS_ZSTD=y -CONFIG_F2FS_FS_LZORLE=y +CONFIG_F2FS_IOSTAT=y CONFIG_ZONEFS_FS=m CONFIG_FS_DAX=y CONFIG_FS_DAX_PMD=y @@ -9441,7 +9484,6 @@ CONFIG_FS_POSIX_ACL=y CONFIG_EXPORTFS=y CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_FILE_LOCKING=y -# CONFIG_MANDATORY_FILE_LOCKING is not set CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_ALGS=m CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y @@ -9481,12 +9523,9 @@ CONFIG_NETFS_SUPPORT=m CONFIG_NETFS_STATS=y CONFIG_FSCACHE=m CONFIG_FSCACHE_STATS=y -# CONFIG_FSCACHE_HISTOGRAM is not set # CONFIG_FSCACHE_DEBUG is not set -CONFIG_FSCACHE_OBJECT_LIST=y CONFIG_CACHEFILES=m # CONFIG_CACHEFILES_DEBUG is not set -# CONFIG_CACHEFILES_HISTOGRAM is not set # end of Caches # @@ -9510,6 +9549,10 @@ CONFIG_FAT_DEFAULT_UTF8=y CONFIG_EXFAT_FS=m CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" # CONFIG_NTFS_FS is not set +CONFIG_NTFS3_FS=m +# CONFIG_NTFS3_64BIT_CLUSTER is not set +CONFIG_NTFS3_LZX_XPRESS=y +CONFIG_NTFS3_FS_POSIX_ACL=y # end of DOS/FAT/EXFAT/NT Filesystems # @@ -9684,7 +9727,6 @@ CONFIG_CEPH_FS_SECURITY_LABEL=y CONFIG_CIFS=m # CONFIG_CIFS_STATS2 is not set CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y -# CONFIG_CIFS_WEAK_PW_HASH is not set CONFIG_CIFS_UPCALL=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y @@ -9695,6 +9737,11 @@ CONFIG_CIFS_DFS_UPCALL=y CONFIG_CIFS_SWN_UPCALL=y # CONFIG_CIFS_SMB_DIRECT is not set CONFIG_CIFS_FSCACHE=y +CONFIG_SMB_SERVER=m +CONFIG_SMB_SERVER_SMBDIRECT=y +CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y +CONFIG_SMB_SERVER_KERBEROS5=y +CONFIG_SMBFS_COMMON=m CONFIG_CODA_FS=m CONFIG_AFS_FS=m # CONFIG_AFS_DEBUG is not set @@ -9845,6 +9892,8 @@ CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y # CONFIG_GCC_PLUGIN_STACKLEAK is not set CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y +CONFIG_ZERO_CALL_USED_REGS=y # end of Memory initialization # end of Kernel hardening options # end of Security options @@ -9895,9 +9944,9 @@ CONFIG_CRYPTO_ENGINE=m # CONFIG_CRYPTO_RSA=y CONFIG_CRYPTO_DH=y -CONFIG_CRYPTO_ECC=m +CONFIG_CRYPTO_ECC=y CONFIG_CRYPTO_ECDH=m -CONFIG_CRYPTO_ECDSA=m +CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_ECRDSA=m CONFIG_CRYPTO_SM2=m CONFIG_CRYPTO_CURVE25519=m @@ -10001,6 +10050,8 @@ CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m CONFIG_CRYPTO_SERPENT_AVX_X86_64=m CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m CONFIG_CRYPTO_SM4=m +CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64=m +CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_TWOFISH_COMMON=m CONFIG_CRYPTO_TWOFISH_X86_64=m @@ -10058,6 +10109,7 @@ CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m CONFIG_CRYPTO_LIB_POLY1305=m CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LIB_SM4=m CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_DEV_PADLOCK=m CONFIG_CRYPTO_DEV_PADLOCK_AES=m @@ -10100,6 +10152,8 @@ CONFIG_SIGNED_PE_FILE_VERIFICATION=y # Certificates for signature checking # CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" +# CONFIG_MODULE_SIG_KEY_TYPE_RSA is not set +CONFIG_MODULE_SIG_KEY_TYPE_ECDSA=y CONFIG_SYSTEM_TRUSTED_KEYRING=y CONFIG_SYSTEM_TRUSTED_KEYS="" # CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set @@ -10362,7 +10416,6 @@ CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y # CONFIG_KASAN is not set CONFIG_HAVE_ARCH_KFENCE=y CONFIG_KFENCE=y -CONFIG_KFENCE_STATIC_KEYS=y CONFIG_KFENCE_SAMPLE_INTERVAL=100 CONFIG_KFENCE_NUM_OBJECTS=255 CONFIG_KFENCE_STRESS_TEST_FAULTS=0 @@ -10453,7 +10506,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=60 # end of RCU Debugging # CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set CONFIG_LATENCYTOP=y CONFIG_USER_STACKTRACE_SUPPORT=y @@ -10534,7 +10586,6 @@ CONFIG_IO_STRICT_DEVMEM=y # # x86 Debugging # -CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y CONFIG_EARLY_PRINTK_USB=y # CONFIG_X86_VERBOSE_BOOTUP is not set @@ -10572,7 +10623,6 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_LKDTM is not set # CONFIG_TEST_MIN_HEAP is not set -# CONFIG_TEST_SORT is not set # CONFIG_TEST_DIV64 is not set # CONFIG_KPROBES_SANITY_TEST is not set # CONFIG_BACKTRACE_SELF_TEST is not set diff --git a/futex2-tkg.patch b/futex2-tkg.patch deleted file mode 100644 index 6ca76dfb6cff..000000000000 --- a/futex2-tkg.patch +++ /dev/null @@ -1,4327 +0,0 @@ -From ed1408eb394c22190c04ce29f859114b34891bec Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:00 -0300 -Subject: [PATCH 01/14] futex2: Implement wait and wake functions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Create a new set of futex syscalls known as futex2. This new interface -is aimed to implement a more maintainable code, while removing obsolete -features and expanding it with new functionalities. - -Implements wait and wake semantics for futexes, along with the base -infrastructure for future operations. The whole wait path is designed to -be used by N waiters, thus making easier to implement vectorized wait. - -* Syscalls implemented by this patch: - -- futex_wait(void *uaddr, unsigned int val, unsigned int flags, - struct timespec *timo) - - The user thread is put to sleep, waiting for a futex_wake() at uaddr, - if the value at *uaddr is the same as val (otherwise, the syscall - returns immediately with -EAGAIN). timo is an optional timeout value - for the operation. - - Return 0 on success, error code otherwise. - - - futex_wake(void *uaddr, unsigned long nr_wake, unsigned int flags) - - Wake `nr_wake` threads waiting at uaddr. - - Return the number of woken threads on success, error code otherwise. - -** The `flag` argument - - The flag is used to specify the size of the futex word - (FUTEX_[8, 16, 32]). It's mandatory to define one, since there's no - default size. - - By default, the timeout uses a monotonic clock, but can be used as a realtime - one by using the FUTEX_REALTIME_CLOCK flag. - - By default, futexes are of the private type, that means that this user address - will be accessed by threads that shares the same memory region. This allows for - some internal optimizations, so they are faster. However, if the address needs - to be shared with different processes (like using `mmap()` or `shm()`), they - need to be defined as shared and the flag FUTEX_SHARED_FLAG is used to set that. - - By default, the operation has no NUMA-awareness, meaning that the user can't - choose the memory node where the kernel side futex data will be stored. The - user can choose the node where it wants to operate by setting the - FUTEX_NUMA_FLAG and using the following structure (where X can be 8, 16, or - 32): - - struct futexX_numa { - __uX value; - __sX hint; - }; - - This structure should be passed at the `void *uaddr` of futex functions. The - address of the structure will be used to be waited/waken on, and the - `value` will be compared to `val` as usual. The `hint` member is used to - defined which node the futex will use. When waiting, the futex will be - registered on a kernel-side table stored on that node; when waking, the futex - will be searched for on that given table. That means that there's no redundancy - between tables, and the wrong `hint` value will led to undesired behavior. - Userspace is responsible for dealing with node migrations issues that may - occur. `hint` can range from [0, MAX_NUMA_NODES], for specifying a node, or - -1, to use the same node the current process is using. - - When not using FUTEX_NUMA_FLAG on a NUMA system, the futex will be stored on a - global table on some node, defined at compilation time. - -** The `timo` argument - -As per the Y2038 work done in the kernel, new interfaces shouldn't add timeout -options known to be buggy. Given that, `timo` should be a 64bit timeout at -all platforms, using an absolute timeout value. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> - -Rebased-by: Joshua Ashton <joshua@froggi.es> ---- - MAINTAINERS | 2 +- - arch/arm/tools/syscall.tbl | 2 + - arch/arm64/include/asm/unistd.h | 2 +- - arch/arm64/include/asm/unistd32.h | 4 + - arch/x86/entry/syscalls/syscall_32.tbl | 2 + - arch/x86/entry/syscalls/syscall_64.tbl | 2 + - include/linux/syscalls.h | 7 + - include/uapi/asm-generic/unistd.h | 8 +- - include/uapi/linux/futex.h | 5 + - init/Kconfig | 7 + - kernel/Makefile | 1 + - kernel/futex2.c | 619 ++++++++++++++++++ - kernel/sys_ni.c | 4 + - tools/include/uapi/asm-generic/unistd.h | 8 +- - .../arch/x86/entry/syscalls/syscall_64.tbl | 2 + - 15 files changed, 671 insertions(+), 4 deletions(-) - create mode 100644 kernel/futex2.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index 673cadd5107a..b4b81b9a6e37 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -7521,7 +7521,7 @@ F: Documentation/locking/*futex* - F: include/asm-generic/futex.h - F: include/linux/futex.h - F: include/uapi/linux/futex.h --F: kernel/futex.c -+F: kernel/futex* - F: tools/perf/bench/futex* - F: tools/testing/selftests/futex/ - -diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl -index 28e03b5fec00..b60a8bdab623 100644 ---- a/arch/arm/tools/syscall.tbl -+++ b/arch/arm/tools/syscall.tbl -@@ -460,3 +460,5 @@ - 444 common landlock_create_ruleset sys_landlock_create_ruleset - 445 common landlock_add_rule sys_landlock_add_rule - 446 common landlock_restrict_self sys_landlock_restrict_self -+447 common futex_wait sys_futex_wait -+448 common futex_wake sys_futex_wake -diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h -index 727bfc3be99b..3cb206aea3db 100644 ---- a/arch/arm64/include/asm/unistd.h -+++ b/arch/arm64/include/asm/unistd.h -@@ -38,7 +38,7 @@ - #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) - #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) - --#define __NR_compat_syscalls 447 -+#define __NR_compat_syscalls 449 - #endif - - #define __ARCH_WANT_SYS_CLONE -diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h -index 5dab69d2c22b..1749cc108449 100644 ---- a/arch/arm64/include/asm/unistd32.h -+++ b/arch/arm64/include/asm/unistd32.h -@@ -900,6 +900,10 @@ __SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset) - __SYSCALL(__NR_landlock_add_rule, sys_landlock_add_rule) - #define __NR_landlock_restrict_self 446 - __SYSCALL(__NR_landlock_restrict_self, sys_landlock_restrict_self) -+#define __NR_futex_wait 447 -+__SYSCALL(__NR_futex_wait, sys_futex_wait) -+#define __NR_futex_wake 448 -+__SYSCALL(__NR_futex_wake, sys_futex_wake) - - /* - * Please add new compat syscalls above this comment and update -diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl -index 4bbc267fb36b..f75de79fa93d 100644 ---- a/arch/x86/entry/syscalls/syscall_32.tbl -+++ b/arch/x86/entry/syscalls/syscall_32.tbl -@@ -451,3 +451,5 @@ - 444 i386 landlock_create_ruleset sys_landlock_create_ruleset - 445 i386 landlock_add_rule sys_landlock_add_rule - 446 i386 landlock_restrict_self sys_landlock_restrict_self -+447 i386 futex_wait sys_futex_wait -+448 i386 futex_wake sys_futex_wake -diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl -index ce18119ea0d0..63b447255df2 100644 ---- a/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/arch/x86/entry/syscalls/syscall_64.tbl -@@ -368,6 +368,8 @@ - 444 common landlock_create_ruleset sys_landlock_create_ruleset - 445 common landlock_add_rule sys_landlock_add_rule - 446 common landlock_restrict_self sys_landlock_restrict_self -+447 common futex_wait sys_futex_wait -+448 common futex_wake sys_futex_wake - - # - # Due to a historical design error, certain syscalls are numbered differently -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index 050511e8f1f8..0f9b64cc34f7 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -623,6 +623,13 @@ asmlinkage long sys_get_robust_list(int pid, - asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, - size_t len); - -+/* kernel/futex2.c */ -+asmlinkage long sys_futex_wait(void __user *uaddr, unsigned int val, -+ unsigned int flags, -+ struct __kernel_timespec __user *timo); -+asmlinkage long sys_futex_wake(void __user *uaddr, unsigned int nr_wake, -+ unsigned int flags); -+ - /* kernel/hrtimer.c */ - asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, - struct __kernel_timespec __user *rmtp); -diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h -index 6de5a7fc066b..2a62ecca2b00 100644 ---- a/include/uapi/asm-generic/unistd.h -+++ b/include/uapi/asm-generic/unistd.h -@@ -873,8 +873,14 @@ __SYSCALL(__NR_landlock_add_rule, sys_landlock_add_rule) - #define __NR_landlock_restrict_self 446 - __SYSCALL(__NR_landlock_restrict_self, sys_landlock_restrict_self) - -+#define __NR_futex_wait 443 -+__SYSCALL(__NR_futex_wait, sys_futex_wait) -+ -+#define __NR_futex_wake 444 -+__SYSCALL(__NR_futex_wake, sys_futex_wake) -+ - #undef __NR_syscalls --#define __NR_syscalls 447 -+#define __NR_syscalls 449 - - /* - * 32 bit systems traditionally used different -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h -index a89eb0accd5e..8d30f4b6d094 100644 ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -41,6 +41,11 @@ - #define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ - FUTEX_PRIVATE_FLAG) - -+/* Size argument to futex2 syscall */ -+#define FUTEX_32 2 -+ -+#define FUTEX_SIZE_MASK 0x3 -+ - /* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. -diff --git a/init/Kconfig b/init/Kconfig -index a61c92066c2e..d87629ec7e48 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1555,6 +1555,13 @@ config FUTEX - support for "fast userspace mutexes". The resulting kernel may not - run glibc-based applications correctly. - -+config FUTEX2 -+ bool "Enable futex2 support" if EXPERT -+ depends on FUTEX -+ default y -+ help -+ Support for futex2 interface. -+ - config FUTEX_PI - bool - depends on FUTEX && RT_MUTEXES -diff --git a/kernel/Makefile b/kernel/Makefile -index 4df609be42d0..1eaf2af50283 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -60,6 +60,7 @@ obj-$(CONFIG_PROFILING) += profile.o - obj-$(CONFIG_STACKTRACE) += stacktrace.o - obj-y += time/ - obj-$(CONFIG_FUTEX) += futex.o -+obj-$(CONFIG_FUTEX2) += futex2.o - obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o - obj-$(CONFIG_SMP) += smp.o - ifneq ($(CONFIG_SMP),y) -diff --git a/kernel/futex2.c b/kernel/futex2.c -new file mode 100644 -index 000000000000..ade407c1abb7 ---- /dev/null -+++ b/kernel/futex2.c -@@ -0,0 +1,619 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * futex2 system call interface by André Almeida <andrealmeid@collabora.com> -+ * -+ * Copyright 2021 Collabora Ltd. -+ * -+ * Based on original futex implementation by: -+ * (C) 2002 Rusty Russell, IBM -+ * (C) 2003, 2006 Ingo Molnar, Red Hat Inc. -+ * (C) 2003, 2004 Jamie Lokier -+ * (C) 2006 Thomas Gleixner, Timesys Corp. -+ * (C) 2007 Eric Dumazet -+ * (C) 2009 Darren Hart, IBM -+ */ -+ -+#include <linux/freezer.h> -+#include <linux/jhash.h> -+#include <linux/memblock.h> -+#include <linux/sched/wake_q.h> -+#include <linux/spinlock.h> -+#include <linux/syscalls.h> -+#include <uapi/linux/futex.h> -+ -+/** -+ * struct futex_key - Components to build unique key for a futex -+ * @pointer: Pointer to current->mm -+ * @index: Start address of the page containing futex -+ * @offset: Address offset of uaddr in a page -+ */ -+struct futex_key { -+ u64 pointer; -+ unsigned long index; -+ unsigned long offset; -+}; -+ -+/** -+ * struct futex_waiter - List entry for a waiter -+ * @uaddr: Virtual address of userspace futex -+ * @key: Information that uniquely identify a futex -+ * @list: List node struct -+ * @val: Expected value for this waiter -+ * @flags: Flags -+ * @bucket: Pointer to the bucket for this waiter -+ * @index: Index of waiter in futexv list -+ */ -+struct futex_waiter { -+ void __user *uaddr; -+ struct futex_key key; -+ struct list_head list; -+ unsigned int val; -+ unsigned int flags; -+ struct futex_bucket *bucket; -+ unsigned int index; -+}; -+ -+/** -+ * struct futex_waiter_head - List of futexes to be waited -+ * @task: Task to be awaken -+ * @hint: Was someone on this list awakened? -+ * @objects: List of futexes -+ */ -+struct futex_waiter_head { -+ struct task_struct *task; -+ bool hint; -+ struct futex_waiter objects[0]; -+}; -+ -+/** -+ * struct futex_bucket - A bucket of futex's hash table -+ * @waiters: Number of waiters in the bucket -+ * @lock: Bucket lock -+ * @list: List of waiters on this bucket -+ */ -+struct futex_bucket { -+ atomic_t waiters; -+ spinlock_t lock; -+ struct list_head list; -+}; -+ -+ -+/* Mask for futex2 flag operations */ -+#define FUTEX2_MASK (FUTEX_SIZE_MASK | FUTEX_CLOCK_REALTIME) -+ -+static struct futex_bucket *futex_table; -+static unsigned int futex2_hashsize; -+ -+/* -+ * Reflects a new waiter being added to the waitqueue. -+ */ -+static inline void bucket_inc_waiters(struct futex_bucket *bucket) -+{ -+#ifdef CONFIG_SMP -+ atomic_inc(&bucket->waiters); -+ /* -+ * Issue a barrier after adding so futex_wake() will see that the -+ * value had increased -+ */ -+ smp_mb__after_atomic(); -+#endif -+} -+ -+/* -+ * Reflects a waiter being removed from the waitqueue by wakeup -+ * paths. -+ */ -+static inline void bucket_dec_waiters(struct futex_bucket *bucket) -+{ -+#ifdef CONFIG_SMP -+ atomic_dec(&bucket->waiters); -+#endif -+} -+ -+/* -+ * Get the number of waiters in a bucket -+ */ -+static inline int bucket_get_waiters(struct futex_bucket *bucket) -+{ -+#ifdef CONFIG_SMP -+ /* -+ * Issue a barrier before reading so we get an updated value from -+ * futex_wait() -+ */ -+ smp_mb(); -+ return atomic_read(&bucket->waiters); -+#else -+ return 1; -+#endif -+} -+ -+/** -+ * futex_get_bucket - Check if the user address is valid, prepare internal -+ * data and calculate the hash -+ * @uaddr: futex user address -+ * @key: data that uniquely identifies a futex -+ * -+ * Return: address of bucket on success, error code otherwise -+ */ -+static struct futex_bucket *futex_get_bucket(void __user *uaddr, -+ struct futex_key *key) -+{ -+ uintptr_t address = (uintptr_t)uaddr; -+ u32 hash_key; -+ -+ /* Checking if uaddr is valid and accessible */ -+ if (unlikely(!IS_ALIGNED(address, sizeof(u32)))) -+ return ERR_PTR(-EINVAL); -+ if (unlikely(!access_ok(uaddr, sizeof(u32)))) -+ return ERR_PTR(-EFAULT); -+ -+ key->offset = address % PAGE_SIZE; -+ address -= key->offset; -+ key->pointer = (u64)address; -+ key->index = (unsigned long)current->mm; -+ -+ /* Generate hash key for this futex using uaddr and current->mm */ -+ hash_key = jhash2((u32 *)key, sizeof(*key) / sizeof(u32), 0); -+ -+ /* Since HASH_SIZE is 2^n, subtracting 1 makes a perfect bit mask */ -+ return &futex_table[hash_key & (futex2_hashsize - 1)]; -+} -+ -+/** -+ * futex_get_user - Get the userspace value on this address -+ * @uval: variable to store the value -+ * @uaddr: userspace address -+ * -+ * Check the comment at futex_enqueue() for more information. -+ */ -+static int futex_get_user(u32 *uval, u32 __user *uaddr) -+{ -+ int ret; -+ -+ pagefault_disable(); -+ ret = __get_user(*uval, uaddr); -+ pagefault_enable(); -+ -+ return ret; -+} -+ -+/** -+ * futex_setup_time - Prepare the timeout mechanism and start it. -+ * @timo: Timeout value from userspace -+ * @timeout: Pointer to hrtimer handler -+ * @flags: Flags from userspace, to decide which clockid to use -+ * -+ * Return: 0 on success, error code otherwise -+ */ -+static int futex_setup_time(struct __kernel_timespec __user *timo, -+ struct hrtimer_sleeper *timeout, -+ unsigned int flags) -+{ -+ ktime_t time; -+ struct timespec64 ts; -+ clockid_t clockid = (flags & FUTEX_CLOCK_REALTIME) ? -+ CLOCK_REALTIME : CLOCK_MONOTONIC; -+ -+ if (get_timespec64(&ts, timo)) -+ return -EFAULT; -+ -+ if (!timespec64_valid(&ts)) -+ return -EINVAL; -+ -+ time = timespec64_to_ktime(ts); -+ -+ hrtimer_init_sleeper(timeout, clockid, HRTIMER_MODE_ABS); -+ -+ hrtimer_set_expires(&timeout->timer, time); -+ -+ hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS); -+ -+ return 0; -+} -+ -+/** -+ * futex_dequeue_multiple - Remove multiple futexes from hash table -+ * @futexv: list of waiters -+ * @nr: number of futexes to be removed -+ * -+ * This function is used if (a) something went wrong while enqueuing, and we -+ * need to undo our work (then nr <= nr_futexes) or (b) we woke up, and thus -+ * need to remove every waiter, check if some was indeed woken and return. -+ * Before removing a waiter, we check if it's on the list, since we have no -+ * clue who have been waken. -+ * -+ * Return: -+ * * -1 - If no futex was woken during the removal -+ * * 0>= - At least one futex was found woken, index of the last one -+ */ -+static int futex_dequeue_multiple(struct futex_waiter_head *futexv, unsigned int nr) -+{ -+ int i, ret = -1; -+ -+ for (i = 0; i < nr; i++) { -+ spin_lock(&futexv->objects[i].bucket->lock); -+ if (!list_empty(&futexv->objects[i].list)) { -+ list_del_init(&futexv->objects[i].list); -+ bucket_dec_waiters(futexv->objects[i].bucket); -+ } else { -+ ret = i; -+ } -+ spin_unlock(&futexv->objects[i].bucket->lock); -+ } -+ -+ return ret; -+} -+ -+/** -+ * futex_enqueue - Check the value and enqueue a futex on a wait list -+ * -+ * @futexv: List of futexes -+ * @nr_futexes: Number of futexes in the list -+ * @awakened: If a futex was awakened during enqueueing, store the index here -+ * -+ * Get the value from the userspace address and compares with the expected one. -+ * -+ * Getting the value from user futex address: -+ * -+ * Since we are in a hurry, we use a spin lock and we can't sleep. -+ * Try to get the value with page fault disabled (when enable, we might -+ * sleep). -+ * -+ * If we fail, we aren't sure if the address is invalid or is just a -+ * page fault. Then, release the lock (so we can sleep) and try to get -+ * the value with page fault enabled. In order to trigger a page fault -+ * handling, we just call __get_user() again. If we sleep with enqueued -+ * futexes, we might miss a wake, so dequeue everything before sleeping. -+ * -+ * If get_user succeeds, this mean that the address is valid and we do -+ * the work again. Since we just handled the page fault, the page is -+ * likely pinned in memory and we should be luckier this time and be -+ * able to get the value. If we fail anyway, we will try again. -+ * -+ * If even with page faults enabled we get and error, this means that -+ * the address is not valid and we return from the syscall. -+ * -+ * If we got an unexpected value or need to treat a page fault and realized that -+ * a futex was awakened, we can priority this and return success. -+ * -+ * In success, enqueue the futex in the correct bucket -+ * -+ * Return: -+ * * 1 - We were awake in the process and nothing is enqueued -+ * * 0 - Everything is enqueued and we are ready to sleep -+ * * 0< - Something went wrong, nothing is enqueued, return error code -+ */ -+static int futex_enqueue(struct futex_waiter_head *futexv, unsigned int nr_futexes, -+ int *awakened) -+{ -+ int i, ret; -+ u32 uval, val; -+ u32 __user *uaddr; -+ struct futex_bucket *bucket; -+ -+retry: -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ for (i = 0; i < nr_futexes; i++) { -+ uaddr = (u32 __user *)futexv->objects[i].uaddr; -+ val = (u32)futexv->objects[i].val; -+ -+ bucket = futexv->objects[i].bucket; -+ -+ bucket_inc_waiters(bucket); -+ spin_lock(&bucket->lock); -+ -+ ret = futex_get_user(&uval, uaddr); -+ -+ if (unlikely(ret)) { -+ spin_unlock(&bucket->lock); -+ -+ bucket_dec_waiters(bucket); -+ __set_current_state(TASK_RUNNING); -+ *awakened = futex_dequeue_multiple(futexv, i); -+ -+ if (*awakened >= 0) -+ return 1; -+ -+ if (__get_user(uval, uaddr)) -+ return -EFAULT; -+ -+ goto retry; -+ } -+ -+ if (uval != val) { -+ spin_unlock(&bucket->lock); -+ -+ bucket_dec_waiters(bucket); -+ __set_current_state(TASK_RUNNING); -+ *awakened = futex_dequeue_multiple(futexv, i); -+ -+ if (*awakened >= 0) -+ return 1; -+ -+ return -EAGAIN; -+ } -+ -+ list_add_tail(&futexv->objects[i].list, &bucket->list); -+ spin_unlock(&bucket->lock); -+ } -+ -+ return 0; -+} -+ -+/** -+ * __futex_wait - Enqueue the list of futexes and wait to be woken -+ * @futexv: List of futexes to wait -+ * @nr_futexes: Length of futexv -+ * @timeout: Pointer to timeout handler -+ * -+ * Return: -+ * * 0 >= - Hint of which futex woke us -+ * * 0 < - Error code -+ */ -+static int __futex_wait(struct futex_waiter_head *futexv, unsigned int nr_futexes, -+ struct hrtimer_sleeper *timeout) -+{ -+ int ret; -+ -+ while (1) { -+ int awakened = -1; -+ -+ ret = futex_enqueue(futexv, nr_futexes, &awakened); -+ -+ if (ret) { -+ if (awakened >= 0) -+ return awakened; -+ return ret; -+ } -+ -+ /* Before sleeping, check if someone was woken */ -+ if (!futexv->hint && (!timeout || timeout->task)) -+ freezable_schedule(); -+ -+ __set_current_state(TASK_RUNNING); -+ -+ /* -+ * One of those things triggered this wake: -+ * -+ * * We have been removed from the bucket. futex_wake() woke -+ * us. We just need to dequeue and return 0 to userspace. -+ * -+ * However, if no futex was dequeued by a futex_wake(): -+ * -+ * * If the there's a timeout and it has expired, -+ * return -ETIMEDOUT. -+ * -+ * * If there is a signal pending, something wants to kill our -+ * thread, return -ERESTARTSYS. -+ * -+ * * If there's no signal pending, it was a spurious wake -+ * (scheduler gave us a chance to do some work, even if we -+ * don't want to). We need to remove ourselves from the -+ * bucket and add again, to prevent losing wakeups in the -+ * meantime. -+ */ -+ -+ ret = futex_dequeue_multiple(futexv, nr_futexes); -+ -+ /* Normal wake */ -+ if (ret >= 0) -+ return ret; -+ -+ if (timeout && !timeout->task) -+ return -ETIMEDOUT; -+ -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ -+ /* Spurious wake, do everything again */ -+ } -+} -+ -+/** -+ * futex_wait - Setup the timer (if there's one) and wait on a list of futexes -+ * @futexv: List of futexes -+ * @nr_futexes: Length of futexv -+ * @timo: Timeout -+ * @flags: Timeout flags -+ * -+ * Return: -+ * * 0 >= - Hint of which futex woke us -+ * * 0 < - Error code -+ */ -+static int futex_set_timer_and_wait(struct futex_waiter_head *futexv, -+ unsigned int nr_futexes, -+ struct __kernel_timespec __user *timo, -+ unsigned int flags) -+{ -+ struct hrtimer_sleeper timeout; -+ int ret; -+ -+ if (timo) { -+ ret = futex_setup_time(timo, &timeout, flags); -+ if (ret) -+ return ret; -+ } -+ -+ ret = __futex_wait(futexv, nr_futexes, timo ? &timeout : NULL); -+ -+ if (timo) -+ hrtimer_cancel(&timeout.timer); -+ -+ return ret; -+} -+ -+/** -+ * sys_futex_wait - Wait on a futex address if (*uaddr) == val -+ * @uaddr: User address of futex -+ * @val: Expected value of futex -+ * @flags: Specify the size of futex and the clockid -+ * @timo: Optional absolute timeout. -+ * -+ * The user thread is put to sleep, waiting for a futex_wake() at uaddr, if the -+ * value at *uaddr is the same as val (otherwise, the syscall returns -+ * immediately with -EAGAIN). -+ * -+ * Returns 0 on success, error code otherwise. -+ */ -+SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val, -+ unsigned int, flags, struct __kernel_timespec __user *, timo) -+{ -+ unsigned int size = flags & FUTEX_SIZE_MASK; -+ struct futex_waiter *waiter; -+ struct futex_waiter_head *futexv; -+ -+ /* Wrapper for a futexv_head of one element */ -+ struct { -+ struct futex_waiter_head futexv; -+ struct futex_waiter waiter; -+ } __packed wait_single; -+ -+ if (flags & ~FUTEX2_MASK) -+ return -EINVAL; -+ -+ if (size != FUTEX_32) -+ return -EINVAL; -+ -+ futexv = &wait_single.futexv; -+ futexv->task = current; -+ futexv->hint = false; -+ -+ waiter = &wait_single.waiter; -+ waiter->index = 0; -+ waiter->val = val; -+ waiter->uaddr = uaddr; -+ memset(&wait_single.waiter.key, 0, sizeof(struct futex_key)); -+ -+ INIT_LIST_HEAD(&waiter->list); -+ -+ /* Get an unlocked hash bucket */ -+ waiter->bucket = futex_get_bucket(uaddr, &waiter->key); -+ if (IS_ERR(waiter->bucket)) -+ return PTR_ERR(waiter->bucket); -+ -+ return futex_set_timer_and_wait(futexv, 1, timo, flags); -+} -+ -+/** -+ * futex_get_parent - For a given futex in a futexv list, get a pointer to the futexv -+ * @waiter: Address of futex in the list -+ * @index: Index of futex in the list -+ * -+ * Return: A pointer to its futexv struct -+ */ -+static inline struct futex_waiter_head *futex_get_parent(uintptr_t waiter, -+ unsigned int index) -+{ -+ uintptr_t parent = waiter - sizeof(struct futex_waiter_head) -+ - (uintptr_t)(index * sizeof(struct futex_waiter)); -+ -+ return (struct futex_waiter_head *)parent; -+} -+ -+/** -+ * futex_mark_wake - Find the task to be wake and add it in wake queue -+ * @waiter: Waiter to be wake -+ * @bucket: Bucket to be decremented -+ * @wake_q: Wake queue to insert the task -+ */ -+static void futex_mark_wake(struct futex_waiter *waiter, -+ struct futex_bucket *bucket, -+ struct wake_q_head *wake_q) -+{ -+ struct task_struct *task; -+ struct futex_waiter_head *parent = futex_get_parent((uintptr_t)waiter, -+ waiter->index); -+ -+ lockdep_assert_held(&bucket->lock); -+ parent->hint = true; -+ task = parent->task; -+ get_task_struct(task); -+ list_del_init(&waiter->list); -+ wake_q_add_safe(wake_q, task); -+ bucket_dec_waiters(bucket); -+} -+ -+static inline bool futex_match(struct futex_key key1, struct futex_key key2) -+{ -+ return (key1.index == key2.index && -+ key1.pointer == key2.pointer && -+ key1.offset == key2.offset); -+} -+ -+/** -+ * sys_futex_wake - Wake a number of futexes waiting on an address -+ * @uaddr: Address of futex to be woken up -+ * @nr_wake: Number of futexes waiting in uaddr to be woken up -+ * @flags: Flags for size and shared -+ * -+ * Wake `nr_wake` threads waiting at uaddr. -+ * -+ * Returns the number of woken threads on success, error code otherwise. -+ */ -+SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, -+ unsigned int, flags) -+{ -+ unsigned int size = flags & FUTEX_SIZE_MASK; -+ struct futex_waiter waiter, *aux, *tmp; -+ struct futex_bucket *bucket; -+ DEFINE_WAKE_Q(wake_q); -+ int ret = 0; -+ -+ if (flags & ~FUTEX2_MASK) -+ return -EINVAL; -+ -+ if (size != FUTEX_32) -+ return -EINVAL; -+ -+ bucket = futex_get_bucket(uaddr, &waiter.key); -+ if (IS_ERR(bucket)) -+ return PTR_ERR(bucket); -+ -+ if (!bucket_get_waiters(bucket) || !nr_wake) -+ return 0; -+ -+ spin_lock(&bucket->lock); -+ list_for_each_entry_safe(aux, tmp, &bucket->list, list) { -+ if (futex_match(waiter.key, aux->key)) { -+ futex_mark_wake(aux, bucket, &wake_q); -+ if (++ret >= nr_wake) -+ break; -+ } -+ } -+ spin_unlock(&bucket->lock); -+ -+ wake_up_q(&wake_q); -+ -+ return ret; -+} -+ -+static int __init futex2_init(void) -+{ -+ int i; -+ unsigned int futex_shift; -+ -+#if CONFIG_BASE_SMALL -+ futex2_hashsize = 16; -+#else -+ futex2_hashsize = roundup_pow_of_two(256 * num_possible_cpus()); -+#endif -+ -+ futex_table = alloc_large_system_hash("futex2", sizeof(struct futex_bucket), -+ futex2_hashsize, 0, -+ futex2_hashsize < 256 ? HASH_SMALL : 0, -+ &futex_shift, NULL, -+ futex2_hashsize, futex2_hashsize); -+ futex2_hashsize = 1UL << futex_shift; -+ -+ BUG_ON(!is_power_of_2(futex2_hashsize)); -+ -+ for (i = 0; i < futex2_hashsize; i++) { -+ INIT_LIST_HEAD(&futex_table[i].list); -+ spin_lock_init(&futex_table[i].lock); -+ atomic_set(&futex_table[i].waiters, 0); -+ } -+ -+ return 0; -+} -+core_initcall(futex2_init); -diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c -index 0ea8128468c3..9addbe373f00 100644 ---- a/kernel/sys_ni.c -+++ b/kernel/sys_ni.c -@@ -151,6 +151,10 @@ COND_SYSCALL_COMPAT(set_robust_list); - COND_SYSCALL(get_robust_list); - COND_SYSCALL_COMPAT(get_robust_list); - -+/* kernel/futex2.c */ -+COND_SYSCALL(futex_wait); -+COND_SYSCALL(futex_wake); -+ - /* kernel/hrtimer.c */ - - /* kernel/itimer.c */ -diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h -index 6de5a7fc066b..2a62ecca2b00 100644 ---- a/tools/include/uapi/asm-generic/unistd.h -+++ b/tools/include/uapi/asm-generic/unistd.h -@@ -873,8 +873,14 @@ __SYSCALL(__NR_landlock_add_rule, sys_landlock_add_rule) - #define __NR_landlock_restrict_self 446 - __SYSCALL(__NR_landlock_restrict_self, sys_landlock_restrict_self) - -+#define __NR_futex_wait 443 -+__SYSCALL(__NR_futex_wait, sys_futex_wait) -+ -+#define __NR_futex_wake 444 -+__SYSCALL(__NR_futex_wake, sys_futex_wake) -+ - #undef __NR_syscalls --#define __NR_syscalls 447 -+#define __NR_syscalls 449 - - /* - * 32 bit systems traditionally used different -diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -index ce18119ea0d0..8eb17cc08a69 100644 ---- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -@@ -368,6 +368,8 @@ - 444 common landlock_create_ruleset sys_landlock_create_ruleset - 445 common landlock_add_rule sys_landlock_add_rule - 446 common landlock_restrict_self sys_landlock_restrict_self -+447 common futex_wait sys_futex_wait -+448 common futex_wake sys_futex_wake - - # - # Due to a historical design error, certain syscalls are numbered differently --- -2.31.1 - - -From 24d84c5a45d3a5c5f3b6f2899bfe1c97e2380964 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:01 -0300 -Subject: [PATCH 02/14] futex2: Add support for shared futexes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add support for shared futexes for cross-process resources. This design -relies on the same approach done in old futex to create an unique id for -file-backed shared memory, by using a counter at struct inode. - -There are two types of futexes: private and shared ones. The private are futexes -meant to be used by threads that shares the same memory space, are easier to be -uniquely identified an thus can have some performance optimization. The elements -for identifying one are: the start address of the page where the address is, -the address offset within the page and the current->mm pointer. - -Now, for uniquely identifying shared futex: - -- If the page containing the user address is an anonymous page, we can - just use the same data used for private futexes (the start address of - the page, the address offset within the page and the current->mm - pointer) that will be enough for uniquely identifying such futex. We - also set one bit at the key to differentiate if a private futex is - used on the same address (mixing shared and private calls are not - allowed). - -- If the page is file-backed, current->mm maybe isn't the same one for - every user of this futex, so we need to use other data: the - page->index, an UUID for the struct inode and the offset within the - page. - -Note that members of futex_key doesn't have any particular meaning after they -are part of the struct - they are just bytes to identify a futex. Given that, -we don't need to use a particular name or type that matches the original data, -we only need to care about the bitsize of each component and make both private -and shared data fit in the same memory space. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - fs/inode.c | 1 + - include/linux/fs.h | 1 + - include/uapi/linux/futex.h | 2 + - kernel/futex2.c | 222 ++++++++++++++++++++++++++++++++++++- - 4 files changed, 220 insertions(+), 6 deletions(-) - -diff --git a/fs/inode.c b/fs/inode.c -index c93500d84264..73e82a304d10 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -138,6 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) - inode->i_blkbits = sb->s_blocksize_bits; - inode->i_flags = 0; - atomic64_set(&inode->i_sequence, 0); -+ atomic64_set(&inode->i_sequence2, 0); - atomic_set(&inode->i_count, 1); - inode->i_op = &empty_iops; - inode->i_fop = &no_open_fops; -diff --git a/include/linux/fs.h b/include/linux/fs.h -index c3c88fdb9b2a..5dd112c04357 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -682,6 +682,7 @@ struct inode { - }; - atomic64_t i_version; - atomic64_t i_sequence; /* see futex */ -+ atomic64_t i_sequence2; /* see futex2 */ - atomic_t i_count; - atomic_t i_dio_count; - atomic_t i_writecount; -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h -index 8d30f4b6d094..70ea66fffb1c 100644 ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -46,6 +46,8 @@ - - #define FUTEX_SIZE_MASK 0x3 - -+#define FUTEX_SHARED_FLAG 8 -+ - /* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. -diff --git a/kernel/futex2.c b/kernel/futex2.c -index ade407c1abb7..51086d0c3fd5 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -14,8 +14,10 @@ - */ - - #include <linux/freezer.h> -+#include <linux/hugetlb.h> - #include <linux/jhash.h> - #include <linux/memblock.h> -+#include <linux/pagemap.h> - #include <linux/sched/wake_q.h> - #include <linux/spinlock.h> - #include <linux/syscalls.h> -@@ -23,8 +25,8 @@ - - /** - * struct futex_key - Components to build unique key for a futex -- * @pointer: Pointer to current->mm -- * @index: Start address of the page containing futex -+ * @pointer: Pointer to current->mm or inode's UUID for file backed futexes -+ * @index: Start address of the page containing futex or index of the page - * @offset: Address offset of uaddr in a page - */ - struct futex_key { -@@ -79,7 +81,12 @@ struct futex_bucket { - - - /* Mask for futex2 flag operations */ --#define FUTEX2_MASK (FUTEX_SIZE_MASK | FUTEX_CLOCK_REALTIME) -+#define FUTEX2_MASK (FUTEX_SIZE_MASK | FUTEX_CLOCK_REALTIME | FUTEX_SHARED_FLAG) -+ -+#define is_object_shared ((futexv->objects[i].flags & FUTEX_SHARED_FLAG) ? true : false) -+ -+#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */ -+#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */ - - static struct futex_bucket *futex_table; - static unsigned int futex2_hashsize; -@@ -127,16 +134,200 @@ static inline int bucket_get_waiters(struct futex_bucket *bucket) - #endif - } - -+/** -+ * futex_get_inode_uuid - Gets an UUID for an inode -+ * @inode: inode to get UUID -+ * -+ * Generate a machine wide unique identifier for this inode. -+ * -+ * This relies on u64 not wrapping in the life-time of the machine; which with -+ * 1ns resolution means almost 585 years. -+ * -+ * This further relies on the fact that a well formed program will not unmap -+ * the file while it has a (shared) futex waiting on it. This mapping will have -+ * a file reference which pins the mount and inode. -+ * -+ * If for some reason an inode gets evicted and read back in again, it will get -+ * a new sequence number and will _NOT_ match, even though it is the exact same -+ * file. -+ * -+ * It is important that match_futex() will never have a false-positive, esp. -+ * for PI futexes that can mess up the state. The above argues that false-negatives -+ * are only possible for malformed programs. -+ * -+ * Returns: UUID for the given inode -+ */ -+static u64 futex_get_inode_uuid(struct inode *inode) -+{ -+ static atomic64_t i_seq; -+ u64 old; -+ -+ /* Does the inode already have a sequence number? */ -+ old = atomic64_read(&inode->i_sequence2); -+ -+ if (likely(old)) -+ return old; -+ -+ for (;;) { -+ u64 new = atomic64_add_return(1, &i_seq); -+ -+ if (WARN_ON_ONCE(!new)) -+ continue; -+ -+ old = atomic64_cmpxchg_relaxed(&inode->i_sequence2, 0, new); -+ if (old) -+ return old; -+ return new; -+ } -+} -+ -+/** -+ * futex_get_shared_key - Get a key for a shared futex -+ * @address: Futex memory address -+ * @mm: Current process mm_struct pointer -+ * @key: Key struct to be filled -+ * -+ * Returns: 0 on success, error code otherwise -+ */ -+static int futex_get_shared_key(uintptr_t address, struct mm_struct *mm, -+ struct futex_key *key) -+{ -+ int ret; -+ struct page *page, *tail; -+ struct address_space *mapping; -+ -+again: -+ ret = get_user_pages_fast(address, 1, 0, &page); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * The treatment of mapping from this point on is critical. The page -+ * lock protects many things but in this context the page lock -+ * stabilizes mapping, prevents inode freeing in the shared -+ * file-backed region case and guards against movement to swap cache. -+ * -+ * Strictly speaking the page lock is not needed in all cases being -+ * considered here and page lock forces unnecessarily serialization -+ * From this point on, mapping will be re-verified if necessary and -+ * page lock will be acquired only if it is unavoidable -+ * -+ * Mapping checks require the head page for any compound page so the -+ * head page and mapping is looked up now. For anonymous pages, it -+ * does not matter if the page splits in the future as the key is -+ * based on the address. For filesystem-backed pages, the tail is -+ * required as the index of the page determines the key. For -+ * base pages, there is no tail page and tail == page. -+ */ -+ tail = page; -+ page = compound_head(page); -+ mapping = READ_ONCE(page->mapping); -+ -+ /* -+ * If page->mapping is NULL, then it cannot be a PageAnon -+ * page; but it might be the ZERO_PAGE or in the gate area or -+ * in a special mapping (all cases which we are happy to fail); -+ * or it may have been a good file page when get_user_pages_fast -+ * found it, but truncated or holepunched or subjected to -+ * invalidate_complete_page2 before we got the page lock (also -+ * cases which we are happy to fail). And we hold a reference, -+ * so refcount care in invalidate_complete_page's remove_mapping -+ * prevents drop_caches from setting mapping to NULL beneath us. -+ * -+ * The case we do have to guard against is when memory pressure made -+ * shmem_writepage move it from filecache to swapcache beneath us: -+ * an unlikely race, but we do need to retry for page->mapping. -+ */ -+ if (unlikely(!mapping)) { -+ int shmem_swizzled; -+ -+ /* -+ * Page lock is required to identify which special case above -+ * applies. If this is really a shmem page then the page lock -+ * will prevent unexpected transitions. -+ */ -+ lock_page(page); -+ shmem_swizzled = PageSwapCache(page) || page->mapping; -+ unlock_page(page); -+ put_page(page); -+ -+ if (shmem_swizzled) -+ goto again; -+ -+ return -EFAULT; -+ } -+ -+ /* -+ * Private mappings are handled in a simple way. -+ * -+ * If the futex key is stored on an anonymous page, then the associated -+ * object is the mm which is implicitly pinned by the calling process. -+ * -+ * NOTE: When userspace waits on a MAP_SHARED mapping, even if -+ * it's a read-only handle, it's expected that futexes attach to -+ * the object not the particular process. -+ */ -+ if (PageAnon(page)) { -+ key->offset |= FUT_OFF_MMSHARED; -+ } else { -+ struct inode *inode; -+ -+ /* -+ * The associated futex object in this case is the inode and -+ * the page->mapping must be traversed. Ordinarily this should -+ * be stabilised under page lock but it's not strictly -+ * necessary in this case as we just want to pin the inode, not -+ * update the radix tree or anything like that. -+ * -+ * The RCU read lock is taken as the inode is finally freed -+ * under RCU. If the mapping still matches expectations then the -+ * mapping->host can be safely accessed as being a valid inode. -+ */ -+ rcu_read_lock(); -+ -+ if (READ_ONCE(page->mapping) != mapping) { -+ rcu_read_unlock(); -+ put_page(page); -+ -+ goto again; -+ } -+ -+ inode = READ_ONCE(mapping->host); -+ if (!inode) { -+ rcu_read_unlock(); -+ put_page(page); -+ -+ goto again; -+ } -+ -+ key->pointer = futex_get_inode_uuid(inode); -+ key->index = (unsigned long)page_to_pgoff(tail); -+ key->offset |= FUT_OFF_INODE; -+ -+ rcu_read_unlock(); -+ } -+ -+ put_page(page); -+ -+ return 0; -+} -+ - /** - * futex_get_bucket - Check if the user address is valid, prepare internal - * data and calculate the hash - * @uaddr: futex user address - * @key: data that uniquely identifies a futex -+ * @shared: is this a shared futex? -+ * -+ * For private futexes, each uaddr will be unique for a given mm_struct, and it -+ * won't be freed for the life time of the process. For shared futexes, check -+ * futex_get_shared_key(). - * - * Return: address of bucket on success, error code otherwise - */ - static struct futex_bucket *futex_get_bucket(void __user *uaddr, -- struct futex_key *key) -+ struct futex_key *key, -+ bool shared) - { - uintptr_t address = (uintptr_t)uaddr; - u32 hash_key; -@@ -152,6 +343,9 @@ static struct futex_bucket *futex_get_bucket(void __user *uaddr, - key->pointer = (u64)address; - key->index = (unsigned long)current->mm; - -+ if (shared) -+ futex_get_shared_key(address, current->mm, key); -+ - /* Generate hash key for this futex using uaddr and current->mm */ - hash_key = jhash2((u32 *)key, sizeof(*key) / sizeof(u32), 0); - -@@ -289,6 +483,7 @@ static int futex_enqueue(struct futex_waiter_head *futexv, unsigned int nr_futex - int i, ret; - u32 uval, val; - u32 __user *uaddr; -+ bool retry = false; - struct futex_bucket *bucket; - - retry: -@@ -298,6 +493,18 @@ static int futex_enqueue(struct futex_waiter_head *futexv, unsigned int nr_futex - uaddr = (u32 __user *)futexv->objects[i].uaddr; - val = (u32)futexv->objects[i].val; - -+ if (is_object_shared && retry) { -+ struct futex_bucket *tmp = -+ futex_get_bucket((void __user *)uaddr, -+ &futexv->objects[i].key, true); -+ if (IS_ERR(tmp)) { -+ __set_current_state(TASK_RUNNING); -+ futex_dequeue_multiple(futexv, i); -+ return PTR_ERR(tmp); -+ } -+ futexv->objects[i].bucket = tmp; -+ } -+ - bucket = futexv->objects[i].bucket; - - bucket_inc_waiters(bucket); -@@ -318,6 +525,7 @@ static int futex_enqueue(struct futex_waiter_head *futexv, unsigned int nr_futex - if (__get_user(uval, uaddr)) - return -EFAULT; - -+ retry = true; - goto retry; - } - -@@ -459,6 +667,7 @@ static int futex_set_timer_and_wait(struct futex_waiter_head *futexv, - SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val, - unsigned int, flags, struct __kernel_timespec __user *, timo) - { -+ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false; - unsigned int size = flags & FUTEX_SIZE_MASK; - struct futex_waiter *waiter; - struct futex_waiter_head *futexv; -@@ -488,7 +697,7 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val, - INIT_LIST_HEAD(&waiter->list); - - /* Get an unlocked hash bucket */ -- waiter->bucket = futex_get_bucket(uaddr, &waiter->key); -+ waiter->bucket = futex_get_bucket(uaddr, &waiter->key, shared); - if (IS_ERR(waiter->bucket)) - return PTR_ERR(waiter->bucket); - -@@ -554,6 +763,7 @@ static inline bool futex_match(struct futex_key key1, struct futex_key key2) - SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, - unsigned int, flags) - { -+ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false; - unsigned int size = flags & FUTEX_SIZE_MASK; - struct futex_waiter waiter, *aux, *tmp; - struct futex_bucket *bucket; -@@ -566,7 +776,7 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, - if (size != FUTEX_32) - return -EINVAL; - -- bucket = futex_get_bucket(uaddr, &waiter.key); -+ bucket = futex_get_bucket(uaddr, &waiter.key, shared); - if (IS_ERR(bucket)) - return PTR_ERR(bucket); - --- -2.31.1 - - -From 649c033164d9a09f9ab682f579298b5f0449fe70 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:00 -0300 -Subject: [PATCH 03/14] futex2: Implement vectorized wait -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add support to wait on multiple futexes. This is the interface -implemented by this syscall: - -futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes, - unsigned int flags, struct timespec *timo) - -struct futex_waitv { - void *uaddr; - unsigned int val; - unsigned int flags; -}; - -Given an array of struct futex_waitv, wait on each uaddr. The thread -wakes if a futex_wake() is performed at any uaddr. The syscall returns -immediately if any waiter has *uaddr != val. *timo is an optional -timeout value for the operation. The flags argument of the syscall -should be used solely for specifying the timeout as realtime, if needed. -Flags for shared futexes, sizes, etc. should be used on the individual -flags of each waiter. - -Returns the array index of one of the awakened futexes. There’s no given -information of how many were awakened, or any particular attribute of it -(if it’s the first awakened, if it is of the smaller index...). - -Signed-off-by: André Almeida <andrealmeid@collabora.com> - -Rebased-by: Joshua Ashton <joshua@froggi.es> ---- - arch/arm/tools/syscall.tbl | 1 + - arch/arm64/include/asm/unistd.h | 2 +- - arch/x86/entry/syscalls/syscall_32.tbl | 1 + - arch/x86/entry/syscalls/syscall_64.tbl | 1 + - include/linux/compat.h | 11 ++ - include/linux/syscalls.h | 4 + - include/uapi/asm-generic/unistd.h | 5 +- - include/uapi/linux/futex.h | 14 ++ - kernel/futex2.c | 177 ++++++++++++++++++ - kernel/sys_ni.c | 1 + - tools/include/uapi/asm-generic/unistd.h | 5 +- - .../arch/x86/entry/syscalls/syscall_64.tbl | 1 + - 12 files changed, 220 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl -index b60a8bdab623..6e476c34bd00 100644 ---- a/arch/arm/tools/syscall.tbl -+++ b/arch/arm/tools/syscall.tbl -@@ -462,3 +462,4 @@ - 446 common landlock_restrict_self sys_landlock_restrict_self - 447 common futex_wait sys_futex_wait - 448 common futex_wake sys_futex_wake -+449 common futex_waitv sys_futex_waitv -diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h -index 3cb206aea3db..6bdb5f5db438 100644 ---- a/arch/arm64/include/asm/unistd.h -+++ b/arch/arm64/include/asm/unistd.h -@@ -38,7 +38,7 @@ - #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) - #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) - --#define __NR_compat_syscalls 449 -+#define __NR_compat_syscalls 450 - #endif - - #define __ARCH_WANT_SYS_CLONE -diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl -index f75de79fa93d..b991991a434a 100644 ---- a/arch/x86/entry/syscalls/syscall_32.tbl -+++ b/arch/x86/entry/syscalls/syscall_32.tbl -@@ -453,3 +453,4 @@ - 446 i386 landlock_restrict_self sys_landlock_restrict_self - 447 i386 futex_wait sys_futex_wait - 448 i386 futex_wake sys_futex_wake -+449 i386 futex_waitv sys_futex_waitv compat_sys_futex_waitv -diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl -index 63b447255df2..bad4aca3e9ba 100644 ---- a/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/arch/x86/entry/syscalls/syscall_64.tbl -@@ -370,6 +370,7 @@ - 446 common landlock_restrict_self sys_landlock_restrict_self - 447 common futex_wait sys_futex_wait - 448 common futex_wake sys_futex_wake -+449 common futex_waitv sys_futex_waitv - - # - # Due to a historical design error, certain syscalls are numbered differently -diff --git a/include/linux/compat.h b/include/linux/compat.h -index 8855b1b702b2..06a40776d8a5 100644 ---- a/include/linux/compat.h -+++ b/include/linux/compat.h -@@ -368,6 +368,12 @@ struct compat_robust_list_head { - compat_uptr_t list_op_pending; - }; - -+struct compat_futex_waitv { -+ compat_uptr_t uaddr; -+ compat_uint_t val; -+ compat_uint_t flags; -+}; -+ - #ifdef CONFIG_COMPAT_OLD_SIGACTION - struct compat_old_sigaction { - compat_uptr_t sa_handler; -@@ -692,6 +698,11 @@ asmlinkage long - compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, - compat_size_t __user *len_ptr); - -+/* kernel/futex2.c */ -+asmlinkage long compat_sys_futex_waitv(struct compat_futex_waitv *waiters, -+ compat_uint_t nr_futexes, compat_uint_t flags, -+ struct __kernel_timespec __user *timo); -+ - /* kernel/itimer.c */ - asmlinkage long compat_sys_getitimer(int which, - struct old_itimerval32 __user *it); -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index 0f9b64cc34f7..7d166f7304ae 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -71,6 +71,7 @@ struct open_how; - struct mount_attr; - struct landlock_ruleset_attr; - enum landlock_rule_type; -+struct futex_waitv; - - #include <linux/types.h> - #include <linux/aio_abi.h> -@@ -629,6 +630,9 @@ asmlinkage long sys_futex_wait(void __user *uaddr, unsigned int val, - struct __kernel_timespec __user *timo); - asmlinkage long sys_futex_wake(void __user *uaddr, unsigned int nr_wake, - unsigned int flags); -+asmlinkage long sys_futex_waitv(struct futex_waitv __user *waiters, -+ unsigned int nr_futexes, unsigned int flags, -+ struct __kernel_timespec __user *timo); - - /* kernel/hrtimer.c */ - asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, -diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h -index 2a62ecca2b00..1179d3f02d65 100644 ---- a/include/uapi/asm-generic/unistd.h -+++ b/include/uapi/asm-generic/unistd.h -@@ -879,8 +879,11 @@ __SYSCALL(__NR_futex_wait, sys_futex_wait) - #define __NR_futex_wake 444 - __SYSCALL(__NR_futex_wake, sys_futex_wake) - -+#define __NR_futex_waitv 445 -+__SC_COMP(__NR_futex_waitv, sys_futex_waitv, compat_sys_futex_waitv) -+ - #undef __NR_syscalls --#define __NR_syscalls 449 -+#define __NR_syscalls 450 - - /* - * 32 bit systems traditionally used different -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h -index 70ea66fffb1c..3216aee015d2 100644 ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -48,6 +48,20 @@ - - #define FUTEX_SHARED_FLAG 8 - -+#define FUTEX_WAITV_MAX 128 -+ -+/** -+ * struct futex_waitv - A waiter for vectorized wait -+ * @uaddr: User address to wait on -+ * @val: Expected value at uaddr -+ * @flags: Flags for this waiter -+ */ -+struct futex_waitv { -+ void __user *uaddr; -+ unsigned int val; -+ unsigned int flags; -+}; -+ - /* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. -diff --git a/kernel/futex2.c b/kernel/futex2.c -index 51086d0c3fd5..beb2ce11ac83 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -83,6 +83,12 @@ struct futex_bucket { - /* Mask for futex2 flag operations */ - #define FUTEX2_MASK (FUTEX_SIZE_MASK | FUTEX_CLOCK_REALTIME | FUTEX_SHARED_FLAG) - -+/* Mask for sys_futex_waitv flag */ -+#define FUTEXV_MASK (FUTEX_CLOCK_REALTIME) -+ -+/* Mask for each futex in futex_waitv list */ -+#define FUTEXV_WAITER_MASK (FUTEX_SIZE_MASK | FUTEX_SHARED_FLAG) -+ - #define is_object_shared ((futexv->objects[i].flags & FUTEX_SHARED_FLAG) ? true : false) - - #define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */ -@@ -704,6 +710,177 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val, - return futex_set_timer_and_wait(futexv, 1, timo, flags); - } - -+#ifdef CONFIG_COMPAT -+/** -+ * compat_futex_parse_waitv - Parse a waitv array from userspace -+ * @futexv: Kernel side list of waiters to be filled -+ * @uwaitv: Userspace list to be parsed -+ * @nr_futexes: Length of futexv -+ * -+ * Return: Error code on failure, pointer to a prepared futexv otherwise -+ */ -+static int compat_futex_parse_waitv(struct futex_waiter_head *futexv, -+ struct compat_futex_waitv __user *uwaitv, -+ unsigned int nr_futexes) -+{ -+ struct futex_bucket *bucket; -+ struct compat_futex_waitv waitv; -+ unsigned int i; -+ -+ for (i = 0; i < nr_futexes; i++) { -+ if (copy_from_user(&waitv, &uwaitv[i], sizeof(waitv))) -+ return -EFAULT; -+ -+ if ((waitv.flags & ~FUTEXV_WAITER_MASK) || -+ (waitv.flags & FUTEX_SIZE_MASK) != FUTEX_32) -+ return -EINVAL; -+ -+ futexv->objects[i].key.pointer = 0; -+ futexv->objects[i].flags = waitv.flags; -+ futexv->objects[i].uaddr = compat_ptr(waitv.uaddr); -+ futexv->objects[i].val = waitv.val; -+ futexv->objects[i].index = i; -+ -+ bucket = futex_get_bucket(compat_ptr(waitv.uaddr), -+ &futexv->objects[i].key, -+ is_object_shared); -+ -+ if (IS_ERR(bucket)) -+ return PTR_ERR(bucket); -+ -+ futexv->objects[i].bucket = bucket; -+ -+ INIT_LIST_HEAD(&futexv->objects[i].list); -+ } -+ -+ return 0; -+} -+ -+COMPAT_SYSCALL_DEFINE4(futex_waitv, struct compat_futex_waitv __user *, waiters, -+ unsigned int, nr_futexes, unsigned int, flags, -+ struct __kernel_timespec __user *, timo) -+{ -+ struct futex_waiter_head *futexv; -+ int ret; -+ -+ if (flags & ~FUTEXV_MASK) -+ return -EINVAL; -+ -+ if (!nr_futexes || nr_futexes > FUTEX_WAITV_MAX || !waiters) -+ return -EINVAL; -+ -+ futexv = kmalloc((sizeof(struct futex_waiter) * nr_futexes) + -+ sizeof(*futexv), GFP_KERNEL); -+ if (!futexv) -+ return -ENOMEM; -+ -+ futexv->hint = false; -+ futexv->task = current; -+ -+ ret = compat_futex_parse_waitv(futexv, waiters, nr_futexes); -+ -+ if (!ret) -+ ret = futex_set_timer_and_wait(futexv, nr_futexes, timo, flags); -+ -+ kfree(futexv); -+ -+ return ret; -+} -+#endif -+ -+/** -+ * futex_parse_waitv - Parse a waitv array from userspace -+ * @futexv: Kernel side list of waiters to be filled -+ * @uwaitv: Userspace list to be parsed -+ * @nr_futexes: Length of futexv -+ * -+ * Return: Error code on failure, pointer to a prepared futexv otherwise -+ */ -+static int futex_parse_waitv(struct futex_waiter_head *futexv, -+ struct futex_waitv __user *uwaitv, -+ unsigned int nr_futexes) -+{ -+ struct futex_bucket *bucket; -+ struct futex_waitv waitv; -+ unsigned int i; -+ -+ for (i = 0; i < nr_futexes; i++) { -+ if (copy_from_user(&waitv, &uwaitv[i], sizeof(waitv))) -+ return -EFAULT; -+ -+ if ((waitv.flags & ~FUTEXV_WAITER_MASK) || -+ (waitv.flags & FUTEX_SIZE_MASK) != FUTEX_32) -+ return -EINVAL; -+ -+ futexv->objects[i].key.pointer = 0; -+ futexv->objects[i].flags = waitv.flags; -+ futexv->objects[i].uaddr = waitv.uaddr; -+ futexv->objects[i].val = waitv.val; -+ futexv->objects[i].index = i; -+ -+ bucket = futex_get_bucket(waitv.uaddr, &futexv->objects[i].key, -+ is_object_shared); -+ -+ if (IS_ERR(bucket)) -+ return PTR_ERR(bucket); -+ -+ futexv->objects[i].bucket = bucket; -+ -+ INIT_LIST_HEAD(&futexv->objects[i].list); -+ } -+ -+ return 0; -+} -+ -+/** -+ * sys_futex_waitv - Wait on a list of futexes -+ * @waiters: List of futexes to wait on -+ * @nr_futexes: Length of futexv -+ * @flags: Flag for timeout (monotonic/realtime) -+ * @timo: Optional absolute timeout. -+ * -+ * Given an array of `struct futex_waitv`, wait on each uaddr. The thread wakes -+ * if a futex_wake() is performed at any uaddr. The syscall returns immediately -+ * if any waiter has *uaddr != val. *timo is an optional timeout value for the -+ * operation. Each waiter has individual flags. The `flags` argument for the -+ * syscall should be used solely for specifying the timeout as realtime, if -+ * needed. Flags for shared futexes, sizes, etc. should be used on the -+ * individual flags of each waiter. -+ * -+ * Returns the array index of one of the awaken futexes. There's no given -+ * information of how many were awakened, or any particular attribute of it (if -+ * it's the first awakened, if it is of the smaller index...). -+ */ -+SYSCALL_DEFINE4(futex_waitv, struct futex_waitv __user *, waiters, -+ unsigned int, nr_futexes, unsigned int, flags, -+ struct __kernel_timespec __user *, timo) -+{ -+ struct futex_waiter_head *futexv; -+ int ret; -+ -+ if (flags & ~FUTEXV_MASK) -+ return -EINVAL; -+ -+ if (!nr_futexes || nr_futexes > FUTEX_WAITV_MAX || !waiters) -+ return -EINVAL; -+ -+ futexv = kmalloc((sizeof(struct futex_waiter) * nr_futexes) + -+ sizeof(*futexv), GFP_KERNEL); -+ if (!futexv) -+ return -ENOMEM; -+ -+ futexv->hint = false; -+ futexv->task = current; -+ -+ ret = futex_parse_waitv(futexv, waiters, nr_futexes); -+ if (!ret) -+ ret = futex_set_timer_and_wait(futexv, nr_futexes, timo, flags); -+ -+ kfree(futexv); -+ -+ return ret; -+} -+ - /** - * futex_get_parent - For a given futex in a futexv list, get a pointer to the futexv - * @waiter: Address of futex in the list -diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c -index 9addbe373f00..d70bb8cb884f 100644 ---- a/kernel/sys_ni.c -+++ b/kernel/sys_ni.c -@@ -154,6 +154,7 @@ COND_SYSCALL_COMPAT(get_robust_list); - /* kernel/futex2.c */ - COND_SYSCALL(futex_wait); - COND_SYSCALL(futex_wake); -+COND_SYSCALL(futex_waitv); - - /* kernel/hrtimer.c */ - -diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h -index 2a62ecca2b00..1179d3f02d65 100644 ---- a/tools/include/uapi/asm-generic/unistd.h -+++ b/tools/include/uapi/asm-generic/unistd.h -@@ -879,8 +879,11 @@ __SYSCALL(__NR_futex_wait, sys_futex_wait) - #define __NR_futex_wake 444 - __SYSCALL(__NR_futex_wake, sys_futex_wake) - -+#define __NR_futex_waitv 445 -+__SC_COMP(__NR_futex_waitv, sys_futex_waitv, compat_sys_futex_waitv) -+ - #undef __NR_syscalls --#define __NR_syscalls 449 -+#define __NR_syscalls 450 - - /* - * 32 bit systems traditionally used different -diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -index 8eb17cc08a69..faa5a3442e43 100644 ---- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl -@@ -370,6 +370,7 @@ - 446 common landlock_restrict_self sys_landlock_restrict_self - 447 common futex_wait sys_futex_wait - 448 common futex_wake sys_futex_wake -+449 common futex_waitv sys_futex_waitv - - # - # Due to a historical design error, certain syscalls are numbered differently --- -2.31.1 - - -From 3f11c8e493c1c7a6602ed564ee4c5e074c90b10f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:01 -0300 -Subject: [PATCH 04/14] futex2: Implement requeue operation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implement requeue interface similary to FUTEX_CMP_REQUEUE operation. -This is the syscall implemented by this patch: - -futex_requeue(struct futex_requeue *uaddr1, struct futex_requeue *uaddr2, - unsigned int nr_wake, unsigned int nr_requeue, - unsigned int cmpval, unsigned int flags) - -struct futex_requeue { - void *uaddr; - unsigned int flags; -}; - -If (uaddr1->uaddr == cmpval), wake at uaddr1->uaddr a nr_wake number of -waiters and then, remove a number of nr_requeue waiters at uaddr1->uaddr -and add them to uaddr2->uaddr list. Each uaddr has its own set of flags, -that must be defined at struct futex_requeue (such as size, shared, NUMA). -The flags argument of the syscall is there just for the sake of -extensibility, and right now it needs to be zero. - -Return the number of the woken futexes + the number of requeued ones on -success, error code otherwise. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> - -Rebased-by: Joshua Ashton <joshua@froggi.es> ---- - arch/arm/tools/syscall.tbl | 1 + - arch/arm64/include/asm/unistd.h | 2 +- - arch/x86/entry/syscalls/syscall_32.tbl | 1 + - arch/x86/entry/syscalls/syscall_64.tbl | 1 + - include/linux/compat.h | 12 ++ - include/linux/syscalls.h | 5 + - include/uapi/asm-generic/unistd.h | 5 +- - include/uapi/linux/futex.h | 10 ++ - kernel/futex2.c | 215 +++++++++++++++++++++++++ - kernel/sys_ni.c | 1 + - 10 files changed, 251 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl -index 6e476c34bd00..25f175ada125 100644 ---- a/arch/arm/tools/syscall.tbl -+++ b/arch/arm/tools/syscall.tbl -@@ -463,3 +463,4 @@ - 447 common futex_wait sys_futex_wait - 448 common futex_wake sys_futex_wake - 449 common futex_waitv sys_futex_waitv -+450 common futex_requeue sys_futex_requeue -diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h -index 6bdb5f5db438..4e65da3445c7 100644 ---- a/arch/arm64/include/asm/unistd.h -+++ b/arch/arm64/include/asm/unistd.h -@@ -38,7 +38,7 @@ - #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) - #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) - --#define __NR_compat_syscalls 450 -+#define __NR_compat_syscalls 451 - #endif - - #define __ARCH_WANT_SYS_CLONE -diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl -index b991991a434a..1c3ca8b50247 100644 ---- a/arch/x86/entry/syscalls/syscall_32.tbl -+++ b/arch/x86/entry/syscalls/syscall_32.tbl -@@ -454,3 +454,4 @@ - 447 i386 futex_wait sys_futex_wait - 448 i386 futex_wake sys_futex_wake - 449 i386 futex_waitv sys_futex_waitv compat_sys_futex_waitv -+450 i386 futex_requeue sys_futex_requeue compat_sys_futex_requeue -diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl -index bad4aca3e9ba..a1a39ed156e8 100644 ---- a/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/arch/x86/entry/syscalls/syscall_64.tbl -@@ -371,6 +371,7 @@ - 447 common futex_wait sys_futex_wait - 448 common futex_wake sys_futex_wake - 449 common futex_waitv sys_futex_waitv -+450 common futex_requeue sys_futex_requeue - - # - # Due to a historical design error, certain syscalls are numbered differently -diff --git a/include/linux/compat.h b/include/linux/compat.h -index 06a40776d8a5..34ad63bac18d 100644 ---- a/include/linux/compat.h -+++ b/include/linux/compat.h -@@ -374,6 +374,11 @@ struct compat_futex_waitv { - compat_uint_t flags; - }; - -+struct compat_futex_requeue { -+ compat_uptr_t uaddr; -+ compat_uint_t flags; -+}; -+ - #ifdef CONFIG_COMPAT_OLD_SIGACTION - struct compat_old_sigaction { - compat_uptr_t sa_handler; -@@ -703,6 +708,13 @@ asmlinkage long compat_sys_futex_waitv(struct compat_futex_waitv *waiters, - compat_uint_t nr_futexes, compat_uint_t flags, - struct __kernel_timespec __user *timo); - -+asmlinkage long compat_sys_futex_requeue(struct compat_futex_requeue *uaddr1, -+ struct compat_futex_requeue *uaddr2, -+ compat_uint_t nr_wake, -+ compat_uint_t nr_requeue, -+ compat_uint_t cmpval, -+ compat_uint_t flags); -+ - /* kernel/itimer.c */ - asmlinkage long compat_sys_getitimer(int which, - struct old_itimerval32 __user *it); -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index 7d166f7304ae..aca64b5126a7 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -72,6 +72,7 @@ struct mount_attr; - struct landlock_ruleset_attr; - enum landlock_rule_type; - struct futex_waitv; -+struct futex_requeue; - - #include <linux/types.h> - #include <linux/aio_abi.h> -@@ -633,6 +634,10 @@ asmlinkage long sys_futex_wake(void __user *uaddr, unsigned int nr_wake, - asmlinkage long sys_futex_waitv(struct futex_waitv __user *waiters, - unsigned int nr_futexes, unsigned int flags, - struct __kernel_timespec __user *timo); -+asmlinkage long sys_futex_requeue(struct futex_requeue __user *uaddr1, -+ struct futex_requeue __user *uaddr2, -+ unsigned int nr_wake, unsigned int nr_requeue, -+ unsigned int cmpval, unsigned int flags); - - /* kernel/hrtimer.c */ - asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, -diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h -index 1179d3f02d65..78d30c06b217 100644 ---- a/include/uapi/asm-generic/unistd.h -+++ b/include/uapi/asm-generic/unistd.h -@@ -882,8 +882,11 @@ __SYSCALL(__NR_futex_wake, sys_futex_wake) - #define __NR_futex_waitv 445 - __SC_COMP(__NR_futex_waitv, sys_futex_waitv, compat_sys_futex_waitv) - -+#define __NR_futex_requeue 446 -+__SC_COMP(__NR_futex_requeue, sys_futex_requeue, compat_sys_futex_requeue) -+ - #undef __NR_syscalls --#define __NR_syscalls 450 -+#define __NR_syscalls 451 - - /* - * 32 bit systems traditionally used different -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h -index 3216aee015d2..c15bfddcf1e2 100644 ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -62,6 +62,16 @@ struct futex_waitv { - unsigned int flags; - }; - -+/** -+ * struct futex_requeue - Define an address and its flags for requeue operation -+ * @uaddr: User address of one of the requeue arguments -+ * @flags: Flags for this address -+ */ -+struct futex_requeue { -+ void __user *uaddr; -+ unsigned int flags; -+}; -+ - /* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. -diff --git a/kernel/futex2.c b/kernel/futex2.c -index beb2ce11ac83..0d1db071c363 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -975,6 +975,221 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, - return ret; - } - -+static void futex_double_unlock(struct futex_bucket *b1, struct futex_bucket *b2) -+{ -+ spin_unlock(&b1->lock); -+ if (b1 != b2) -+ spin_unlock(&b2->lock); -+} -+ -+static inline int __futex_requeue(struct futex_requeue rq1, -+ struct futex_requeue rq2, unsigned int nr_wake, -+ unsigned int nr_requeue, unsigned int cmpval, -+ bool shared1, bool shared2) -+{ -+ struct futex_waiter w1, w2, *aux, *tmp; -+ bool retry = false; -+ struct futex_bucket *b1, *b2; -+ DEFINE_WAKE_Q(wake_q); -+ u32 uval; -+ int ret; -+ -+ b1 = futex_get_bucket(rq1.uaddr, &w1.key, shared1); -+ if (IS_ERR(b1)) -+ return PTR_ERR(b1); -+ -+ b2 = futex_get_bucket(rq2.uaddr, &w2.key, shared2); -+ if (IS_ERR(b2)) -+ return PTR_ERR(b2); -+ -+retry: -+ if (shared1 && retry) { -+ b1 = futex_get_bucket(rq1.uaddr, &w1.key, shared1); -+ if (IS_ERR(b1)) -+ return PTR_ERR(b1); -+ } -+ -+ if (shared2 && retry) { -+ b2 = futex_get_bucket(rq2.uaddr, &w2.key, shared2); -+ if (IS_ERR(b2)) -+ return PTR_ERR(b2); -+ } -+ -+ bucket_inc_waiters(b2); -+ /* -+ * To ensure the locks are taken in the same order for all threads (and -+ * thus avoiding deadlocks), take the "smaller" one first -+ */ -+ if (b1 <= b2) { -+ spin_lock(&b1->lock); -+ if (b1 < b2) -+ spin_lock_nested(&b2->lock, SINGLE_DEPTH_NESTING); -+ } else { -+ spin_lock(&b2->lock); -+ spin_lock_nested(&b1->lock, SINGLE_DEPTH_NESTING); -+ } -+ -+ ret = futex_get_user(&uval, rq1.uaddr); -+ -+ if (unlikely(ret)) { -+ futex_double_unlock(b1, b2); -+ if (__get_user(uval, (u32 __user *)rq1.uaddr)) -+ return -EFAULT; -+ -+ bucket_dec_waiters(b2); -+ retry = true; -+ goto retry; -+ } -+ -+ if (uval != cmpval) { -+ futex_double_unlock(b1, b2); -+ -+ bucket_dec_waiters(b2); -+ return -EAGAIN; -+ } -+ -+ list_for_each_entry_safe(aux, tmp, &b1->list, list) { -+ if (futex_match(w1.key, aux->key)) { -+ if (ret < nr_wake) { -+ futex_mark_wake(aux, b1, &wake_q); -+ ret++; -+ continue; -+ } -+ -+ if (ret >= nr_wake + nr_requeue) -+ break; -+ -+ aux->key.pointer = w2.key.pointer; -+ aux->key.index = w2.key.index; -+ aux->key.offset = w2.key.offset; -+ -+ if (b1 != b2) { -+ list_del_init_careful(&aux->list); -+ bucket_dec_waiters(b1); -+ -+ list_add_tail(&aux->list, &b2->list); -+ bucket_inc_waiters(b2); -+ } -+ ret++; -+ } -+ } -+ -+ futex_double_unlock(b1, b2); -+ wake_up_q(&wake_q); -+ bucket_dec_waiters(b2); -+ -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+static int compat_futex_parse_requeue(struct futex_requeue *rq, -+ struct compat_futex_requeue __user *uaddr, -+ bool *shared) -+{ -+ struct compat_futex_requeue tmp; -+ -+ if (copy_from_user(&tmp, uaddr, sizeof(tmp))) -+ return -EFAULT; -+ -+ if (tmp.flags & ~FUTEXV_WAITER_MASK || -+ (tmp.flags & FUTEX_SIZE_MASK) != FUTEX_32) -+ return -EINVAL; -+ -+ *shared = (tmp.flags & FUTEX_SHARED_FLAG) ? true : false; -+ -+ rq->uaddr = compat_ptr(tmp.uaddr); -+ rq->flags = tmp.flags; -+ -+ return 0; -+} -+ -+COMPAT_SYSCALL_DEFINE6(futex_requeue, struct compat_futex_requeue __user *, uaddr1, -+ struct compat_futex_requeue __user *, uaddr2, -+ unsigned int, nr_wake, unsigned int, nr_requeue, -+ unsigned int, cmpval, unsigned int, flags) -+{ -+ struct futex_requeue rq1, rq2; -+ bool shared1, shared2; -+ int ret; -+ -+ if (flags) -+ return -EINVAL; -+ -+ ret = compat_futex_parse_requeue(&rq1, uaddr1, &shared1); -+ if (ret) -+ return ret; -+ -+ ret = compat_futex_parse_requeue(&rq2, uaddr2, &shared2); -+ if (ret) -+ return ret; -+ -+ return __futex_requeue(rq1, rq2, nr_wake, nr_requeue, cmpval, shared1, shared2); -+} -+#endif -+ -+/** -+ * futex_parse_requeue - Copy a user struct futex_requeue and check it's flags -+ * @rq: Kernel struct -+ * @uaddr: Address of user struct -+ * @shared: Out parameter, defines if this is a shared futex -+ * -+ * Return: 0 on success, error code otherwise -+ */ -+static int futex_parse_requeue(struct futex_requeue *rq, -+ struct futex_requeue __user *uaddr, bool *shared) -+{ -+ if (copy_from_user(rq, uaddr, sizeof(*rq))) -+ return -EFAULT; -+ -+ if (rq->flags & ~FUTEXV_WAITER_MASK || -+ (rq->flags & FUTEX_SIZE_MASK) != FUTEX_32) -+ return -EINVAL; -+ -+ *shared = (rq->flags & FUTEX_SHARED_FLAG) ? true : false; -+ -+ return 0; -+} -+ -+/** -+ * sys_futex_requeue - Wake futexes at uaddr1 and requeue from uaddr1 to uaddr2 -+ * @uaddr1: Address of futexes to be waken/dequeued -+ * @uaddr2: Address for the futexes to be enqueued -+ * @nr_wake: Number of futexes waiting in uaddr1 to be woken up -+ * @nr_requeue: Number of futexes to be requeued from uaddr1 to uaddr2 -+ * @cmpval: Expected value at uaddr1 -+ * @flags: Reserved flags arg for requeue operation expansion. Must be 0. -+ * -+ * If (uaddr1->uaddr == cmpval), wake at uaddr1->uaddr a nr_wake number of -+ * waiters and then, remove a number of nr_requeue waiters at uaddr1->uaddr -+ * and add then to uaddr2->uaddr list. Each uaddr has its own set of flags, -+ * that must be defined at struct futex_requeue (such as size, shared, NUMA). -+ * -+ * Return the number of the woken futexes + the number of requeued ones on -+ * success, error code otherwise. -+ */ -+SYSCALL_DEFINE6(futex_requeue, struct futex_requeue __user *, uaddr1, -+ struct futex_requeue __user *, uaddr2, -+ unsigned int, nr_wake, unsigned int, nr_requeue, -+ unsigned int, cmpval, unsigned int, flags) -+{ -+ struct futex_requeue rq1, rq2; -+ bool shared1, shared2; -+ int ret; -+ -+ if (flags) -+ return -EINVAL; -+ -+ ret = futex_parse_requeue(&rq1, uaddr1, &shared1); -+ if (ret) -+ return ret; -+ -+ ret = futex_parse_requeue(&rq2, uaddr2, &shared2); -+ if (ret) -+ return ret; -+ -+ return __futex_requeue(rq1, rq2, nr_wake, nr_requeue, cmpval, shared1, shared2); -+} -+ - static int __init futex2_init(void) - { - int i; -diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c -index d70bb8cb884f..af0b1ef09d93 100644 ---- a/kernel/sys_ni.c -+++ b/kernel/sys_ni.c -@@ -155,6 +155,7 @@ COND_SYSCALL_COMPAT(get_robust_list); - COND_SYSCALL(futex_wait); - COND_SYSCALL(futex_wake); - COND_SYSCALL(futex_waitv); -+COND_SYSCALL(futex_requeue); - - /* kernel/hrtimer.c */ - --- -2.31.1 - - -From 75ed26356ac56c0110ee39243b8c2948751cfd36 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Thu, 11 Feb 2021 10:47:23 -0300 -Subject: [PATCH 05/14] futex2: Add compatibility entry point for x86_x32 ABI -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -New syscalls should use the same entry point for x86_64 and x86_x32 -paths. Add a wrapper for x32 calls to use parse functions that assumes -32bit pointers. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - kernel/futex2.c | 42 +++++++++++++++++++++++++++++++++++------- - 1 file changed, 35 insertions(+), 7 deletions(-) - -diff --git a/kernel/futex2.c b/kernel/futex2.c -index 0d1db071c363..22ba9b3e45e2 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -23,6 +23,10 @@ - #include <linux/syscalls.h> - #include <uapi/linux/futex.h> - -+#ifdef CONFIG_X86_64 -+#include <linux/compat.h> -+#endif -+ - /** - * struct futex_key - Components to build unique key for a futex - * @pointer: Pointer to current->mm or inode's UUID for file backed futexes -@@ -872,7 +876,16 @@ SYSCALL_DEFINE4(futex_waitv, struct futex_waitv __user *, waiters, - futexv->hint = false; - futexv->task = current; - -- ret = futex_parse_waitv(futexv, waiters, nr_futexes); -+#ifdef CONFIG_X86_X32_ABI -+ if (in_x32_syscall()) { -+ ret = compat_futex_parse_waitv(futexv, (struct compat_futex_waitv *)waiters, -+ nr_futexes); -+ } else -+#endif -+ { -+ ret = futex_parse_waitv(futexv, waiters, nr_futexes); -+ } -+ - if (!ret) - ret = futex_set_timer_and_wait(futexv, nr_futexes, timo, flags); - -@@ -1179,13 +1192,28 @@ SYSCALL_DEFINE6(futex_requeue, struct futex_requeue __user *, uaddr1, - if (flags) - return -EINVAL; - -- ret = futex_parse_requeue(&rq1, uaddr1, &shared1); -- if (ret) -- return ret; -+#ifdef CONFIG_X86_X32_ABI -+ if (in_x32_syscall()) { -+ ret = compat_futex_parse_requeue(&rq1, (struct compat_futex_requeue *)uaddr1, -+ &shared1); -+ if (ret) -+ return ret; - -- ret = futex_parse_requeue(&rq2, uaddr2, &shared2); -- if (ret) -- return ret; -+ ret = compat_futex_parse_requeue(&rq2, (struct compat_futex_requeue *)uaddr2, -+ &shared2); -+ if (ret) -+ return ret; -+ } else -+#endif -+ { -+ ret = futex_parse_requeue(&rq1, uaddr1, &shared1); -+ if (ret) -+ return ret; -+ -+ ret = futex_parse_requeue(&rq2, uaddr2, &shared2); -+ if (ret) -+ return ret; -+ } - - return __futex_requeue(rq1, rq2, nr_wake, nr_requeue, cmpval, shared1, shared2); - } --- -2.31.1 - - -From ccdfc0a01aca5de728da256a2e5dea1d8a2ffc1f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Tue, 9 Feb 2021 13:59:00 -0300 -Subject: [PATCH 06/14] docs: locking: futex2: Add documentation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add a new documentation file specifying both userspace API and internal -implementation details of futex2 syscalls. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - Documentation/locking/futex2.rst | 198 +++++++++++++++++++++++++++++++ - Documentation/locking/index.rst | 1 + - 2 files changed, 199 insertions(+) - create mode 100644 Documentation/locking/futex2.rst - -diff --git a/Documentation/locking/futex2.rst b/Documentation/locking/futex2.rst -new file mode 100644 -index 000000000000..13a7699bd6fc ---- /dev/null -+++ b/Documentation/locking/futex2.rst -@@ -0,0 +1,198 @@ -+.. SPDX-License-Identifier: GPL-2.0 -+ -+====== -+futex2 -+====== -+ -+:Author: André Almeida <andrealmeid@collabora.com> -+ -+futex, or fast user mutex, is a set of syscalls to allow userspace to create -+performant synchronization mechanisms, such as mutexes, semaphores and -+conditional variables in userspace. C standard libraries, like glibc, uses it -+as a means to implement more high level interfaces like pthreads. -+ -+The interface -+============= -+ -+uAPI functions -+-------------- -+ -+.. kernel-doc:: kernel/futex2.c -+ :identifiers: sys_futex_wait sys_futex_wake sys_futex_waitv sys_futex_requeue -+ -+uAPI structures -+--------------- -+ -+.. kernel-doc:: include/uapi/linux/futex.h -+ -+The ``flag`` argument -+--------------------- -+ -+The flag is used to specify the size of the futex word -+(FUTEX_[8, 16, 32]). It's mandatory to define one, since there's no -+default size. -+ -+By default, the timeout uses a monotonic clock, but can be used as a realtime -+one by using the FUTEX_REALTIME_CLOCK flag. -+ -+By default, futexes are of the private type, that means that this user address -+will be accessed by threads that share the same memory region. This allows for -+some internal optimizations, so they are faster. However, if the address needs -+to be shared with different processes (like using ``mmap()`` or ``shm()``), they -+need to be defined as shared and the flag FUTEX_SHARED_FLAG is used to set that. -+ -+By default, the operation has no NUMA-awareness, meaning that the user can't -+choose the memory node where the kernel side futex data will be stored. The -+user can choose the node where it wants to operate by setting the -+FUTEX_NUMA_FLAG and using the following structure (where X can be 8, 16, or -+32):: -+ -+ struct futexX_numa { -+ __uX value; -+ __sX hint; -+ }; -+ -+This structure should be passed at the ``void *uaddr`` of futex functions. The -+address of the structure will be used to be waited on/waken on, and the -+``value`` will be compared to ``val`` as usual. The ``hint`` member is used to -+define which node the futex will use. When waiting, the futex will be -+registered on a kernel-side table stored on that node; when waking, the futex -+will be searched for on that given table. That means that there's no redundancy -+between tables, and the wrong ``hint`` value will lead to undesired behavior. -+Userspace is responsible for dealing with node migrations issues that may -+occur. ``hint`` can range from [0, MAX_NUMA_NODES), for specifying a node, or -+-1, to use the same node the current process is using. -+ -+When not using FUTEX_NUMA_FLAG on a NUMA system, the futex will be stored on a -+global table on allocated on the first node. -+ -+The ``timo`` argument -+--------------------- -+ -+As per the Y2038 work done in the kernel, new interfaces shouldn't add timeout -+options known to be buggy. Given that, ``timo`` should be a 64-bit timeout at -+all platforms, using an absolute timeout value. -+ -+Implementation -+============== -+ -+The internal implementation follows a similar design to the original futex. -+Given that we want to replicate the same external behavior of current futex, -+this should be somewhat expected. -+ -+Waiting -+------- -+ -+For the wait operations, they are all treated as if you want to wait on N -+futexes, so the path for futex_wait and futex_waitv is the basically the same. -+For both syscalls, the first step is to prepare an internal list for the list -+of futexes to wait for (using struct futexv_head). For futex_wait() calls, this -+list will have a single object. -+ -+We have a hash table, where waiters register themselves before sleeping. Then -+the wake function checks this table looking for waiters at uaddr. The hash -+bucket to be used is determined by a struct futex_key, that stores information -+to uniquely identify an address from a given process. Given the huge address -+space, there'll be hash collisions, so we store information to be later used on -+collision treatment. -+ -+First, for every futex we want to wait on, we check if (``*uaddr == val``). -+This check is done holding the bucket lock, so we are correctly serialized with -+any futex_wake() calls. If any waiter fails the check above, we dequeue all -+futexes. The check (``*uaddr == val``) can fail for two reasons: -+ -+- The values are different, and we return -EAGAIN. However, if while -+ dequeueing we found that some futexes were awakened, we prioritize this -+ and return success. -+ -+- When trying to access the user address, we do so with page faults -+ disabled because we are holding a bucket's spin lock (and can't sleep -+ while holding a spin lock). If there's an error, it might be a page -+ fault, or an invalid address. We release the lock, dequeue everyone -+ (because it's illegal to sleep while there are futexes enqueued, we -+ could lose wakeups) and try again with page fault enabled. If we -+ succeed, this means that the address is valid, but we need to do -+ all the work again. For serialization reasons, we need to have the -+ spin lock when getting the user value. Additionally, for shared -+ futexes, we also need to recalculate the hash, since the underlying -+ mapping mechanisms could have changed when dealing with page fault. -+ If, even with page fault enabled, we can't access the address, it -+ means it's an invalid user address, and we return -EFAULT. For this -+ case, we prioritize the error, even if some futexes were awaken. -+ -+If the check is OK, they are enqueued on a linked list in our bucket, and -+proceed to the next one. If all waiters succeed, we put the thread to sleep -+until a futex_wake() call, timeout expires or we get a signal. After waking up, -+we dequeue everyone, and check if some futex was awakened. This dequeue is done -+by iteratively walking at each element of struct futex_head list. -+ -+All enqueuing/dequeuing operations requires to hold the bucket lock, to avoid -+racing while modifying the list. -+ -+Waking -+------ -+ -+We get the bucket that's storing the waiters at uaddr, and wake the required -+number of waiters, checking for hash collision. -+ -+There's an optimization that makes futex_wake() not take the bucket lock if -+there's no one to be woken on that bucket. It checks an atomic counter that each -+bucket has, if it says 0, then the syscall exits. In order for this to work, the -+waiter thread increases it before taking the lock, so the wake thread will -+correctly see that there's someone waiting and will continue the path to take -+the bucket lock. To get the correct serialization, the waiter issues a memory -+barrier after increasing the bucket counter and the waker issues a memory -+barrier before checking it. -+ -+Requeuing -+--------- -+ -+The requeue path first checks for each struct futex_requeue and their flags. -+Then, it will compare the expected value with the one at uaddr1::uaddr. -+Following the same serialization explained at Waking_, we increase the atomic -+counter for the bucket of uaddr2 before taking the lock. We need to have both -+buckets locks at same time so we don't race with other futex operation. To -+ensure the locks are taken in the same order for all threads (and thus avoiding -+deadlocks), every requeue operation takes the "smaller" bucket first, when -+comparing both addresses. -+ -+If the compare with user value succeeds, we proceed by waking ``nr_wake`` -+futexes, and then requeuing ``nr_requeue`` from bucket of uaddr1 to the uaddr2. -+This consists in a simple list deletion/addition and replacing the old futex key -+with the new one. -+ -+Futex keys -+---------- -+ -+There are two types of futexes: private and shared ones. The private are futexes -+meant to be used by threads that share the same memory space, are easier to be -+uniquely identified and thus can have some performance optimization. The -+elements for identifying one are: the start address of the page where the -+address is, the address offset within the page and the current->mm pointer. -+ -+Now, for uniquely identifying a shared futex: -+ -+- If the page containing the user address is an anonymous page, we can -+ just use the same data used for private futexes (the start address of -+ the page, the address offset within the page and the current->mm -+ pointer); that will be enough for uniquely identifying such futex. We -+ also set one bit at the key to differentiate if a private futex is -+ used on the same address (mixing shared and private calls does not -+ work). -+ -+- If the page is file-backed, current->mm maybe isn't the same one for -+ every user of this futex, so we need to use other data: the -+ page->index, a UUID for the struct inode and the offset within the -+ page. -+ -+Note that members of futex_key don't have any particular meaning after they -+are part of the struct - they are just bytes to identify a futex. Given that, -+we don't need to use a particular name or type that matches the original data, -+we only need to care about the bitsize of each component and make both private -+and shared fit in the same memory space. -+ -+Source code documentation -+========================= -+ -+.. kernel-doc:: kernel/futex2.c -+ :no-identifiers: sys_futex_wait sys_futex_wake sys_futex_waitv sys_futex_requeue -diff --git a/Documentation/locking/index.rst b/Documentation/locking/index.rst -index 7003bd5aeff4..9bf03c7fa1ec 100644 ---- a/Documentation/locking/index.rst -+++ b/Documentation/locking/index.rst -@@ -24,6 +24,7 @@ locking - percpu-rw-semaphore - robust-futexes - robust-futex-ABI -+ futex2 - - .. only:: subproject and html - --- -2.31.1 - - -From 213a8dc8b0266d98f95d7b5d642abbbf9a636d2b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:01 -0300 -Subject: [PATCH 07/14] selftests: futex2: Add wake/wait test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add a simple file to test wake/wait mechanism using futex2 interface. -Test three scenarios: using a common local int variable as private -futex, a shm futex as shared futex and a file-backed shared memory as a -shared futex. This should test all branches of futex_get_key(). - -Create helper files so more tests can evaluate futex2. While 32bit ABIs -from glibc aren't yet able to use 64 bit sized time variables, add a -temporary workaround that implements the required types and calls the -appropriated syscalls, since futex2 doesn't supports 32 bit sized time. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - .../selftests/futex/functional/.gitignore | 1 + - .../selftests/futex/functional/Makefile | 6 +- - .../selftests/futex/functional/futex2_wait.c | 209 ++++++++++++++++++ - .../testing/selftests/futex/functional/run.sh | 3 + - .../selftests/futex/include/futex2test.h | 79 +++++++ - 5 files changed, 296 insertions(+), 2 deletions(-) - create mode 100644 tools/testing/selftests/futex/functional/futex2_wait.c - create mode 100644 tools/testing/selftests/futex/include/futex2test.h - -diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore -index 0efcd494daab..d61f1df94360 100644 ---- a/tools/testing/selftests/futex/functional/.gitignore -+++ b/tools/testing/selftests/futex/functional/.gitignore -@@ -6,3 +6,4 @@ futex_wait_private_mapped_file - futex_wait_timeout - futex_wait_uninitialized_heap - futex_wait_wouldblock -+futex2_wait -diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile -index 23207829ec75..9b334f190759 100644 ---- a/tools/testing/selftests/futex/functional/Makefile -+++ b/tools/testing/selftests/futex/functional/Makefile -@@ -1,10 +1,11 @@ - # SPDX-License-Identifier: GPL-2.0 --INCLUDES := -I../include -I../../ -+INCLUDES := -I../include -I../../ -I../../../../../usr/include/ - CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES) - LDLIBS := -lpthread -lrt - - HEADERS := \ - ../include/futextest.h \ -+ ../include/futex2test.h \ - ../include/atomic.h \ - ../include/logging.h - TEST_GEN_FILES := \ -@@ -14,7 +15,8 @@ TEST_GEN_FILES := \ - futex_requeue_pi_signal_restart \ - futex_requeue_pi_mismatched_ops \ - futex_wait_uninitialized_heap \ -- futex_wait_private_mapped_file -+ futex_wait_private_mapped_file \ -+ futex2_wait - - TEST_PROGS := run.sh - -diff --git a/tools/testing/selftests/futex/functional/futex2_wait.c b/tools/testing/selftests/futex/functional/futex2_wait.c -new file mode 100644 -index 000000000000..752a26b33bf8 ---- /dev/null -+++ b/tools/testing/selftests/futex/functional/futex2_wait.c -@@ -0,0 +1,209 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/****************************************************************************** -+ * -+ * Copyright Collabora Ltd., 2021 -+ * -+ * DESCRIPTION -+ * Test wait/wake mechanism of futex2, using 32bit sized futexes. -+ * -+ * AUTHOR -+ * André Almeida <andrealmeid@collabora.com> -+ * -+ * HISTORY -+ * 2021-Feb-5: Initial version by André <andrealmeid@collabora.com> -+ * -+ *****************************************************************************/ -+ -+#include <errno.h> -+#include <error.h> -+#include <getopt.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <time.h> -+#include <pthread.h> -+#include <sys/shm.h> -+#include <sys/mman.h> -+#include <fcntl.h> -+#include <string.h> -+#include "futex2test.h" -+#include "logging.h" -+ -+#define TEST_NAME "futex2-wait" -+#define timeout_ns 30000000 -+#define WAKE_WAIT_US 10000 -+#define SHM_PATH "futex2_shm_file" -+futex_t *f1; -+ -+void usage(char *prog) -+{ -+ printf("Usage: %s\n", prog); -+ printf(" -c Use color\n"); -+ printf(" -h Display this help message\n"); -+ printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", -+ VQUIET, VCRITICAL, VINFO); -+} -+ -+void *waiterfn(void *arg) -+{ -+ struct timespec64 to64; -+ unsigned int flags = 0; -+ -+ if (arg) -+ flags = *((unsigned int *) arg); -+ -+ /* setting absolute timeout for futex2 */ -+ if (gettime64(CLOCK_MONOTONIC, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_nsec += timeout_ns; -+ -+ if (to64.tv_nsec >= 1000000000) { -+ to64.tv_sec++; -+ to64.tv_nsec -= 1000000000; -+ } -+ -+ if (futex2_wait(f1, *f1, FUTEX_32 | flags, &to64)) -+ printf("waiter failed errno %d\n", errno); -+ -+ return NULL; -+} -+ -+void *waitershm(void *arg) -+{ -+ futex2_wait(arg, 0, FUTEX_32 | FUTEX_SHARED_FLAG, NULL); -+ -+ return NULL; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ pthread_t waiter; -+ unsigned int flags = FUTEX_SHARED_FLAG; -+ int res, ret = RET_PASS; -+ int c; -+ futex_t f_private = 0; -+ -+ f1 = &f_private; -+ -+ while ((c = getopt(argc, argv, "cht:v:")) != -1) { -+ switch (c) { -+ case 'c': -+ log_color(1); -+ break; -+ case 'h': -+ usage(basename(argv[0])); -+ exit(0); -+ case 'v': -+ log_verbosity(atoi(optarg)); -+ break; -+ default: -+ usage(basename(argv[0])); -+ exit(1); -+ } -+ } -+ -+ ksft_print_header(); -+ ksft_set_plan(3); -+ ksft_print_msg("%s: Test FUTEX2_WAIT\n", -+ basename(argv[0])); -+ -+ /* Testing a private futex */ -+ info("Calling private futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1); -+ -+ if (pthread_create(&waiter, NULL, waiterfn, NULL)) -+ error("pthread_create failed\n", errno); -+ -+ usleep(WAKE_WAIT_US); -+ -+ info("Calling private futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1); -+ res = futex2_wake(f1, 1, FUTEX_32); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_wake private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wake private succeeds\n"); -+ } -+ -+ int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); -+ -+ if (shm_id < 0) { -+ perror("shmget"); -+ exit(1); -+ } -+ -+ /* Testing an anon page shared memory */ -+ unsigned int *shared_data = shmat(shm_id, NULL, 0); -+ -+ *shared_data = 0; -+ f1 = shared_data; -+ -+ info("Calling shared futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1); -+ -+ if (pthread_create(&waiter, NULL, waiterfn, &flags)) -+ error("pthread_create failed\n", errno); -+ -+ usleep(WAKE_WAIT_US); -+ -+ info("Calling shared futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1); -+ res = futex2_wake(f1, 1, FUTEX_32 | FUTEX_SHARED_FLAG); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_wake shared (shmget) returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wake shared (shmget) succeeds\n"); -+ } -+ -+ shmdt(shared_data); -+ -+ /* Testing a file backed shared memory */ -+ void *shm; -+ int fd, pid; -+ -+ f_private = 0; -+ -+ fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); -+ if (fd < 0) { -+ perror("open"); -+ exit(1); -+ } -+ -+ res = ftruncate(fd, sizeof(f_private)); -+ if (res) { -+ perror("ftruncate"); -+ exit(1); -+ } -+ -+ shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ if (shm == MAP_FAILED) { -+ perror("mmap"); -+ exit(1); -+ } -+ -+ memcpy(shm, &f_private, sizeof(f_private)); -+ -+ pthread_create(&waiter, NULL, waitershm, shm); -+ -+ usleep(WAKE_WAIT_US); -+ -+ res = futex2_wake(shm, 1, FUTEX_32 | FUTEX_SHARED_FLAG); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_wake shared (mmap) returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wake shared (mmap) succeeds\n"); -+ } -+ -+ munmap(shm, sizeof(f_private)); -+ -+ remove(SHM_PATH); -+ -+ ksft_print_cnts(); -+ return ret; -+} -diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh -index 1acb6ace1680..3730159c865a 100755 ---- a/tools/testing/selftests/futex/functional/run.sh -+++ b/tools/testing/selftests/futex/functional/run.sh -@@ -73,3 +73,6 @@ echo - echo - ./futex_wait_uninitialized_heap $COLOR - ./futex_wait_private_mapped_file $COLOR -+ -+echo -+./futex2_wait $COLOR -diff --git a/tools/testing/selftests/futex/include/futex2test.h b/tools/testing/selftests/futex/include/futex2test.h -new file mode 100644 -index 000000000000..917ac8909a3b ---- /dev/null -+++ b/tools/testing/selftests/futex/include/futex2test.h -@@ -0,0 +1,79 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/****************************************************************************** -+ * -+ * Copyright Collabora Ltd., 2021 -+ * -+ * DESCRIPTION -+ * Futex2 library addons for old futex library -+ * -+ * AUTHOR -+ * André Almeida <andrealmeid@collabora.com> -+ * -+ * HISTORY -+ * 2021-Feb-5: Initial version by André <andrealmeid@collabora.com> -+ * -+ *****************************************************************************/ -+#include "futextest.h" -+#include <stdio.h> -+ -+#define NSEC_PER_SEC 1000000000L -+ -+#ifndef FUTEX_8 -+# define FUTEX_8 0 -+#endif -+#ifndef FUTEX_16 -+# define FUTEX_16 1 -+#endif -+#ifndef FUTEX_32 -+# define FUTEX_32 2 -+#endif -+ -+/* -+ * - Y2038 section for 32-bit applications - -+ * -+ * Remove this when glibc is ready for y2038. Then, always compile with -+ * `-DTIME_BITS=64` or `-D__USE_TIME_BITS64`. glibc will provide both -+ * timespec64 and clock_gettime64 so we won't need to define here. -+ */ -+#if defined(__i386__) || __TIMESIZE == 32 -+# define NR_gettime __NR_clock_gettime64 -+#else -+# define NR_gettime __NR_clock_gettime -+#endif -+ -+struct timespec64 { -+ long long tv_sec; /* seconds */ -+ long long tv_nsec; /* nanoseconds */ -+}; -+ -+int gettime64(clock_t clockid, struct timespec64 *tv) -+{ -+ return syscall(NR_gettime, clockid, tv); -+} -+/* -+ * - End of Y2038 section - -+ */ -+ -+/** -+ * futex2_wait - If (*uaddr == val), wait at uaddr until timo -+ * @uaddr: User address to wait on -+ * @val: Expected value at uaddr, return if is not equal -+ * @flags: Operation flags -+ * @timo: Optional timeout for operation -+ */ -+static inline int futex2_wait(volatile void *uaddr, unsigned long val, -+ unsigned long flags, struct timespec64 *timo) -+{ -+ return syscall(__NR_futex_wait, uaddr, val, flags, timo); -+} -+ -+/** -+ * futex2_wake - Wake a number of waiters at uaddr -+ * @uaddr: Address to wake -+ * @nr: Number of waiters to wake -+ * @flags: Operation flags -+ */ -+static inline int futex2_wake(volatile void *uaddr, unsigned int nr, unsigned long flags) -+{ -+ return syscall(__NR_futex_wake, uaddr, nr, flags); -+} --- -2.31.1 - - -From daefe54ab3e913048e88050a66f81d5e678287c0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:01 -0300 -Subject: [PATCH 08/14] selftests: futex2: Add timeout test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adapt existing futex wait timeout file to test the same mechanism for -futex2. futex2 accepts only absolute 64bit timers, but supports both -monotonic and realtime clocks. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - .../futex/functional/futex_wait_timeout.c | 58 ++++++++++++++++--- - 1 file changed, 49 insertions(+), 9 deletions(-) - -diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c -index ee55e6d389a3..4569bf303b05 100644 ---- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c -+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c -@@ -11,6 +11,7 @@ - * - * HISTORY - * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> -+ * 2021-Feb-5: Add futex2 test by André <andrealmeid@collabora.com> - * - *****************************************************************************/ - -@@ -20,7 +21,7 @@ - #include <stdlib.h> - #include <string.h> - #include <time.h> --#include "futextest.h" -+#include "futex2test.h" - #include "logging.h" - - #define TEST_NAME "futex-wait-timeout" -@@ -40,7 +41,8 @@ void usage(char *prog) - int main(int argc, char *argv[]) - { - futex_t f1 = FUTEX_INITIALIZER; -- struct timespec to; -+ struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns}; -+ struct timespec64 to64; - int res, ret = RET_PASS; - int c; - -@@ -65,22 +67,60 @@ int main(int argc, char *argv[]) - } - - ksft_print_header(); -- ksft_set_plan(1); -+ ksft_set_plan(3); - ksft_print_msg("%s: Block on a futex and wait for timeout\n", - basename(argv[0])); - ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns); - -- /* initialize timeout */ -- to.tv_sec = 0; -- to.tv_nsec = timeout_ns; -- - info("Calling futex_wait on f1: %u @ %p\n", f1, &f1); - res = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG); - if (!res || errno != ETIMEDOUT) { -- fail("futex_wait returned %d\n", ret < 0 ? errno : ret); -+ ksft_test_result_fail("futex_wait returned %d\n", ret < 0 ? errno : ret); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex_wait timeout succeeds\n"); -+ } -+ -+ /* setting absolute monotonic timeout for futex2 */ -+ if (gettime64(CLOCK_MONOTONIC, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_nsec += timeout_ns; -+ -+ if (to64.tv_nsec >= 1000000000) { -+ to64.tv_sec++; -+ to64.tv_nsec -= 1000000000; -+ } -+ -+ info("Calling futex2_wait on f1: %u @ %p\n", f1, &f1); -+ res = futex2_wait(&f1, f1, FUTEX_32, &to64); -+ if (!res || errno != ETIMEDOUT) { -+ ksft_test_result_fail("futex2_wait monotonic returned %d\n", ret < 0 ? errno : ret); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wait monotonic timeout succeeds\n"); -+ } -+ -+ /* setting absolute realtime timeout for futex2 */ -+ if (gettime64(CLOCK_REALTIME, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_nsec += timeout_ns; -+ -+ if (to64.tv_nsec >= 1000000000) { -+ to64.tv_sec++; -+ to64.tv_nsec -= 1000000000; -+ } -+ -+ info("Calling futex2_wait on f1: %u @ %p\n", f1, &f1); -+ res = futex2_wait(&f1, f1, FUTEX_32 | FUTEX_CLOCK_REALTIME, &to64); -+ if (!res || errno != ETIMEDOUT) { -+ ksft_test_result_fail("futex2_wait realtime returned %d\n", ret < 0 ? errno : ret); - ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wait realtime timeout succeeds\n"); - } - -- print_result(TEST_NAME, ret); -+ ksft_print_cnts(); - return ret; - } --- -2.31.1 - - -From ffc9b6260a0a8f12da9aa20f3c0a91bf90e732aa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:01 -0300 -Subject: [PATCH 09/14] selftests: futex2: Add wouldblock test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adapt existing futex wait wouldblock file to test the same mechanism for -futex2. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - .../futex/functional/futex_wait_wouldblock.c | 33 ++++++++++++++++--- - 1 file changed, 29 insertions(+), 4 deletions(-) - -diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c -index 0ae390ff8164..b1d463ebb33d 100644 ---- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c -+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c -@@ -12,6 +12,7 @@ - * - * HISTORY - * 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com> -+ * 2021-Feb-5: Add futex2 test by André <andrealmeid@collabora.com> - * - *****************************************************************************/ - -@@ -21,7 +22,7 @@ - #include <stdlib.h> - #include <string.h> - #include <time.h> --#include "futextest.h" -+#include "futex2test.h" - #include "logging.h" - - #define TEST_NAME "futex-wait-wouldblock" -@@ -39,6 +40,7 @@ void usage(char *prog) - int main(int argc, char *argv[]) - { - struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns}; -+ struct timespec64 to64; - futex_t f1 = FUTEX_INITIALIZER; - int res, ret = RET_PASS; - int c; -@@ -61,18 +63,41 @@ int main(int argc, char *argv[]) - } - - ksft_print_header(); -- ksft_set_plan(1); -+ ksft_set_plan(2); - ksft_print_msg("%s: Test the unexpected futex value in FUTEX_WAIT\n", - basename(argv[0])); - - info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); - res = futex_wait(&f1, f1+1, &to, FUTEX_PRIVATE_FLAG); - if (!res || errno != EWOULDBLOCK) { -- fail("futex_wait returned: %d %s\n", -+ ksft_test_result_fail("futex_wait returned: %d %s\n", - res ? errno : res, res ? strerror(errno) : ""); - ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex_wait wouldblock succeeds\n"); - } - -- print_result(TEST_NAME, ret); -+ /* setting absolute timeout for futex2 */ -+ if (gettime64(CLOCK_MONOTONIC, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_nsec += timeout_ns; -+ -+ if (to64.tv_nsec >= 1000000000) { -+ to64.tv_sec++; -+ to64.tv_nsec -= 1000000000; -+ } -+ -+ info("Calling futex2_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); -+ res = futex2_wait(&f1, f1+1, FUTEX_32, &to64); -+ if (!res || errno != EWOULDBLOCK) { -+ ksft_test_result_fail("futex2_wait returned: %d %s\n", -+ res ? errno : res, res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_wait wouldblock succeeds\n"); -+ } -+ -+ ksft_print_cnts(); - return ret; - } --- -2.31.1 - - -From 1b9fd688507408bd196b03ec96b6d5d303ed344b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:02 -0300 -Subject: [PATCH 10/14] selftests: futex2: Add waitv test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Create a new file to test the waitv mechanism. Test both private and -shared futexes. Wake the last futex in the array, and check if the -return value from futex_waitv() is the right index. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - .../selftests/futex/functional/.gitignore | 1 + - .../selftests/futex/functional/Makefile | 3 +- - .../selftests/futex/functional/futex2_waitv.c | 157 ++++++++++++++++++ - .../testing/selftests/futex/functional/run.sh | 3 + - .../selftests/futex/include/futex2test.h | 26 +++ - 5 files changed, 189 insertions(+), 1 deletion(-) - create mode 100644 tools/testing/selftests/futex/functional/futex2_waitv.c - -diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore -index d61f1df94360..d0b8f637b786 100644 ---- a/tools/testing/selftests/futex/functional/.gitignore -+++ b/tools/testing/selftests/futex/functional/.gitignore -@@ -7,3 +7,4 @@ futex_wait_timeout - futex_wait_uninitialized_heap - futex_wait_wouldblock - futex2_wait -+futex2_waitv -diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile -index 9b334f190759..09c08ccdeaf2 100644 ---- a/tools/testing/selftests/futex/functional/Makefile -+++ b/tools/testing/selftests/futex/functional/Makefile -@@ -16,7 +16,8 @@ TEST_GEN_FILES := \ - futex_requeue_pi_mismatched_ops \ - futex_wait_uninitialized_heap \ - futex_wait_private_mapped_file \ -- futex2_wait -+ futex2_wait \ -+ futex2_waitv - - TEST_PROGS := run.sh - -diff --git a/tools/testing/selftests/futex/functional/futex2_waitv.c b/tools/testing/selftests/futex/functional/futex2_waitv.c -new file mode 100644 -index 000000000000..8ba74f1cbd51 ---- /dev/null -+++ b/tools/testing/selftests/futex/functional/futex2_waitv.c -@@ -0,0 +1,157 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/****************************************************************************** -+ * -+ * Copyright Collabora Ltd., 2021 -+ * -+ * DESCRIPTION -+ * Test waitv/wake mechanism of futex2, using 32bit sized futexes. -+ * -+ * AUTHOR -+ * André Almeida <andrealmeid@collabora.com> -+ * -+ * HISTORY -+ * 2021-Feb-5: Initial version by André <andrealmeid@collabora.com> -+ * -+ *****************************************************************************/ -+ -+#include <errno.h> -+#include <error.h> -+#include <getopt.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <time.h> -+#include <pthread.h> -+#include <sys/shm.h> -+#include "futex2test.h" -+#include "logging.h" -+ -+#define TEST_NAME "futex2-wait" -+#define timeout_ns 1000000000 -+#define WAKE_WAIT_US 10000 -+#define NR_FUTEXES 30 -+struct futex_waitv waitv[NR_FUTEXES]; -+u_int32_t futexes[NR_FUTEXES] = {0}; -+ -+void usage(char *prog) -+{ -+ printf("Usage: %s\n", prog); -+ printf(" -c Use color\n"); -+ printf(" -h Display this help message\n"); -+ printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", -+ VQUIET, VCRITICAL, VINFO); -+} -+ -+void *waiterfn(void *arg) -+{ -+ struct timespec64 to64; -+ int res; -+ -+ /* setting absolute timeout for futex2 */ -+ if (gettime64(CLOCK_MONOTONIC, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_sec++; -+ -+ res = futex2_waitv(waitv, NR_FUTEXES, 0, &to64); -+ if (res < 0) { -+ ksft_test_result_fail("futex2_waitv private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ } else if (res != NR_FUTEXES - 1) { -+ ksft_test_result_fail("futex2_waitv private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ } -+ -+ return NULL; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ pthread_t waiter; -+ int res, ret = RET_PASS; -+ int c, i; -+ -+ while ((c = getopt(argc, argv, "cht:v:")) != -1) { -+ switch (c) { -+ case 'c': -+ log_color(1); -+ break; -+ case 'h': -+ usage(basename(argv[0])); -+ exit(0); -+ case 'v': -+ log_verbosity(atoi(optarg)); -+ break; -+ default: -+ usage(basename(argv[0])); -+ exit(1); -+ } -+ } -+ -+ ksft_print_header(); -+ ksft_set_plan(2); -+ ksft_print_msg("%s: Test FUTEX2_WAITV\n", -+ basename(argv[0])); -+ -+ for (i = 0; i < NR_FUTEXES; i++) { -+ waitv[i].uaddr = &futexes[i]; -+ waitv[i].flags = FUTEX_32; -+ waitv[i].val = 0; -+ } -+ -+ /* Private waitv */ -+ if (pthread_create(&waiter, NULL, waiterfn, NULL)) -+ error("pthread_create failed\n", errno); -+ -+ usleep(WAKE_WAIT_US); -+ -+ res = futex2_wake(waitv[NR_FUTEXES - 1].uaddr, 1, FUTEX_32); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_waitv private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_waitv private succeeds\n"); -+ } -+ -+ /* Shared waitv */ -+ for (i = 0; i < NR_FUTEXES; i++) { -+ int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); -+ -+ if (shm_id < 0) { -+ perror("shmget"); -+ exit(1); -+ } -+ -+ unsigned int *shared_data = shmat(shm_id, NULL, 0); -+ -+ *shared_data = 0; -+ waitv[i].uaddr = shared_data; -+ waitv[i].flags = FUTEX_32 | FUTEX_SHARED_FLAG; -+ waitv[i].val = 0; -+ } -+ -+ if (pthread_create(&waiter, NULL, waiterfn, NULL)) -+ error("pthread_create failed\n", errno); -+ -+ usleep(WAKE_WAIT_US); -+ -+ res = futex2_wake(waitv[NR_FUTEXES - 1].uaddr, 1, FUTEX_32 | FUTEX_SHARED_FLAG); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_waitv shared returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_waitv shared succeeds\n"); -+ } -+ -+ for (i = 0; i < NR_FUTEXES; i++) -+ shmdt(waitv[i].uaddr); -+ -+ ksft_print_cnts(); -+ return ret; -+} -diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh -index 3730159c865a..18b3883d7236 100755 ---- a/tools/testing/selftests/futex/functional/run.sh -+++ b/tools/testing/selftests/futex/functional/run.sh -@@ -76,3 +76,6 @@ echo - - echo - ./futex2_wait $COLOR -+ -+echo -+./futex2_waitv $COLOR -diff --git a/tools/testing/selftests/futex/include/futex2test.h b/tools/testing/selftests/futex/include/futex2test.h -index 917ac8909a3b..7f847bd60594 100644 ---- a/tools/testing/selftests/futex/include/futex2test.h -+++ b/tools/testing/selftests/futex/include/futex2test.h -@@ -28,6 +28,19 @@ - # define FUTEX_32 2 - #endif - -+#ifndef FUTEX_SHARED_FLAG -+#define FUTEX_SHARED_FLAG 8 -+#endif -+ -+#ifndef FUTEX_WAITV_MAX -+#define FUTEX_WAITV_MAX 128 -+struct futex_waitv { -+ void *uaddr; -+ unsigned int val; -+ unsigned int flags; -+}; -+#endif -+ - /* - * - Y2038 section for 32-bit applications - - * -@@ -77,3 +90,16 @@ static inline int futex2_wake(volatile void *uaddr, unsigned int nr, unsigned lo - { - return syscall(__NR_futex_wake, uaddr, nr, flags); - } -+ -+/** -+ * futex2_waitv - Wait at multiple futexes, wake on any -+ * @waiters: Array of waiters -+ * @nr_waiters: Length of waiters array -+ * @flags: Operation flags -+ * @timo: Optional timeout for operation -+ */ -+static inline int futex2_waitv(volatile struct futex_waitv *waiters, unsigned long nr_waiters, -+ unsigned long flags, struct timespec64 *timo) -+{ -+ return syscall(__NR_futex_waitv, waiters, nr_waiters, flags, timo); -+} --- -2.31.1 - - -From 232e77c996fb8a19ef4511771568019d3545156f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:02 -0300 -Subject: [PATCH 11/14] selftests: futex2: Add requeue test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add testing for futex_requeue(). The first test just requeue from one -waiter to another one, and wake it. The second performs both wake and -requeue, and we check return values to see if the operation -woke/requeued the expected number of waiters. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - .../selftests/futex/functional/.gitignore | 1 + - .../selftests/futex/functional/Makefile | 3 +- - .../futex/functional/futex2_requeue.c | 164 ++++++++++++++++++ - .../selftests/futex/include/futex2test.h | 16 ++ - 4 files changed, 183 insertions(+), 1 deletion(-) - create mode 100644 tools/testing/selftests/futex/functional/futex2_requeue.c - -diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore -index d0b8f637b786..af7557e821da 100644 ---- a/tools/testing/selftests/futex/functional/.gitignore -+++ b/tools/testing/selftests/futex/functional/.gitignore -@@ -8,3 +8,4 @@ futex_wait_uninitialized_heap - futex_wait_wouldblock - futex2_wait - futex2_waitv -+futex2_requeue -diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile -index 09c08ccdeaf2..3ccb9ea58ddd 100644 ---- a/tools/testing/selftests/futex/functional/Makefile -+++ b/tools/testing/selftests/futex/functional/Makefile -@@ -17,7 +17,8 @@ TEST_GEN_FILES := \ - futex_wait_uninitialized_heap \ - futex_wait_private_mapped_file \ - futex2_wait \ -- futex2_waitv -+ futex2_waitv \ -+ futex2_requeue - - TEST_PROGS := run.sh - -diff --git a/tools/testing/selftests/futex/functional/futex2_requeue.c b/tools/testing/selftests/futex/functional/futex2_requeue.c -new file mode 100644 -index 000000000000..05629c2257d0 ---- /dev/null -+++ b/tools/testing/selftests/futex/functional/futex2_requeue.c -@@ -0,0 +1,164 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/****************************************************************************** -+ * -+ * Copyright Collabora Ltd., 2021 -+ * -+ * DESCRIPTION -+ * Test requeue mechanism of futex2, using 32bit sized futexes. -+ * -+ * AUTHOR -+ * André Almeida <andrealmeid@collabora.com> -+ * -+ * HISTORY -+ * 2021-Feb-5: Initial version by André <andrealmeid@collabora.com> -+ * -+ *****************************************************************************/ -+ -+#include <errno.h> -+#include <error.h> -+#include <getopt.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <time.h> -+#include <pthread.h> -+#include <sys/shm.h> -+#include <limits.h> -+#include "futex2test.h" -+#include "logging.h" -+ -+#define TEST_NAME "futex2-wait" -+#define timeout_ns 30000000 -+#define WAKE_WAIT_US 10000 -+volatile futex_t *f1; -+ -+void usage(char *prog) -+{ -+ printf("Usage: %s\n", prog); -+ printf(" -c Use color\n"); -+ printf(" -h Display this help message\n"); -+ printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", -+ VQUIET, VCRITICAL, VINFO); -+} -+ -+void *waiterfn(void *arg) -+{ -+ struct timespec64 to64; -+ -+ /* setting absolute timeout for futex2 */ -+ if (gettime64(CLOCK_MONOTONIC, &to64)) -+ error("gettime64 failed\n", errno); -+ -+ to64.tv_nsec += timeout_ns; -+ -+ if (to64.tv_nsec >= 1000000000) { -+ to64.tv_sec++; -+ to64.tv_nsec -= 1000000000; -+ } -+ -+ if (futex2_wait(f1, *f1, FUTEX_32, &to64)) -+ printf("waiter failed errno %d\n", errno); -+ -+ return NULL; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ pthread_t waiter[10]; -+ int res, ret = RET_PASS; -+ int c, i; -+ volatile futex_t _f1 = 0; -+ volatile futex_t f2 = 0; -+ struct futex_requeue r1, r2; -+ -+ f1 = &_f1; -+ -+ r1.flags = FUTEX_32; -+ r2.flags = FUTEX_32; -+ -+ r1.uaddr = f1; -+ r2.uaddr = &f2; -+ -+ while ((c = getopt(argc, argv, "cht:v:")) != -1) { -+ switch (c) { -+ case 'c': -+ log_color(1); -+ break; -+ case 'h': -+ usage(basename(argv[0])); -+ exit(0); -+ case 'v': -+ log_verbosity(atoi(optarg)); -+ break; -+ default: -+ usage(basename(argv[0])); -+ exit(1); -+ } -+ } -+ -+ ksft_print_header(); -+ ksft_set_plan(2); -+ ksft_print_msg("%s: Test FUTEX2_REQUEUE\n", -+ basename(argv[0])); -+ -+ /* -+ * Requeue a waiter from f1 to f2, and wake f2. -+ */ -+ if (pthread_create(&waiter[0], NULL, waiterfn, NULL)) -+ error("pthread_create failed\n", errno); -+ -+ usleep(WAKE_WAIT_US); -+ -+ res = futex2_requeue(&r1, &r2, 0, 1, 0, 0); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_requeue private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } -+ -+ -+ info("Calling private futex2_wake on f2: %u @ %p with val=%u\n", f2, &f2, f2); -+ res = futex2_wake(&f2, 1, FUTEX_32); -+ if (res != 1) { -+ ksft_test_result_fail("futex2_requeue private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_requeue simple succeeds\n"); -+ } -+ -+ -+ /* -+ * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7. -+ * At futex_wake, wake INT_MAX (should be exaclty 7). -+ */ -+ for (i = 0; i < 10; i++) { -+ if (pthread_create(&waiter[i], NULL, waiterfn, NULL)) -+ error("pthread_create failed\n", errno); -+ } -+ -+ usleep(WAKE_WAIT_US); -+ -+ res = futex2_requeue(&r1, &r2, 3, 7, 0, 0); -+ if (res != 10) { -+ ksft_test_result_fail("futex2_requeue private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } -+ -+ res = futex2_wake(&f2, INT_MAX, FUTEX_32); -+ if (res != 7) { -+ ksft_test_result_fail("futex2_requeue private returned: %d %s\n", -+ res ? errno : res, -+ res ? strerror(errno) : ""); -+ ret = RET_FAIL; -+ } else { -+ ksft_test_result_pass("futex2_requeue succeeds\n"); -+ } -+ -+ ksft_print_cnts(); -+ return ret; -+} -diff --git a/tools/testing/selftests/futex/include/futex2test.h b/tools/testing/selftests/futex/include/futex2test.h -index 7f847bd60594..faa4027ce5b1 100644 ---- a/tools/testing/selftests/futex/include/futex2test.h -+++ b/tools/testing/selftests/futex/include/futex2test.h -@@ -103,3 +103,19 @@ static inline int futex2_waitv(volatile struct futex_waitv *waiters, unsigned lo - { - return syscall(__NR_futex_waitv, waiters, nr_waiters, flags, timo); - } -+ -+/** -+ * futex2_requeue - Wake futexes at uaddr1 and requeue from uaddr1 to uaddr2 -+ * @uaddr1: Original address to wake and requeue from -+ * @uaddr2: Address to requeue to -+ * @nr_wake: Number of futexes to wake at uaddr1 before requeuing -+ * @nr_requeue: Number of futexes to requeue from uaddr1 to uaddr2 -+ * @cmpval: If (uaddr1->uaddr != cmpval), return immediatally -+ * @flgas: Operation flags -+ */ -+static inline int futex2_requeue(struct futex_requeue *uaddr1, struct futex_requeue *uaddr2, -+ unsigned int nr_wake, unsigned int nr_requeue, -+ unsigned int cmpval, unsigned long flags) -+{ -+ return syscall(__NR_futex_requeue, uaddr1, uaddr2, nr_wake, nr_requeue, cmpval, flags); -+} --- -2.31.1 - - -From 34e8923658222740ed4357544cf38df3ea4a0bf2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:02 -0300 -Subject: [PATCH 12/14] perf bench: Add futex2 benchmark tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add support at the existing futex benchmarking code base to enable -futex2 calls. `perf bench` tests can be used not only as a way to -measure the performance of implementation, but also as stress testing -for the kernel infrastructure. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - tools/arch/x86/include/asm/unistd_64.h | 12 ++++++ - tools/perf/bench/bench.h | 4 ++ - tools/perf/bench/futex-hash.c | 24 +++++++++-- - tools/perf/bench/futex-requeue.c | 57 ++++++++++++++++++++------ - tools/perf/bench/futex-wake-parallel.c | 41 +++++++++++++++--- - tools/perf/bench/futex-wake.c | 37 +++++++++++++---- - tools/perf/bench/futex.h | 47 +++++++++++++++++++++ - tools/perf/builtin-bench.c | 18 ++++++-- - 8 files changed, 206 insertions(+), 34 deletions(-) - -diff --git a/tools/arch/x86/include/asm/unistd_64.h b/tools/arch/x86/include/asm/unistd_64.h -index 4205ed4158bf..b65c51e8d675 100644 ---- a/tools/arch/x86/include/asm/unistd_64.h -+++ b/tools/arch/x86/include/asm/unistd_64.h -@@ -17,3 +17,15 @@ - #ifndef __NR_setns - #define __NR_setns 308 - #endif -+ -+#ifndef __NR_futex_wait -+# define __NR_futex_wait 443 -+#endif -+ -+#ifndef __NR_futex_wake -+# define __NR_futex_wake 444 -+#endif -+ -+#ifndef __NR_futex_requeue -+# define __NR_futex_requeue 446 -+#endif -diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h -index eac36afab2b3..12346844b354 100644 ---- a/tools/perf/bench/bench.h -+++ b/tools/perf/bench/bench.h -@@ -38,9 +38,13 @@ int bench_mem_memcpy(int argc, const char **argv); - int bench_mem_memset(int argc, const char **argv); - int bench_mem_find_bit(int argc, const char **argv); - int bench_futex_hash(int argc, const char **argv); -+int bench_futex2_hash(int argc, const char **argv); - int bench_futex_wake(int argc, const char **argv); -+int bench_futex2_wake(int argc, const char **argv); - int bench_futex_wake_parallel(int argc, const char **argv); -+int bench_futex2_wake_parallel(int argc, const char **argv); - int bench_futex_requeue(int argc, const char **argv); -+int bench_futex2_requeue(int argc, const char **argv); - /* pi futexes */ - int bench_futex_lock_pi(int argc, const char **argv); - int bench_epoll_wait(int argc, const char **argv); -diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c -index b65373ce5c4f..1068749af40c 100644 ---- a/tools/perf/bench/futex-hash.c -+++ b/tools/perf/bench/futex-hash.c -@@ -33,7 +33,7 @@ static unsigned int nthreads = 0; - static unsigned int nsecs = 10; - /* amount of futexes per thread */ - static unsigned int nfutexes = 1024; --static bool fshared = false, done = false, silent = false; -+static bool fshared = false, done = false, silent = false, futex2 = false; - static int futex_flag = 0; - - struct timeval bench__start, bench__end, bench__runtime; -@@ -85,7 +85,10 @@ static void *workerfn(void *arg) - * such as internal waitqueue handling, thus enlarging - * the critical region protected by hb->lock. - */ -- ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag); -+ if (!futex2) -+ ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag); -+ else -+ ret = futex2_wait(&w->futex[i], 1234, futex_flag, NULL); - if (!silent && - (!ret || errno != EAGAIN || errno != EWOULDBLOCK)) - warn("Non-expected futex return call"); -@@ -116,7 +119,7 @@ static void print_summary(void) - (int)bench__runtime.tv_sec); - } - --int bench_futex_hash(int argc, const char **argv) -+static int __bench_futex_hash(int argc, const char **argv) - { - int ret = 0; - cpu_set_t cpuset; -@@ -148,7 +151,9 @@ int bench_futex_hash(int argc, const char **argv) - if (!worker) - goto errmem; - -- if (!fshared) -+ if (futex2) -+ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG); -+ else if (!fshared) - futex_flag = FUTEX_PRIVATE_FLAG; - - printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n", -@@ -228,3 +233,14 @@ int bench_futex_hash(int argc, const char **argv) - errmem: - err(EXIT_FAILURE, "calloc"); - } -+ -+int bench_futex_hash(int argc, const char **argv) -+{ -+ return __bench_futex_hash(argc, argv); -+} -+ -+int bench_futex2_hash(int argc, const char **argv) -+{ -+ futex2 = true; -+ return __bench_futex_hash(argc, argv); -+} -diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c -index 5fa23295ee5f..6cdd649b54f4 100644 ---- a/tools/perf/bench/futex-requeue.c -+++ b/tools/perf/bench/futex-requeue.c -@@ -2,8 +2,8 @@ - /* - * Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com> - * -- * futex-requeue: Block a bunch of threads on futex1 and requeue them -- * on futex2, N at a time. -+ * futex-requeue: Block a bunch of threads on addr1 and requeue them -+ * on addr2, N at a time. - * - * This program is particularly useful to measure the latency of nthread - * requeues without waking up any tasks -- thus mimicking a regular futex_wait. -@@ -28,7 +28,10 @@ - #include <stdlib.h> - #include <sys/time.h> - --static u_int32_t futex1 = 0, futex2 = 0; -+static u_int32_t addr1 = 0, addr2 = 0; -+ -+static struct futex_requeue rq1 = { .uaddr = &addr1, .flags = FUTEX_32 }; -+static struct futex_requeue rq2 = { .uaddr = &addr2, .flags = FUTEX_32 }; - - /* - * How many tasks to requeue at a time. -@@ -37,7 +40,7 @@ static u_int32_t futex1 = 0, futex2 = 0; - static unsigned int nrequeue = 1; - - static pthread_t *worker; --static bool done = false, silent = false, fshared = false; -+static bool done = false, silent = false, fshared = false, futex2 = false; - static pthread_mutex_t thread_lock; - static pthread_cond_t thread_parent, thread_worker; - static struct stats requeuetime_stats, requeued_stats; -@@ -79,7 +82,11 @@ static void *workerfn(void *arg __maybe_unused) - pthread_cond_wait(&thread_worker, &thread_lock); - pthread_mutex_unlock(&thread_lock); - -- futex_wait(&futex1, 0, NULL, futex_flag); -+ if (!futex2) -+ futex_wait(&addr1, 0, NULL, futex_flag); -+ else -+ futex2_wait(&addr1, 0, futex_flag, NULL); -+ - return NULL; - } - -@@ -111,7 +118,7 @@ static void toggle_done(int sig __maybe_unused, - done = true; - } - --int bench_futex_requeue(int argc, const char **argv) -+static int __bench_futex_requeue(int argc, const char **argv) - { - int ret = 0; - unsigned int i, j; -@@ -139,15 +146,20 @@ int bench_futex_requeue(int argc, const char **argv) - if (!worker) - err(EXIT_FAILURE, "calloc"); - -- if (!fshared) -+ if (futex2) { -+ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG); -+ rq1.flags |= FUTEX_SHARED_FLAG * fshared; -+ rq2.flags |= FUTEX_SHARED_FLAG * fshared; -+ } else if (!fshared) { - futex_flag = FUTEX_PRIVATE_FLAG; -+ } - - if (nrequeue > nthreads) - nrequeue = nthreads; - - printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), " - "%d at a time.\n\n", getpid(), nthreads, -- fshared ? "shared":"private", &futex1, &futex2, nrequeue); -+ fshared ? "shared":"private", &addr1, &addr2, nrequeue); - - init_stats(&requeued_stats); - init_stats(&requeuetime_stats); -@@ -176,11 +188,15 @@ int bench_futex_requeue(int argc, const char **argv) - gettimeofday(&start, NULL); - while (nrequeued < nthreads) { - /* -- * Do not wakeup any tasks blocked on futex1, allowing -+ * Do not wakeup any tasks blocked on addr1, allowing - * us to really measure futex_wait functionality. - */ -- nrequeued += futex_cmp_requeue(&futex1, 0, &futex2, 0, -- nrequeue, futex_flag); -+ if (!futex2) -+ nrequeued += futex_cmp_requeue(&addr1, 0, &addr2, -+ 0, nrequeue, futex_flag); -+ else -+ nrequeued += futex2_requeue(&rq1, &rq2, -+ 0, nrequeue, 0, 0); - } - - gettimeofday(&end, NULL); -@@ -194,8 +210,12 @@ int bench_futex_requeue(int argc, const char **argv) - j + 1, nrequeued, nthreads, runtime.tv_usec / (double)USEC_PER_MSEC); - } - -- /* everybody should be blocked on futex2, wake'em up */ -- nrequeued = futex_wake(&futex2, nrequeued, futex_flag); -+ /* everybody should be blocked on addr2, wake'em up */ -+ if (!futex2) -+ nrequeued = futex_wake(&addr2, nrequeued, futex_flag); -+ else -+ nrequeued = futex2_wake(&addr2, nrequeued, futex_flag); -+ - if (nthreads != nrequeued) - warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads); - -@@ -220,3 +240,14 @@ int bench_futex_requeue(int argc, const char **argv) - usage_with_options(bench_futex_requeue_usage, options); - exit(EXIT_FAILURE); - } -+ -+int bench_futex_requeue(int argc, const char **argv) -+{ -+ return __bench_futex_requeue(argc, argv); -+} -+ -+int bench_futex2_requeue(int argc, const char **argv) -+{ -+ futex2 = true; -+ return __bench_futex_requeue(argc, argv); -+} -diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c -index 6e6f5247e1fe..cac90fc0bfb3 100644 ---- a/tools/perf/bench/futex-wake-parallel.c -+++ b/tools/perf/bench/futex-wake-parallel.c -@@ -17,6 +17,12 @@ int bench_futex_wake_parallel(int argc __maybe_unused, const char **argv __maybe - pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__); - return 0; - } -+ -+int bench_futex2_wake_parallel(int argc __maybe_unused, const char **argv __maybe_unused) -+{ -+ pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__); -+ return 0; -+} - #else /* HAVE_PTHREAD_BARRIER */ - /* For the CLR_() macros */ - #include <string.h> -@@ -47,7 +53,7 @@ static unsigned int nwakes = 1; - static u_int32_t futex = 0; - - static pthread_t *blocked_worker; --static bool done = false, silent = false, fshared = false; -+static bool done = false, silent = false, fshared = false, futex2 = false; - static unsigned int nblocked_threads = 0, nwaking_threads = 0; - static pthread_mutex_t thread_lock; - static pthread_cond_t thread_parent, thread_worker; -@@ -78,7 +84,11 @@ static void *waking_workerfn(void *arg) - - gettimeofday(&start, NULL); - -- waker->nwoken = futex_wake(&futex, nwakes, futex_flag); -+ if (!futex2) -+ waker->nwoken = futex_wake(&futex, nwakes, futex_flag); -+ else -+ waker->nwoken = futex2_wake(&futex, nwakes, futex_flag); -+ - if (waker->nwoken != nwakes) - warnx("couldn't wakeup all tasks (%d/%d)", - waker->nwoken, nwakes); -@@ -129,8 +139,13 @@ static void *blocked_workerfn(void *arg __maybe_unused) - pthread_mutex_unlock(&thread_lock); - - while (1) { /* handle spurious wakeups */ -- if (futex_wait(&futex, 0, NULL, futex_flag) != EINTR) -- break; -+ if (!futex2) { -+ if (futex_wait(&futex, 0, NULL, futex_flag) != EINTR) -+ break; -+ } else { -+ if (futex2_wait(&futex, 0, futex_flag, NULL) != EINTR) -+ break; -+ } - } - - pthread_exit(NULL); -@@ -217,7 +232,7 @@ static void toggle_done(int sig __maybe_unused, - done = true; - } - --int bench_futex_wake_parallel(int argc, const char **argv) -+static int __bench_futex_wake_parallel(int argc, const char **argv) - { - int ret = 0; - unsigned int i, j; -@@ -261,7 +276,9 @@ int bench_futex_wake_parallel(int argc, const char **argv) - if (!blocked_worker) - err(EXIT_FAILURE, "calloc"); - -- if (!fshared) -+ if (futex2) -+ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG); -+ else if (!fshared) - futex_flag = FUTEX_PRIVATE_FLAG; - - printf("Run summary [PID %d]: blocking on %d threads (at [%s] " -@@ -321,4 +338,16 @@ int bench_futex_wake_parallel(int argc, const char **argv) - free(blocked_worker); - return ret; - } -+ -+int bench_futex_wake_parallel(int argc, const char **argv) -+{ -+ return __bench_futex_wake_parallel(argc, argv); -+} -+ -+int bench_futex2_wake_parallel(int argc, const char **argv) -+{ -+ futex2 = true; -+ return __bench_futex_wake_parallel(argc, argv); -+} -+ - #endif /* HAVE_PTHREAD_BARRIER */ -diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c -index 6d217868f53c..546d2818eed8 100644 ---- a/tools/perf/bench/futex-wake.c -+++ b/tools/perf/bench/futex-wake.c -@@ -38,7 +38,7 @@ static u_int32_t futex1 = 0; - static unsigned int nwakes = 1; - - pthread_t *worker; --static bool done = false, silent = false, fshared = false; -+static bool done = false, silent = false, fshared = false, futex2 = false; - static pthread_mutex_t thread_lock; - static pthread_cond_t thread_parent, thread_worker; - static struct stats waketime_stats, wakeup_stats; -@@ -68,8 +68,13 @@ static void *workerfn(void *arg __maybe_unused) - pthread_mutex_unlock(&thread_lock); - - while (1) { -- if (futex_wait(&futex1, 0, NULL, futex_flag) != EINTR) -- break; -+ if (!futex2) { -+ if (futex_wait(&futex1, 0, NULL, futex_flag) != EINTR) -+ break; -+ } else { -+ if (futex2_wait(&futex1, 0, futex_flag, NULL) != EINTR) -+ break; -+ } - } - - pthread_exit(NULL); -@@ -117,7 +122,7 @@ static void toggle_done(int sig __maybe_unused, - done = true; - } - --int bench_futex_wake(int argc, const char **argv) -+static int __bench_futex_wake(int argc, const char **argv) - { - int ret = 0; - unsigned int i, j; -@@ -147,7 +152,9 @@ int bench_futex_wake(int argc, const char **argv) - if (!worker) - err(EXIT_FAILURE, "calloc"); - -- if (!fshared) -+ if (futex2) -+ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG); -+ else if (!fshared) - futex_flag = FUTEX_PRIVATE_FLAG; - - printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), " -@@ -179,9 +186,14 @@ int bench_futex_wake(int argc, const char **argv) - - /* Ok, all threads are patiently blocked, start waking folks up */ - gettimeofday(&start, NULL); -- while (nwoken != nthreads) -- nwoken += futex_wake(&futex1, nwakes, futex_flag); -+ while (nwoken != nthreads) { -+ if (!futex2) -+ nwoken += futex_wake(&futex1, nwakes, futex_flag); -+ else -+ nwoken += futex2_wake(&futex1, nwakes, futex_flag); -+ } - gettimeofday(&end, NULL); -+ - timersub(&end, &start, &runtime); - - update_stats(&wakeup_stats, nwoken); -@@ -211,3 +223,14 @@ int bench_futex_wake(int argc, const char **argv) - free(worker); - return ret; - } -+ -+int bench_futex_wake(int argc, const char **argv) -+{ -+ return __bench_futex_wake(argc, argv); -+} -+ -+int bench_futex2_wake(int argc, const char **argv) -+{ -+ futex2 = true; -+ return __bench_futex_wake(argc, argv); -+} -diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h -index 31b53cc7d5bc..6b2213cf3f64 100644 ---- a/tools/perf/bench/futex.h -+++ b/tools/perf/bench/futex.h -@@ -86,4 +86,51 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak - return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, - val, opflags); - } -+ -+/** -+ * futex2_wait - Wait at uaddr if *uaddr == val, until timo. -+ * @uaddr: User address to wait for -+ * @val: Expected value at uaddr -+ * @flags: Operation options -+ * @timo: Optional timeout -+ * -+ * Return: 0 on success, error code otherwise -+ */ -+static inline int futex2_wait(volatile void *uaddr, unsigned long val, -+ unsigned long flags, struct timespec *timo) -+{ -+ return syscall(__NR_futex_wait, uaddr, val, flags, timo); -+} -+ -+/** -+ * futex2_wake - Wake a number of waiters waiting at uaddr -+ * @uaddr: Address to wake -+ * @nr: Number of waiters to wake -+ * @flags: Operation options -+ * -+ * Return: number of waked futexes -+ */ -+static inline int futex2_wake(volatile void *uaddr, unsigned int nr, unsigned long flags) -+{ -+ return syscall(__NR_futex_wake, uaddr, nr, flags); -+} -+ -+/** -+ * futex2_requeue - Requeue waiters from an address to another one -+ * @uaddr1: Address where waiters are currently waiting on -+ * @uaddr2: New address to wait -+ * @nr_wake: Number of waiters at uaddr1 to be wake -+ * @nr_requeue: After waking nr_wake, number of waiters to be requeued -+ * @cmpval: Expected value at uaddr1 -+ * @flags: Operation options -+ * -+ * Return: waked futexes + requeued futexes at uaddr1 -+ */ -+static inline int futex2_requeue(volatile struct futex_requeue *uaddr1, -+ volatile struct futex_requeue *uaddr2, -+ unsigned int nr_wake, unsigned int nr_requeue, -+ unsigned int cmpval, unsigned long flags) -+{ -+ return syscall(__NR_futex_requeue, uaddr1, uaddr2, nr_wake, nr_requeue, cmpval, flags); -+} - #endif /* _FUTEX_H */ -diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c -index 62a7b7420a44..e41a95ad2db6 100644 ---- a/tools/perf/builtin-bench.c -+++ b/tools/perf/builtin-bench.c -@@ -12,10 +12,11 @@ - * - * sched ... scheduler and IPC performance - * syscall ... System call performance -- * mem ... memory access performance -- * numa ... NUMA scheduling and MM performance -- * futex ... Futex performance -- * epoll ... Event poll performance -+ * mem ... memory access performance -+ * numa ... NUMA scheduling and MM performance -+ * futex ... Futex performance -+ * futex2 ... Futex2 performance -+ * epoll ... Event poll performance - */ - #include <subcmd/parse-options.h> - #include "builtin.h" -@@ -75,6 +76,14 @@ static struct bench futex_benchmarks[] = { - { NULL, NULL, NULL } - }; - -+static struct bench futex2_benchmarks[] = { -+ { "hash", "Benchmark for futex2 hash table", bench_futex2_hash }, -+ { "wake", "Benchmark for futex2 wake calls", bench_futex2_wake }, -+ { "wake-parallel", "Benchmark for parallel futex2 wake calls", bench_futex2_wake_parallel }, -+ { "requeue", "Benchmark for futex2 requeue calls", bench_futex2_requeue }, -+ { NULL, NULL, NULL } -+}; -+ - #ifdef HAVE_EVENTFD_SUPPORT - static struct bench epoll_benchmarks[] = { - { "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait }, -@@ -105,6 +114,7 @@ static struct collection collections[] = { - { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks }, - #endif - {"futex", "Futex stressing benchmarks", futex_benchmarks }, -+ {"futex2", "Futex2 stressing benchmarks", futex2_benchmarks }, - #ifdef HAVE_EVENTFD_SUPPORT - {"epoll", "Epoll stressing benchmarks", epoll_benchmarks }, - #endif --- -2.31.1 - - -From 04b171b8aae7843cc1cc15d4f41188626382548b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:02 -0300 -Subject: [PATCH 13/14] kernel: Enable waitpid() for futex2 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To make pthreads works as expected if they are using futex2, wake -clear_child_tid with futex2 as well. This is make applications that uses -waitpid() (and clone(CLONE_CHILD_SETTID)) wake while waiting for the -child to terminate. Given that apps should not mix futex() and futex2(), -any correct app will trigger a harmless noop wakeup on the interface -that it isn't using. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - include/linux/syscalls.h | 2 ++ - kernel/fork.c | 2 ++ - kernel/futex2.c | 30 ++++++++++++++++++------------ - 3 files changed, 22 insertions(+), 12 deletions(-) - -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index aca64b5126a7..a0a9748b0236 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -1325,6 +1325,8 @@ int ksys_ipc(unsigned int call, int first, unsigned long second, - unsigned long third, void __user * ptr, long fifth); - int compat_ksys_ipc(u32 call, int first, int second, - u32 third, u32 ptr, u32 fifth); -+long ksys_futex_wake(void __user *uaddr, unsigned long nr_wake, -+ unsigned int flags); - - /* - * The following kernel syscall equivalents are just wrappers to fs-internal -diff --git a/kernel/fork.c b/kernel/fork.c -index dc06afd725cb..344430d882b1 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1322,6 +1322,8 @@ static void mm_release(struct task_struct *tsk, struct mm_struct *mm) - put_user(0, tsk->clear_child_tid); - do_futex(tsk->clear_child_tid, FUTEX_WAKE, - 1, NULL, NULL, 0, 0); -+ ksys_futex_wake(tsk->clear_child_tid, 1, -+ FUTEX_32 | FUTEX_SHARED_FLAG); - } - tsk->clear_child_tid = NULL; - } -diff --git a/kernel/futex2.c b/kernel/futex2.c -index 22ba9b3e45e2..25f5dea49ad7 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -940,18 +940,8 @@ static inline bool futex_match(struct futex_key key1, struct futex_key key2) - key1.offset == key2.offset); - } - --/** -- * sys_futex_wake - Wake a number of futexes waiting on an address -- * @uaddr: Address of futex to be woken up -- * @nr_wake: Number of futexes waiting in uaddr to be woken up -- * @flags: Flags for size and shared -- * -- * Wake `nr_wake` threads waiting at uaddr. -- * -- * Returns the number of woken threads on success, error code otherwise. -- */ --SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, -- unsigned int, flags) -+long ksys_futex_wake(void __user *uaddr, unsigned long nr_wake, -+ unsigned int flags) - { - bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false; - unsigned int size = flags & FUTEX_SIZE_MASK; -@@ -988,6 +978,22 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, - return ret; - } - -+/** -+ * sys_futex_wake - Wake a number of futexes waiting on an address -+ * @uaddr: Address of futex to be woken up -+ * @nr_wake: Number of futexes waiting in uaddr to be woken up -+ * @flags: Flags for size and shared -+ * -+ * Wake `nr_wake` threads waiting at uaddr. -+ * -+ * Returns the number of woken threads on success, error code otherwise. -+ */ -+SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake, -+ unsigned int, flags) -+{ -+ return ksys_futex_wake(uaddr, nr_wake, flags); -+} -+ - static void futex_double_unlock(struct futex_bucket *b1, struct futex_bucket *b2) - { - spin_unlock(&b1->lock); --- -2.31.1 - - -From 015b8cacf01907cdedfb46522908c3a8ab482bd6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com> -Date: Fri, 5 Feb 2021 10:34:02 -0300 -Subject: [PATCH 14/14] futex2: Add sysfs entry for syscall numbers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In the course of futex2 development, it will be rebased on top of -different kernel releases, and the syscall number can change in this -process. Expose futex2 syscall number via sysfs so tools that are -experimenting with futex2 (like Proton/Wine) can test it and set the -syscall number at runtime, rather than setting it at compilation time. - -Signed-off-by: André Almeida <andrealmeid@collabora.com> ---- - kernel/futex2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/kernel/futex2.c b/kernel/futex2.c -index 25f5dea49ad7..a7f132bb061d 100644 ---- a/kernel/futex2.c -+++ b/kernel/futex2.c -@@ -1224,6 +1224,48 @@ SYSCALL_DEFINE6(futex_requeue, struct futex_requeue __user *, uaddr1, - return __futex_requeue(rq1, rq2, nr_wake, nr_requeue, cmpval, shared1, shared2); - } - -+static ssize_t wait_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%u\n", __NR_futex_wait); -+ -+} -+static struct kobj_attribute futex2_wait_attr = __ATTR_RO(wait); -+ -+static ssize_t wake_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%u\n", __NR_futex_wake); -+ -+} -+static struct kobj_attribute futex2_wake_attr = __ATTR_RO(wake); -+ -+static ssize_t waitv_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%u\n", __NR_futex_waitv); -+ -+} -+static struct kobj_attribute futex2_waitv_attr = __ATTR_RO(waitv); -+ -+static struct attribute *futex2_sysfs_attrs[] = { -+ &futex2_wait_attr.attr, -+ &futex2_wake_attr.attr, -+ &futex2_waitv_attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group futex2_sysfs_attr_group = { -+ .attrs = futex2_sysfs_attrs, -+ .name = "futex2", -+}; -+ -+static int __init futex2_sysfs_init(void) -+{ -+ return sysfs_create_group(kernel_kobj, &futex2_sysfs_attr_group); -+} -+subsys_initcall(futex2_sysfs_init); -+ - static int __init futex2_init(void) - { - int i; --- -2.31.1 - - |