diff --git a/build.sh b/build.sh index 6ff9fbcc..fca41e78 100755 --- a/build.sh +++ b/build.sh @@ -94,13 +94,13 @@ fi if [ "$OMR_OPENWRT" = "default" ]; then if [ "$OMR_KERNEL" = "5.4" ]; then # Use OpenWrt 21.02 for 5.4 kernel - _get_repo "$OMR_TARGET/${OMR_KERNEL}/source" https://github.com/openwrt/openwrt "ab26cddca2e45911a980a60afaee889bd1353a6e" - _get_repo feeds/${OMR_KERNEL}/packages https://github.com/openwrt/packages "6711badf079986f847da07747c95c0a74960b965" - _get_repo feeds/${OMR_KERNEL}/luci https://github.com/openwrt/luci "04257f6704c1b8707ee7a58ca4ec0f18a2133611" + _get_repo "$OMR_TARGET/${OMR_KERNEL}/source" https://github.com/openwrt/openwrt "1b6e9b3f64344aa17bdb2dc7b89bb2765305dbe5" + _get_repo feeds/${OMR_KERNEL}/packages https://github.com/openwrt/packages "88b0e30806965a73058d79dd2d8bcbe6a2da88f9" + _get_repo feeds/${OMR_KERNEL}/luci https://github.com/openwrt/luci "d548d858c8cf62d36ab87dcf5d317fe05ede19cf" else - _get_repo "$OMR_TARGET/${OMR_KERNEL}/source" https://github.com/openwrt/openwrt "d7876daf6552a9f39bd5e0bf50b554e9406ec275" - _get_repo feeds/${OMR_KERNEL}/packages https://github.com/openwrt/packages "8762261112c8235f7f85a6f57dbf342cf17093b9" - _get_repo feeds/${OMR_KERNEL}/luci https://github.com/openwrt/luci "a1ee78fa696e13ad4e19c0252eb345500d4ab3ee" + _get_repo "$OMR_TARGET/${OMR_KERNEL}/source" https://github.com/openwrt/openwrt "895f38ca1efeb46f0cd3029c732e6156d4589eb0" + _get_repo feeds/${OMR_KERNEL}/packages https://github.com/openwrt/packages "8f68e1bd911dd4cab5d11199f65f78f97bc4faf9" + _get_repo feeds/${OMR_KERNEL}/luci https://github.com/openwrt/luci "ec3aac47c43d44d170af6a09d31493c2e8efe590" fi elif [ "$OMR_OPENWRT" = "master" ]; then _get_repo "$OMR_TARGET/${OMR_KERNEL}/source" https://github.com/openwrt/openwrt "master" @@ -391,6 +391,12 @@ if ! patch -Rf -N -p1 -s --dry-run < ../../../patches/nanqinlang.patch; then fi echo "Done" +echo "Checking if Meson patch is set or not" +if [ "$OMR_KERNEL" = "5.4" ] && ! patch -Rf -N -p1 -s --dry-run < ../../../patches/meson.patch; then + patch -N -p1 -s < ../../../patches/meson.patch +fi +echo "Done" + #echo "Checking if remove_abi patch is set or not" #if ! patch -Rf -N -p1 -s --dry-run < ../../../patches/remove_abi.patch; then # echo "apply..." diff --git a/config b/config index 65b1c4f7..57c62014 100644 --- a/config +++ b/config @@ -259,3 +259,4 @@ CONFIG_AUTOREMOVE=y # CONFIG_PACKAGE_kmod-sound-core is not set # CONFIG_PACKAGE_kmod-video-core is not set # CONFIG_PACKAGE_kmod-leds-ubnt-ledbar is not set +# CONFIG_PACKAGE_kmod-ath11k-pci is not set diff --git a/patches/meson.patch b/patches/meson.patch new file mode 100644 index 00000000..c81e929b --- /dev/null +++ b/patches/meson.patch @@ -0,0 +1,89 @@ +diff --git a/include/cmake.mk b/include/cmake.mk +index 96c4d7df3479f..8a1c4fc4d5db7 100644 +--- a/include/cmake.mk ++++ b/include/cmake.mk +@@ -1,5 +1,11 @@ + cmake_bool = $(patsubst %,-D%:BOOL=$(if $($(1)),ON,OFF),$(2)) + ++ifeq ($(PKG_USE_NINJA),1) ++ PKG_BUILD_PARALLEL ?= 1 ++endif ++ifeq ($(HOST_USE_NINJA),1) ++ HOST_BUILD_PARALLEL ?= 1 ++endif + PKG_INSTALL:=1 + + ifneq ($(findstring c,$(OPENWRT_VERBOSE)),) +@@ -44,6 +50,34 @@ CMAKE_FIND_ROOT_PATH:=$(STAGING_DIR)/usr;$(TOOLCHAIN_DIR)$(if $(CONFIG_EXTERNAL_ + CMAKE_HOST_FIND_ROOT_PATH:=$(STAGING_DIR)/host;$(STAGING_DIR_HOSTPKG);$(STAGING_DIR_HOST) + CMAKE_SHARED_LDFLAGS:=-Wl,-Bsymbolic-functions + ++ifeq ($(HOST_USE_NINJA),1) ++ CMAKE_HOST_OPTIONS += -DCMAKE_GENERATOR="Ninja" ++ ++ define Host/Compile/Default ++ +$(NINJA) -C $(HOST_BUILD_DIR) $(1) ++ endef ++ ++ define Host/Install/Default ++ +DESTDIR="$(HOST_INSTALL_DIR)" $(NINJA) -C $(HOST_BUILD_DIR) install ++ endef ++ ++ define Host/Uninstall/Default ++ +DESTDIR="$(HOST_INSTALL_DIR)" $(NINJA) -C $(HOST_BUILD_DIR) uninstall ++ endef ++endif ++ ++ifeq ($(PKG_USE_NINJA),1) ++ CMAKE_OPTIONS += -DCMAKE_GENERATOR="Ninja" ++ ++ define Build/Compile/Default ++ +$(NINJA) -C $(CMAKE_BINARY_DIR) $(1) ++ endef ++ ++ define Build/Install/Default ++ +DESTDIR="$(PKG_INSTALL_DIR)" $(NINJA) -C $(CMAKE_BINARY_DIR) install ++ endef ++endif ++ + define Build/Configure/Default + mkdir -p $(CMAKE_BINARY_DIR) + (cd $(CMAKE_BINARY_DIR); \ +diff --git a/rules.mk b/rules.mk +index 51f822e3f1c5f..8b24d3a3bb416 100644 +--- a/rules.mk ++++ b/rules.mk +@@ -342,6 +342,12 @@ else + $(SCRIPT_DIR)/rstrip.sh + endif + ++NINJA = \ ++ MAKEFLAGS="$(MAKE_JOBSERVER)" \ ++ $(STAGING_DIR_HOST)/bin/ninja \ ++ $(if $(findstring c,$(OPENWRT_VERBOSE)),-v) \ ++ $(if $(MAKE_JOBSERVER),,-j1) ++ + ifeq ($(CONFIG_IPV6),y) + DISABLE_IPV6:= + else +diff --git a/tools/Makefile b/tools/Makefile +index 8752a3e2b5139..47a82fd237828 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -24,7 +24,7 @@ endif + tools-y += autoconf autoconf-archive automake bc bison cmake dosfstools + tools-y += e2fsprogs fakeroot findutils firmware-utils flex gengetopt + tools-y += libressl libtool lzma m4 make-ext4fs missing-macros mkimage +-tools-y += mklibs mm-macros mtd-utils mtools padjffs2 patch-image ++tools-y += mklibs mm-macros mtd-utils mtools ninja meson padjffs2 patch-image + tools-y += patchelf pkgconf quilt squashfskit4 sstrip zip zlib zstd + tools-$(BUILD_B43_TOOLS) += b43-tools + tools-$(BUILD_ISL) += isl +@@ -57,6 +57,7 @@ $(curdir)/libressl/compile := $(curdir)/pkgconf/compile + $(curdir)/libtool/compile := $(curdir)/m4/compile $(curdir)/autoconf/compile $(curdir)/automake/compile $(curdir)/missing-macros/compile + $(curdir)/lzma-old/compile := $(curdir)/zlib/compile + $(curdir)/make-ext4fs/compile := $(curdir)/zlib/compile ++$(curdir)/meson/compile := $(curdir)/ninja/compile + $(curdir)/missing-macros/compile := $(curdir)/autoconf/compile + $(curdir)/mkimage/compile += $(curdir)/libressl/compile + $(curdir)/mklibs/compile := $(curdir)/libtool/compile diff --git a/root/include/kernel-version.mk b/root/include/kernel-version.mk index 652f45b3..e28e6458 100644 --- a/root/include/kernel-version.mk +++ b/root/include/kernel-version.mk @@ -6,7 +6,7 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .203 +LINUX_VERSION-5.4 = .225 LINUX_VERSION-5.15 = .83 LINUX_VERSION-6.1 = .3 @@ -27,6 +27,7 @@ LINUX_KERNEL_HASH-5.15.78 = 0db99f7347a38c27b8c155f3c9c8b260011aea0a4ded85ee95e6 LINUX_KERNEL_HASH-6.1 = 2ca1f17051a430f6fed1196e4952717507171acfd97d96577212502703b25deb LINUX_KERNEL_HASH-5.15.83 = 40590843c04c85789105157f69efbd71a4efe87ae2568e40d1b7258c3f747ff3 LINUX_KERNEL_HASH-6.1.3 = 6dc89ae7a7513e433c597c7346ed7ff4bfd115ea43a3b5e27a6bdb38c5580317 +LINUX_KERNEL_HASH-5.4.225 = 59f596f6714317955cf481590babcf015aff2bc1900bd8e8dc8f7af73bc560aa remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/root/include/meson.mk b/root/include/meson.mk new file mode 100644 index 00000000..7d67dcf2 --- /dev/null +++ b/root/include/meson.mk @@ -0,0 +1,146 @@ +# To build your package using meson: +# +# include $(INCLUDE_DIR)/meson.mk +# MESON_ARGS+=-Dfoo -Dbar=baz +# +# To pass additional environment variables to meson: +# +# MESON_VARS+=FOO=bar +# +# Default configure/compile/install targets are provided, but can be +# overwritten if required: +# +# define Build/Configure +# $(call Build/Configure/Meson) +# ... +# endef +# +# same for Build/Compile and Build/Install +# +# Host packages are built in the same fashion, just use these vars instead: +# +# MESON_HOST_ARGS+=-Dfoo -Dbar=baz +# MESON_HOST_VARS+=FOO=bar + +MESON_DIR:=$(STAGING_DIR_HOST)/lib/meson + +MESON_HOST_BUILD_DIR:=$(HOST_BUILD_DIR)/openwrt-build +MESON_HOST_VARS:= +MESON_HOST_ARGS:= + +MESON_BUILD_DIR:=$(PKG_BUILD_DIR)/openwrt-build +MESON_VARS:= +MESON_ARGS:= + +ifneq ($(findstring i386,$(CONFIG_ARCH)),) +MESON_ARCH:="x86" +else ifneq ($(findstring powerpc64,$(CONFIG_ARCH)),) +MESON_ARCH:="ppc64" +else ifneq ($(findstring powerpc,$(CONFIG_ARCH)),) +MESON_ARCH:="ppc" +else ifneq ($(findstring mips64el,$(CONFIG_ARCH)),) +MESON_ARCH:="mips64" +else ifneq ($(findstring mipsel,$(CONFIG_ARCH)),) +MESON_ARCH:="mips" +else ifneq ($(findstring armeb,$(CONFIG_ARCH)),) +MESON_ARCH:="arm" +else +MESON_ARCH:=$(CONFIG_ARCH) +endif + +# this is undefined for just x64_64 +ifeq ($(origin CPU_TYPE),undefined) +MESON_CPU:="generic" +else +MESON_CPU:="$(CPU_TYPE)$(if $(CPU_SUBTYPE),+$(CPU_SUBTYPE))" +endif + +define Meson + $(2) $(STAGING_DIR_HOST)/bin/$(PYTHON) $(STAGING_DIR_HOST)/bin/meson.py $(1) +endef + +define Meson/CreateNativeFile + $(STAGING_DIR_HOST)/bin/sed \ + -e "s|@CC@|$(foreach BIN,$(HOSTCC),'$(BIN)',)|" \ + -e "s|@CXX@|$(foreach BIN,$(HOSTCXX),'$(BIN)',)|" \ + -e "s|@PKGCONFIG@|$(PKG_CONFIG)|" \ + -e "s|@CMAKE@|$(STAGING_DIR_HOST)/bin/cmake|" \ + -e "s|@PYTHON@|$(STAGING_DIR_HOST)/bin/python3|" \ + -e "s|@CFLAGS@|$(foreach FLAG,$(HOST_CFLAGS) $(HOST_CPPFLAGS),'$(FLAG)',)|" \ + -e "s|@CXXFLAGS@|$(foreach FLAG,$(HOST_CXXFLAGS) $(HOST_CPPFLAGS),'$(FLAG)',)|" \ + -e "s|@LDFLAGS@|$(foreach FLAG,$(HOST_LDFLAGS),'$(FLAG)',)|" \ + -e "s|@PREFIX@|$(HOST_BUILD_PREFIX)|" \ + < $(MESON_DIR)/openwrt-native.txt.in \ + > $(1) +endef + +define Meson/CreateCrossFile + $(STAGING_DIR_HOST)/bin/sed \ + -e "s|@CC@|$(foreach BIN,$(TARGET_CC),'$(BIN)',)|" \ + -e "s|@CXX@|$(foreach BIN,$(TARGET_CXX),'$(BIN)',)|" \ + -e "s|@AR@|$(TARGET_AR)|" \ + -e "s|@STRIP@|$(TARGET_CROSS)strip|" \ + -e "s|@NM@|$(TARGET_NM)|" \ + -e "s|@PKGCONFIG@|$(PKG_CONFIG)|" \ + -e "s|@CMAKE@|$(STAGING_DIR_HOST)/bin/cmake|" \ + -e "s|@PYTHON@|$(STAGING_DIR_HOST)/bin/python3|" \ + -e "s|@CFLAGS@|$(foreach FLAG,$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS),'$(FLAG)',)|" \ + -e "s|@CXXFLAGS@|$(foreach FLAG,$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS),'$(FLAG)',)|" \ + -e "s|@LDFLAGS@|$(foreach FLAG,$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS),'$(FLAG)',)|" \ + -e "s|@ARCH@|$(MESON_ARCH)|" \ + -e "s|@CPU@|$(MESON_CPU)|" \ + -e "s|@ENDIAN@|$(if $(CONFIG_BIG_ENDIAN),big,little)|" \ + < $(MESON_DIR)/openwrt-cross.txt.in \ + > $(1) +endef + +define Host/Configure/Meson + $(call Meson/CreateNativeFile,$(HOST_BUILD_DIR)/openwrt-native.txt) + $(call Meson, \ + --native-file $(HOST_BUILD_DIR)/openwrt-native.txt \ + $(MESON_HOST_ARGS) \ + $(MESON_HOST_BUILD_DIR) \ + $(MESON_HOST_BUILD_DIR)/.., \ + $(MESON_HOST_VARS)) +endef + +define Host/Compile/Meson + +$(NINJA) -C $(MESON_HOST_BUILD_DIR) $(1) +endef + +define Host/Install/Meson + +$(NINJA) -C $(MESON_HOST_BUILD_DIR) install +endef + +define Host/Uninstall/Meson + +$(NINJA) -C $(MESON_HOST_BUILD_DIR) uninstall || true +endef + +define Build/Configure/Meson + $(call Meson/CreateNativeFile,$(PKG_BUILD_DIR)/openwrt-native.txt) + $(call Meson/CreateCrossFile,$(PKG_BUILD_DIR)/openwrt-cross.txt) + $(call Meson, \ + --buildtype plain \ + --native-file $(PKG_BUILD_DIR)/openwrt-native.txt \ + --cross-file $(PKG_BUILD_DIR)/openwrt-cross.txt \ + $(MESON_ARGS) \ + $(MESON_BUILD_DIR) \ + $(MESON_BUILD_DIR)/.., \ + $(MESON_VARS)) +endef + +define Build/Compile/Meson + +$(NINJA) -C $(MESON_BUILD_DIR) $(1) +endef + +define Build/Install/Meson + +DESTDIR="$(PKG_INSTALL_DIR)" $(NINJA) -C $(MESON_BUILD_DIR) install +endef + +Host/Configure=$(call Host/Configure/Meson) +Host/Compile=$(call Host/Compile/Meson) +Host/Install=$(call Host/Install/Meson) +Host/Uninstall=$(call Host/Uninstall/Meson) +Build/Configure=$(call Build/Configure/Meson) +Build/Compile=$(call Build/Compile/Meson) +Build/Install=$(call Build/Install/Meson) diff --git a/root/package/firmware/cypress-firmware/Makefile b/root/package/firmware/cypress-firmware/Makefile new file mode 100644 index 00000000..6a14ff99 --- /dev/null +++ b/root/package/firmware/cypress-firmware/Makefile @@ -0,0 +1,486 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +include $(TOPDIR)/rules.mk + +PKG_NAME:=cypress-firmware +PKG_VERSION:=5.10.9-2022_0909 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/Infineon/ifx-linux-firmware/ +PKG_MIRROR_HASH:=944faae3a80013f1a963b6692d7f50a38c97edcf91fd163de521df755e6922b5 +PKG_SOURCE_VERSION:=release-v$(PKG_VERSION) + +PKG_MAINTAINER:=Álvaro Fernández Rojas +PKG_LICENSE_FILES:=LICENCE + +include $(INCLUDE_DIR)/package.mk + +define Package/cypress-firmware-default + SECTION:=firmware + CATEGORY:=Firmware + URL:=https://community.infineon.com/ +endef + +define Build/Compile + true +endef + +# Cypress 43012 SDIO Firmware +define Package/cypress-firmware-43012-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43012 FullMac SDIO firmware +endef + +define Package/cypress-firmware-43012-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43012-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43012-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43012-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43012-sdio.bin + $(LN) \ + ../cypress/cyfmac43012-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac43012-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-43012-sdio)) + +# Cypress 43340 SDIO Firmware +define Package/cypress-firmware-43340-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43340 FullMac SDIO firmware +endef + +define Package/cypress-firmware-43340-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43340-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43340-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43340-sdio.bin +endef + +$(eval $(call BuildPackage,cypress-firmware-43340-sdio)) + +# Cypress 43362 SDIO Firmware +define Package/cypress-firmware-43362-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43362 FullMac SDIO firmware + PROVIDES:=brcmfmac-firmware-43362-sdio + CONFLICTS:=brcmfmac-firmware-43362-sdio +endef + +define Package/cypress-firmware-43362-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43362-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43362-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43362-sdio.bin +endef + +$(eval $(call BuildPackage,cypress-firmware-43362-sdio)) + +# Cypress 4339 SDIO Firmware +define Package/cypress-firmware-4339-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW4339 FullMac SDIO firmware + PROVIDES:=brcmfmac-firmware-4339-sdio + CONFLICTS:=brcmfmac-firmware-4339-sdio +endef + +define Package/cypress-firmware-4339-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4339-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4339-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac4339-sdio.bin +endef + +$(eval $(call BuildPackage,cypress-firmware-4339-sdio)) + +# Cypress 43430 SDIO Firmware +define Package/cypress-firmware-43430-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43430 FullMac SDIO firmware + PROVIDES:=brcmfmac-firmware-43430-sdio + CONFLICTS:=brcmfmac-firmware-43430-sdio +endef + +define Package/cypress-firmware-43430-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43430-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43430-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43430-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43430-sdio.bin + $(LN) \ + ../cypress/cyfmac43430-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-43430-sdio)) + +# Cypress 43439 SDIO Firmware +define Package/cypress-firmware-43439-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43439 FullMac SDIO firmware +endef + +define Package/cypress-firmware-43439-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43439-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43439-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43439-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43439-sdio.bin + $(LN) \ + ../cypress/cyfmac43439-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac43439-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-43439-sdio)) + +# Cypress 43455 SDIO Firmware +define Package/cypress-firmware-43455-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW43455 FullMac SDIO firmware + PROVIDES:=brcmfmac-firmware-43455-sdio + CONFLICTS:=brcmfmac-firmware-43455-sdio +endef + +define Package/cypress-firmware-43455-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43455-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43455-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43455-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac43455-sdio.bin + $(LN) \ + ../cypress/cyfmac43455-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac43455-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-43455-sdio)) + +# Cypress 4354 SDIO Firmware +define Package/cypress-firmware-4354-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW4354 FullMac SDIO firmware +endef + +define Package/cypress-firmware-4354-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4354-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4354-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4354-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac4354-sdio.bin + $(LN) \ + ../cypress/cyfmac4354-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4354-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4354-sdio)) + +# Cypress 4356 PCIe Firmware +define Package/cypress-firmware-4356-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW4356 FullMac PCIe firmware +endef + +define Package/cypress-firmware-4356-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4356-pcie.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4356-pcie.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4356-pcie.bin \ + $(1)/lib/firmware/brcm/brcmfmac4356-pcie.bin + $(LN) \ + ../cypress/cyfmac4356-pcie.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4356-pcie.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4356-pcie)) + +# Cypress 4356 SDIO Firmware +define Package/cypress-firmware-4356-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW4356 FullMac SDIO firmware +endef + +define Package/cypress-firmware-4356-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4356-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4356-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4356-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac4356-sdio.bin + $(LN) \ + ../cypress/cyfmac4356-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4356-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4356-sdio)) + +# Cypress 43570 PCIe Firmware +define Package/cypress-firmware-43570-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW43570 FullMac PCIe firmware +endef + +define Package/cypress-firmware-43570-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43570-pcie.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac43570-pcie.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac43570-pcie.bin \ + $(1)/lib/firmware/brcm/brcmfmac43570-pcie.bin + $(LN) \ + ../cypress/cyfmac43570-pcie.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac43570-pcie.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-43570-pcie)) + +# Cypress 4373 PCIe Firmware +define Package/cypress-firmware-4373-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW4373 FullMac PCIe firmware +endef + +define Package/cypress-firmware-4373-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373-pcie.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373-pcie.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4373-pcie.bin \ + $(1)/lib/firmware/brcm/brcmfmac4373-pcie.bin + $(LN) \ + ../cypress/cyfmac4373-pcie.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4373-pcie.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4373-pcie)) + +# Cypress 4373 SDIO Firmware +define Package/cypress-firmware-4373-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW4373 FullMac SDIO firmware +endef + +define Package/cypress-firmware-4373-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4373-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac4373-sdio.bin + $(LN) \ + ../cypress/cyfmac4373-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4373-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4373-sdio)) + +# Cypress 4373 USB Firmware +define Package/cypress-firmware-4373-usb + $(Package/cypress-firmware-default) + TITLE:=CYW4373 FullMac USB firmware +endef + +define Package/cypress-firmware-4373-usb/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373-usb.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac4373.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac4373-usb.bin \ + $(1)/lib/firmware/brcm/brcmfmac4373-usb.bin + $(LN) \ + ../cypress/cyfmac4373.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac4373.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-4373-usb)) + +# Cypress 54591 PCIe Firmware +define Package/cypress-firmware-54591-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW54591 FullMac PCIe firmware +endef + +define Package/cypress-firmware-54591-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac54591-pcie.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac54591-pcie.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac54591-pcie.bin \ + $(1)/lib/firmware/brcm/brcmfmac54591-pcie.bin + $(LN) \ + ../cypress/cyfmac54591-pcie.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac54591-pcie.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-54591-pcie)) + +# Cypress 54591 SDIO Firmware +define Package/cypress-firmware-54591-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW54591 FullMac SDIO firmware +endef + +define Package/cypress-firmware-54591-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac54591-sdio.bin \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac54591-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac54591-sdio.bin \ + $(1)/lib/firmware/brcm/brcmfmac54591-sdio.bin + $(LN) \ + ../cypress/cyfmac54591-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac54591-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-54591-sdio)) + +# Cypress 55560 PCIe Firmware +define Package/cypress-firmware-55560-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW55560 FullMac PCIe firmware +endef + +define Package/cypress-firmware-55560-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac55560-pcie.trxse \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac55560-pcie.trxse \ + $(1)/lib/firmware/brcm/brcmfmac55560-pcie.trxse +endef + +$(eval $(call BuildPackage,cypress-firmware-55560-pcie)) + +# Cypress 55572 PCIe Firmware +define Package/cypress-firmware-55572-pcie + $(Package/cypress-firmware-default) + TITLE:=CYW55572 FullMac PCIe firmware +endef + +define Package/cypress-firmware-55572-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac55572-pcie.trxse \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac55572-pcie.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac55572-pcie.trxse \ + $(1)/lib/firmware/brcm/brcmfmac55572-pcie.trxse + $(LN) \ + ../cypress/cyfmac55572-pcie.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac55572-pcie.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-55572-pcie)) + +# Cypress 55572 SDIO Firmware +define Package/cypress-firmware-55572-sdio + $(Package/cypress-firmware-default) + TITLE:=CYW55572 FullMac SDIO firmware +endef + +define Package/cypress-firmware-55572-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/cypress + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac55572-sdio.trxse \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/firmware/cyfmac55572-sdio.clm_blob \ + $(1)/lib/firmware/cypress/ + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(LN) \ + ../cypress/cyfmac55572-sdio.trxse \ + $(1)/lib/firmware/brcm/brcmfmac55572-sdio.trxse + $(LN) \ + ../cypress/cyfmac55572-sdio.clm_blob \ + $(1)/lib/firmware/brcm/brcmfmac55572-sdio.clm_blob +endef + +$(eval $(call BuildPackage,cypress-firmware-55572-sdio)) diff --git a/root/target/linux/generic/config-5.15 b/root/target/linux/generic/config-5.15 index f71f3c0c..36da1a10 100644 --- a/root/target/linux/generic/config-5.15 +++ b/root/target/linux/generic/config-5.15 @@ -7610,3 +7610,5 @@ CONFIG_SERIAL_8250_16550A_VARIANTS=y # CONFIG_ZRAM_DEF_COMP_LZORLE is not set # CONFIG_ZRAM_DEF_COMP_ZSTD is not set # CONFIG_ZRAM_DEF_COMP_LZ4HC is not set +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set diff --git a/root/target/linux/generic/hack-5.4/690-mptcp_v0.96.patch b/root/target/linux/generic/hack-5.4/690-mptcp_v0.96.patch index 537b5e51..09a9e757 100644 --- a/root/target/linux/generic/hack-5.4/690-mptcp_v0.96.patch +++ b/root/target/linux/generic/hack-5.4/690-mptcp_v0.96.patch @@ -50,10 +50,10 @@ index 535ee41ee421..9f82f93e6e77 100644 req = __skb_push(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h -index 680f71ecdc08..6a9dc0368f94 100644 +index eab3a4d02f32..e8b164781bbb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -717,7 +717,7 @@ struct sk_buff { +@@ -718,7 +718,7 @@ struct sk_buff { * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ @@ -75,7 +75,7 @@ index a465c6a45d6f..3bfdbfb49c5a 100644 /* IPX options */ #define IPX_TYPE 1 diff --git a/include/linux/tcp.h b/include/linux/tcp.h -index 358deb4ff830..aebfedba9838 100644 +index 89751c89f11f..4d8f36da81de 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -54,7 +54,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) @@ -299,10 +299,10 @@ index 58db7c69c146..1acaa5e45f15 100644 union { diff --git a/include/net/mptcp.h b/include/net/mptcp.h new file mode 100644 -index 000000000000..d565634f760f +index 000000000000..281558f4983e --- /dev/null +++ b/include/net/mptcp.h -@@ -0,0 +1,1559 @@ +@@ -0,0 +1,1601 @@ +/* + * MPTCP implementation + * @@ -1668,6 +1668,48 @@ index 000000000000..d565634f760f + return i; +} + ++static inline bool mptcp_options_add_addr4_enough_space(const struct mptcp_cb *mpcb, ++ unsigned int size) ++{ ++ unsigned int remaining = MAX_TCP_OPTION_SPACE - size; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ return remaining >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ ++ return remaining >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++} ++ ++static inline bool mptcp_options_add_addr6_enough_space(const struct mptcp_cb *mpcb, ++ unsigned int size) ++{ ++ unsigned int remaining = MAX_TCP_OPTION_SPACE - size; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ return remaining >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ ++ return remaining >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++} ++ ++static inline bool mptcp_options_rm_addr_enough_space(u16 remove_addrs, ++ int *remove_addr_len, ++ unsigned int size) ++{ ++ unsigned int remaining = MAX_TCP_OPTION_SPACE - size; ++ ++ *remove_addr_len = mptcp_sub_len_remove_addr_align(remove_addrs); ++ ++ return remaining >= *remove_addr_len; ++} ++ ++unsigned int mptcp_options_fill_add_addr4(struct mptcp_cb *mpcb, ++ struct tcp_out_options *opts, ++ struct mptcp_loc4 *loc); ++unsigned int mptcp_options_fill_add_addr6(struct mptcp_cb *mpcb, ++ struct tcp_out_options *opts, ++ struct mptcp_loc6 *loc); ++unsigned int mptcp_options_fill_rm_addr(struct tcp_out_options *opts, ++ u16 remove_addrs, int remove_addr_len); ++ +/* TCP and MPTCP mpc flag-depending functions */ +u16 mptcp_select_window(struct sock *sk); +void mptcp_tcp_set_rto(struct sock *sk); @@ -2120,7 +2162,7 @@ index cb8ced4380a6..0aa0d10af2ce 100644 #define TCP_MIB_MAX __TCP_MIB_MAX struct tcp_mib { diff --git a/include/net/sock.h b/include/net/sock.h -index 9d687070d272..4c40e2af33f1 100644 +index f508e86a2021..bc3a92c6ca44 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -821,6 +821,7 @@ enum sock_flags { @@ -2171,7 +2213,7 @@ index 9d687070d272..4c40e2af33f1 100644 bool lock_sock_fast(struct sock *sk); /** diff --git a/include/net/tcp.h b/include/net/tcp.h -index 8459145497b7..c1b90862e3cc 100644 +index 077feeca6c99..b9b3f4d995fd 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -182,6 +182,7 @@ @@ -2462,7 +2504,7 @@ index 8459145497b7..c1b90862e3cc 100644 union { struct { /* There is space for up to 24 bytes */ -@@ -1090,6 +1259,8 @@ struct tcp_congestion_ops { +@@ -1092,6 +1261,8 @@ struct tcp_congestion_ops { int tcp_set_allowed_congestion_control(char *allowed); int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, bool reinit, bool cap_net_admin); @@ -2471,7 +2513,7 @@ index 8459145497b7..c1b90862e3cc 100644 u32 tcp_slow_start(struct tcp_sock *tp, u32 acked); void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked); -@@ -1396,6 +1567,19 @@ static inline int tcp_win_from_space(const struct sock *sk, int space) +@@ -1401,6 +1572,19 @@ static inline int tcp_win_from_space(const struct sock *sk, int space) space - (space>>tcp_adv_win_scale); } @@ -2491,7 +2533,7 @@ index 8459145497b7..c1b90862e3cc 100644 /* Note: caller must be prepared to deal with negative returns */ static inline int tcp_space(const struct sock *sk) { -@@ -1989,6 +2173,30 @@ struct tcp_sock_af_ops { +@@ -1994,6 +2178,30 @@ struct tcp_sock_af_ops { #endif }; @@ -2522,7 +2564,7 @@ index 8459145497b7..c1b90862e3cc 100644 struct tcp_request_sock_ops { u16 mss_clamp; #ifdef CONFIG_TCP_MD5SIG -@@ -1999,12 +2207,13 @@ struct tcp_request_sock_ops { +@@ -2004,12 +2212,13 @@ struct tcp_request_sock_ops { const struct sock *sk, const struct sk_buff *skb); #endif @@ -2541,7 +2583,7 @@ index 8459145497b7..c1b90862e3cc 100644 #endif struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, const struct request_sock *req); -@@ -2023,15 +2232,17 @@ struct tcp_request_sock_ops { +@@ -2028,15 +2237,17 @@ struct tcp_request_sock_ops { #ifdef CONFIG_SYN_COOKIES static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, @@ -3198,10 +3240,10 @@ index a2b12a5cf42b..222762983441 100644 /* sk->sk_memcg will be populated at accept() time */ newsk->sk_memcg = NULL; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig -index a926de2e42b5..6d73dc6e2586 100644 +index f5af8c6b2f87..17a46590ced4 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig -@@ -655,6 +655,51 @@ config TCP_CONG_BBR +@@ -665,6 +665,51 @@ config TCP_CONG_BBR bufferbloat, policers, or AQM schemes that do not provide a delay signal. It requires the fq ("Fair Queue") pacing packet scheduler. @@ -3253,7 +3295,7 @@ index a926de2e42b5..6d73dc6e2586 100644 choice prompt "Default TCP congestion control" default DEFAULT_CUBIC -@@ -692,6 +737,21 @@ choice +@@ -702,6 +747,21 @@ choice config DEFAULT_BBR bool "BBR" if TCP_CONG_BBR=y @@ -3275,7 +3317,7 @@ index a926de2e42b5..6d73dc6e2586 100644 config DEFAULT_RENO bool "Reno" endchoice -@@ -712,6 +772,10 @@ config DEFAULT_TCP_CONG +@@ -722,6 +782,10 @@ config DEFAULT_TCP_CONG default "vegas" if DEFAULT_VEGAS default "westwood" if DEFAULT_WESTWOOD default "veno" if DEFAULT_VENO @@ -3287,7 +3329,7 @@ index a926de2e42b5..6d73dc6e2586 100644 default "dctcp" if DEFAULT_DCTCP default "cdg" if DEFAULT_CDG diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index d61ca7be6eda..8e474fe9dfd8 100644 +index 3c6412cb4b48..bf84fb3817ee 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -100,6 +100,7 @@ @@ -3342,7 +3384,7 @@ index d61ca7be6eda..8e474fe9dfd8 100644 WARN_ON(!((1 << sk2->sk_state) & (TCPF_ESTABLISHED | TCPF_SYN_RECV | TCPF_CLOSE_WAIT | TCPF_CLOSE))); -@@ -1981,6 +2001,9 @@ static int __init inet_init(void) +@@ -1971,6 +1991,9 @@ static int __init inet_init(void) if (init_ipv4_mibs()) panic("%s: Cannot init ipv4 mibs\n", __func__); @@ -3353,7 +3395,7 @@ index d61ca7be6eda..8e474fe9dfd8 100644 tcp_init(); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c -index 6cbf0db57ad0..be95a4b0ffa2 100644 +index 6cbf0db57ad0..61d829c2613d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -19,6 +19,7 @@ @@ -3387,22 +3429,24 @@ index 6cbf0db57ad0..be95a4b0ffa2 100644 if (newsk) { struct inet_connection_sock *newicsk = inet_csk(newsk); -@@ -966,6 +972,14 @@ struct sock *inet_csk_reqsk_queue_add(struct sock *sk, +@@ -966,6 +972,16 @@ struct sock *inet_csk_reqsk_queue_add(struct sock *sk, spin_lock(&queue->rskq_lock); if (unlikely(sk->sk_state != TCP_LISTEN)) { -+ struct tcp_sock *tp = tcp_sk(sk); ++ if (sk->sk_protocol == IPPROTO_TCP) { ++ struct tcp_sock *child_tp = tcp_sk(child); + -+ /* in case of mptcp, two locks may been taken, one -+ * on the meta, the other on master_sk -+ */ -+ if (mptcp(tp) && tp->mpcb && tp->mpcb->master_sk) -+ bh_unlock_sock(tp->mpcb->master_sk); ++ /* in case of mptcp, two locks may been taken, one ++ * on the meta, the other on master_sk ++ */ ++ if (mptcp(child_tp) && child_tp->mpcb && child_tp->mpcb->master_sk) ++ bh_unlock_sock(child_tp->mpcb->master_sk); ++ } + inet_child_forget(sk, req, child); child = NULL; } else { -@@ -1019,7 +1033,14 @@ void inet_csk_listen_stop(struct sock *sk) +@@ -1019,7 +1035,14 @@ void inet_csk_listen_stop(struct sock *sk) */ while ((req = reqsk_queue_remove(queue, sk)) != NULL) { struct sock *child = req->sk; @@ -3417,7 +3461,7 @@ index 6cbf0db57ad0..be95a4b0ffa2 100644 local_bh_disable(); bh_lock_sock(child); WARN_ON(sock_owned_by_user(child)); -@@ -1029,6 +1050,10 @@ void inet_csk_listen_stop(struct sock *sk) +@@ -1029,6 +1052,10 @@ void inet_csk_listen_stop(struct sock *sk) reqsk_put(req); bh_unlock_sock(child); local_bh_enable(); @@ -3603,7 +3647,7 @@ index 3f6c9514c7a9..9dc0cff27ad8 100644 * Normal sockets get it right from inet_csk_route_child_sock() */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 0a570d5d0b38..521095c03ecf 100644 +index 93825ec968aa..aac80ddc837f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -270,6 +270,7 @@ @@ -3975,7 +4019,7 @@ index 0a570d5d0b38..521095c03ecf 100644 tcp_chrono_stop(sk, TCP_CHRONO_BUSY); while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { tcp_skb_tsorted_anchor_cleanup(skb); -@@ -2572,6 +2666,36 @@ void tcp_write_queue_purge(struct sock *sk) +@@ -2572,6 +2666,38 @@ void tcp_write_queue_purge(struct sock *sk) inet_csk(sk)->icsk_backoff = 0; } @@ -3992,6 +4036,8 @@ index 0a570d5d0b38..521095c03ecf 100644 + tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; + tp->snd_cwnd = TCP_INIT_CWND; + tp->snd_cwnd_cnt = 0; ++ tp->is_cwnd_limited = 0; ++ tp->max_packets_out = 0; + tp->delivered = 0; + tp->delivered_ce = 0; + tp->is_sack_reneg = 0; @@ -4012,7 +4058,7 @@ index 0a570d5d0b38..521095c03ecf 100644 int tcp_disconnect(struct sock *sk, int flags) { struct inet_sock *inet = inet_sk(sk); -@@ -2594,7 +2718,7 @@ int tcp_disconnect(struct sock *sk, int flags) +@@ -2594,7 +2720,7 @@ int tcp_disconnect(struct sock *sk, int flags) /* The last check adjusts for discrepancy of Linux wrt. RFC * states */ @@ -4021,7 +4067,7 @@ index 0a570d5d0b38..521095c03ecf 100644 sk->sk_err = ECONNRESET; } else if (old_state == TCP_SYN_SENT) sk->sk_err = ECONNRESET; -@@ -2616,11 +2740,16 @@ int tcp_disconnect(struct sock *sk, int flags) +@@ -2616,11 +2742,16 @@ int tcp_disconnect(struct sock *sk, int flags) if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); @@ -4041,7 +4087,7 @@ index 0a570d5d0b38..521095c03ecf 100644 seq = tp->write_seq + tp->max_window + 2; if (!seq) -@@ -2630,21 +2759,14 @@ int tcp_disconnect(struct sock *sk, int flags) +@@ -2630,23 +2761,14 @@ int tcp_disconnect(struct sock *sk, int flags) icsk->icsk_backoff = 0; tp->snd_cwnd = 2; icsk->icsk_probes_out = 0; @@ -4050,6 +4096,8 @@ index 0a570d5d0b38..521095c03ecf 100644 - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; - tp->snd_cwnd = TCP_INIT_CWND; - tp->snd_cwnd_cnt = 0; +- tp->is_cwnd_limited = 0; +- tp->max_packets_out = 0; tp->window_clamp = 0; - tp->delivered = 0; - tp->delivered_ce = 0; @@ -4066,8 +4114,8 @@ index 0a570d5d0b38..521095c03ecf 100644 inet_csk_delack_init(sk); /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 * issue in __tcp_select_window() -@@ -2656,14 +2778,6 @@ int tcp_disconnect(struct sock *sk, int flags) - sk->sk_rx_dst = NULL; +@@ -2657,14 +2779,6 @@ int tcp_disconnect(struct sock *sk, int flags) + dst_release(xchg((__force struct dst_entry **)&sk->sk_rx_dst, NULL)); tcp_saved_syn_free(tp); tp->compressed_ack = 0; - tp->segs_in = 0; @@ -4081,7 +4129,7 @@ index 0a570d5d0b38..521095c03ecf 100644 tp->duplicate_sack[0].start_seq = 0; tp->duplicate_sack[0].end_seq = 0; tp->dsack_dups = 0; -@@ -2672,8 +2786,6 @@ int tcp_disconnect(struct sock *sk, int flags) +@@ -2673,8 +2787,6 @@ int tcp_disconnect(struct sock *sk, int flags) tp->sacked_out = 0; tp->tlp_high_seq = 0; tp->last_oow_ack_time = 0; @@ -4090,7 +4138,7 @@ index 0a570d5d0b38..521095c03ecf 100644 tp->rack.mstamp = 0; tp->rack.advanced = 0; tp->rack.reo_wnd_steps = 1; -@@ -2707,7 +2819,7 @@ int tcp_disconnect(struct sock *sk, int flags) +@@ -2708,7 +2820,7 @@ int tcp_disconnect(struct sock *sk, int flags) static inline bool tcp_can_repair_sock(const struct sock *sk) { return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && @@ -4099,7 +4147,7 @@ index 0a570d5d0b38..521095c03ecf 100644 } static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) -@@ -2738,6 +2850,7 @@ static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int l +@@ -2739,6 +2851,7 @@ static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int l tp->rcv_wnd = opt.rcv_wnd; tp->rcv_wup = opt.rcv_wup; @@ -4107,7 +4155,7 @@ index 0a570d5d0b38..521095c03ecf 100644 return 0; } -@@ -2876,6 +2989,61 @@ static int do_tcp_setsockopt(struct sock *sk, int level, +@@ -2877,6 +2990,61 @@ static int do_tcp_setsockopt(struct sock *sk, int level, return tcp_fastopen_reset_cipher(net, sk, key, backup_key); } @@ -4169,7 +4217,7 @@ index 0a570d5d0b38..521095c03ecf 100644 default: /* fallthru */ break; -@@ -3065,6 +3233,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level, +@@ -3066,6 +3234,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; case TCP_DEFER_ACCEPT: @@ -4182,7 +4230,7 @@ index 0a570d5d0b38..521095c03ecf 100644 /* Translate value in seconds to number of retransmits */ icsk->icsk_accept_queue.rskq_defer_accept = secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, -@@ -3092,7 +3266,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, +@@ -3093,7 +3267,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && inet_csk_ack_scheduled(sk)) { icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; @@ -4191,7 +4239,7 @@ index 0a570d5d0b38..521095c03ecf 100644 if (!(val & 1)) inet_csk_enter_pingpong_mode(sk); } -@@ -3102,7 +3276,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, +@@ -3103,7 +3277,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, #ifdef CONFIG_TCP_MD5SIG case TCP_MD5SIG: case TCP_MD5SIG_EXT: @@ -4203,7 +4251,7 @@ index 0a570d5d0b38..521095c03ecf 100644 break; #endif case TCP_USER_TIMEOUT: -@@ -3159,6 +3336,33 @@ static int do_tcp_setsockopt(struct sock *sk, int level, +@@ -3160,6 +3337,33 @@ static int do_tcp_setsockopt(struct sock *sk, int level, tp->notsent_lowat = val; sk->sk_write_space(sk); break; @@ -4237,7 +4285,7 @@ index 0a570d5d0b38..521095c03ecf 100644 case TCP_INQ: if (val > 1 || val < 0) err = -EINVAL; -@@ -3223,7 +3427,7 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp, +@@ -3224,7 +3428,7 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp, } /* Return information about state of tcp endpoint in API format. */ @@ -4246,7 +4294,7 @@ index 0a570d5d0b38..521095c03ecf 100644 { const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ const struct inet_connection_sock *icsk = inet_csk(sk); -@@ -3260,7 +3464,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) +@@ -3261,7 +3465,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) return; } @@ -4256,7 +4304,7 @@ index 0a570d5d0b38..521095c03ecf 100644 info->tcpi_ca_state = icsk->icsk_ca_state; info->tcpi_retransmits = icsk->icsk_retransmits; -@@ -3336,7 +3541,9 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) +@@ -3337,7 +3542,9 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_reord_seen = tp->reord_seen; info->tcpi_rcv_ooopack = tp->rcv_ooopack; info->tcpi_snd_wnd = tp->snd_wnd; @@ -4267,7 +4315,7 @@ index 0a570d5d0b38..521095c03ecf 100644 } EXPORT_SYMBOL_GPL(tcp_get_info); -@@ -3483,7 +3690,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, +@@ -3484,7 +3691,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, if (get_user(len, optlen)) return -EFAULT; @@ -4276,7 +4324,7 @@ index 0a570d5d0b38..521095c03ecf 100644 len = min_t(unsigned int, len, sizeof(info)); if (put_user(len, optlen)) -@@ -3672,6 +3879,87 @@ static int do_tcp_getsockopt(struct sock *sk, int level, +@@ -3673,6 +3880,87 @@ static int do_tcp_getsockopt(struct sock *sk, int level, } return 0; } @@ -4364,7 +4412,7 @@ index 0a570d5d0b38..521095c03ecf 100644 #ifdef CONFIG_MMU case TCP_ZEROCOPY_RECEIVE: { struct tcp_zerocopy_receive zc; -@@ -3707,6 +3995,8 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, +@@ -3708,6 +3996,8 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, { struct inet_connection_sock *icsk = inet_csk(sk); @@ -4373,7 +4421,7 @@ index 0a570d5d0b38..521095c03ecf 100644 if (level != SOL_TCP) return icsk->icsk_af_ops->getsockopt(sk, level, optname, optval, optlen); -@@ -3877,7 +4167,9 @@ void tcp_done(struct sock *sk) +@@ -3884,7 +4174,9 @@ void tcp_done(struct sock *sk) if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); @@ -4383,7 +4431,7 @@ index 0a570d5d0b38..521095c03ecf 100644 tcp_clear_xmit_timers(sk); if (req) reqsk_fastopen_remove(sk, req, false); -@@ -3893,6 +4185,8 @@ void tcp_done(struct sock *sk) +@@ -3900,6 +4192,8 @@ void tcp_done(struct sock *sk) int tcp_abort(struct sock *sk, int err) { @@ -4392,7 +4440,7 @@ index 0a570d5d0b38..521095c03ecf 100644 if (!sk_fullsock(sk)) { if (sk->sk_state == TCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk); -@@ -3906,7 +4200,7 @@ int tcp_abort(struct sock *sk, int err) +@@ -3913,7 +4207,7 @@ int tcp_abort(struct sock *sk, int err) } /* Don't race with userspace socket closes such as tcp_close. */ @@ -4401,7 +4449,7 @@ index 0a570d5d0b38..521095c03ecf 100644 if (sk->sk_state == TCP_LISTEN) { tcp_set_state(sk, TCP_CLOSE); -@@ -3915,7 +4209,7 @@ int tcp_abort(struct sock *sk, int err) +@@ -3922,7 +4216,7 @@ int tcp_abort(struct sock *sk, int err) /* Don't race with BH socket closes such as inet_csk_listen_stop. */ local_bh_disable(); @@ -4410,7 +4458,7 @@ index 0a570d5d0b38..521095c03ecf 100644 if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_err = err; -@@ -3923,14 +4217,14 @@ int tcp_abort(struct sock *sk, int err) +@@ -3930,14 +4224,14 @@ int tcp_abort(struct sock *sk, int err) smp_wmb(); sk->sk_error_report(sk); if (tcp_need_reset(sk->sk_state)) @@ -4531,7 +4579,7 @@ index 21705b2ddaff..8b439c148e2c 100644 * and queues the child into listener accept queue. */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index 0ebba83dbe22..777c1301e433 100644 +index 44398317f033..b4612a5969b4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -76,35 +76,15 @@ @@ -4675,7 +4723,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Normally R but no L won't result in plain S */ if (!dup_sack && (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS) -@@ -2980,7 +2987,7 @@ static bool tcp_ack_update_rtt(struct sock *sk, const int flag, +@@ -2981,7 +2988,7 @@ static bool tcp_ack_update_rtt(struct sock *sk, const int flag, */ tcp_update_rtt_min(sk, ca_rtt_us, flag); tcp_rtt_estimator(sk, seq_rtt_us); @@ -4684,7 +4732,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* RFC6298: only reset backoff on valid RTT measurement. */ inet_csk(sk)->icsk_backoff = 0; -@@ -3048,7 +3055,7 @@ static void tcp_set_xmit_timer(struct sock *sk) +@@ -3049,7 +3056,7 @@ static void tcp_set_xmit_timer(struct sock *sk) } /* If we get here, the whole TSO packet has not been acked. */ @@ -4693,7 +4741,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct tcp_sock *tp = tcp_sk(sk); u32 packets_acked; -@@ -3068,8 +3075,7 @@ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) +@@ -3069,8 +3076,7 @@ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) return packets_acked; } @@ -4703,7 +4751,7 @@ index 0ebba83dbe22..777c1301e433 100644 { const struct skb_shared_info *shinfo; -@@ -3174,6 +3180,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, +@@ -3175,6 +3181,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, */ if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { flag |= FLAG_DATA_ACKED; @@ -4712,7 +4760,7 @@ index 0ebba83dbe22..777c1301e433 100644 } else { flag |= FLAG_SYN_ACKED; tp->retrans_stamp = 0; -@@ -3294,7 +3302,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, +@@ -3295,7 +3303,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, return flag; } @@ -4721,7 +4769,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct inet_connection_sock *icsk = inet_csk(sk); struct sk_buff *head = tcp_send_head(sk); -@@ -3369,9 +3377,8 @@ static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked, +@@ -3370,9 +3378,8 @@ static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked, /* Check that window update is acceptable. * The function assumes that snd_una<=ack<=snd_next. */ @@ -4733,7 +4781,7 @@ index 0ebba83dbe22..777c1301e433 100644 { return after(ack, tp->snd_una) || after(ack_seq, tp->snd_wl1) || -@@ -3610,7 +3617,7 @@ static u32 tcp_newly_delivered(struct sock *sk, u32 prior_delivered, int flag) +@@ -3611,7 +3618,7 @@ static u32 tcp_newly_delivered(struct sock *sk, u32 prior_delivered, int flag) } /* This routine deals with incoming acks, but not outgoing ones. */ @@ -4742,7 +4790,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); -@@ -3733,6 +3740,14 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) +@@ -3734,6 +3741,14 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) tcp_rack_update_reo_wnd(sk, &rs); @@ -4757,7 +4805,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (tp->tlp_high_seq) tcp_process_tlp_ack(sk, ack, flag); -@@ -3877,8 +3892,10 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) +@@ -3878,8 +3893,10 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) */ void tcp_parse_options(const struct net *net, const struct sk_buff *skb, @@ -4770,7 +4818,7 @@ index 0ebba83dbe22..777c1301e433 100644 { const unsigned char *ptr; const struct tcphdr *th = tcp_hdr(skb); -@@ -3964,6 +3981,10 @@ void tcp_parse_options(const struct net *net, +@@ -3965,6 +3982,10 @@ void tcp_parse_options(const struct net *net, */ break; #endif @@ -4781,7 +4829,7 @@ index 0ebba83dbe22..777c1301e433 100644 case TCPOPT_FASTOPEN: tcp_parse_fastopen_option( opsize - TCPOLEN_FASTOPEN_BASE, -@@ -4031,7 +4052,9 @@ static bool tcp_fast_parse_options(const struct net *net, +@@ -4032,7 +4053,9 @@ static bool tcp_fast_parse_options(const struct net *net, return true; } @@ -4792,7 +4840,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) tp->rx_opt.rcv_tsecr -= tp->tsoffset; -@@ -4141,7 +4164,7 @@ static inline bool tcp_paws_discard(const struct sock *sk, +@@ -4142,7 +4165,7 @@ static inline bool tcp_paws_discard(const struct sock *sk, static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) { return !before(end_seq, tp->rcv_wup) && @@ -4801,7 +4849,7 @@ index 0ebba83dbe22..777c1301e433 100644 } /* When we get a reset we do this. */ -@@ -4190,6 +4213,11 @@ void tcp_fin(struct sock *sk) +@@ -4191,6 +4214,11 @@ void tcp_fin(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -4813,7 +4861,7 @@ index 0ebba83dbe22..777c1301e433 100644 inet_csk_schedule_ack(sk); sk->sk_shutdown |= RCV_SHUTDOWN; -@@ -4200,6 +4228,10 @@ void tcp_fin(struct sock *sk) +@@ -4201,6 +4229,10 @@ void tcp_fin(struct sock *sk) case TCP_ESTABLISHED: /* Move to CLOSE_WAIT */ tcp_set_state(sk, TCP_CLOSE_WAIT); @@ -4824,7 +4872,7 @@ index 0ebba83dbe22..777c1301e433 100644 inet_csk_enter_pingpong_mode(sk); break; -@@ -4222,9 +4254,16 @@ void tcp_fin(struct sock *sk) +@@ -4223,9 +4255,16 @@ void tcp_fin(struct sock *sk) tcp_set_state(sk, TCP_CLOSING); break; case TCP_FIN_WAIT2: @@ -4842,7 +4890,7 @@ index 0ebba83dbe22..777c1301e433 100644 break; default: /* Only TCP_LISTEN and TCP_CLOSE are left, in these -@@ -4246,6 +4285,10 @@ void tcp_fin(struct sock *sk) +@@ -4247,6 +4286,10 @@ void tcp_fin(struct sock *sk) if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); @@ -4853,7 +4901,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Do not send POLL_HUP for half duplex close. */ if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) -@@ -4460,6 +4503,9 @@ static bool tcp_try_coalesce(struct sock *sk, +@@ -4461,6 +4504,9 @@ static bool tcp_try_coalesce(struct sock *sk, *fragstolen = false; @@ -4863,7 +4911,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Its possible this segment overlaps with prior segment in queue */ if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) return false; -@@ -4514,7 +4560,7 @@ static void tcp_drop(struct sock *sk, struct sk_buff *skb) +@@ -4515,7 +4561,7 @@ static void tcp_drop(struct sock *sk, struct sk_buff *skb) /* This one checks to see if we can put data from the * out_of_order queue into the receive_queue. */ @@ -4872,7 +4920,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct tcp_sock *tp = tcp_sk(sk); __u32 dsack_high = tp->rcv_nxt; -@@ -4537,7 +4583,14 @@ static void tcp_ofo_queue(struct sock *sk) +@@ -4538,7 +4584,14 @@ static void tcp_ofo_queue(struct sock *sk) p = rb_next(p); rb_erase(&skb->rbnode, &tp->out_of_order_queue); @@ -4888,7 +4936,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_drop(sk, skb); continue; } -@@ -4567,21 +4620,23 @@ static void tcp_ofo_queue(struct sock *sk) +@@ -4568,21 +4621,23 @@ static void tcp_ofo_queue(struct sock *sk) static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, unsigned int size) { @@ -4916,7 +4964,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct tcp_sock *tp = tcp_sk(sk); struct rb_node **p, *parent; -@@ -4653,7 +4708,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) +@@ -4654,7 +4709,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) continue; } if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { @@ -4926,7 +4974,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* All the bits are present. Drop. */ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); -@@ -4700,6 +4756,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) +@@ -4701,6 +4757,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) end_seq); break; } @@ -4938,7 +4986,7 @@ index 0ebba83dbe22..777c1301e433 100644 rb_erase(&skb1->rbnode, &tp->out_of_order_queue); tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq); -@@ -4711,7 +4772,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) +@@ -4712,7 +4773,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) tp->ooo_last_skb = skb; add_sack: @@ -4947,7 +4995,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_sack_new_ofo_skb(sk, seq, end_seq); end: if (skb) { -@@ -4725,8 +4786,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) +@@ -4726,8 +4787,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) } } @@ -4958,7 +5006,7 @@ index 0ebba83dbe22..777c1301e433 100644 { int eaten; struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); -@@ -4801,7 +4862,8 @@ void tcp_data_ready(struct sock *sk) +@@ -4802,7 +4863,8 @@ void tcp_data_ready(struct sock *sk) if (avail < sk->sk_rcvlowat && !tcp_rmem_pressure(sk) && !sock_flag(sk, SOCK_DONE) && @@ -4968,7 +5016,7 @@ index 0ebba83dbe22..777c1301e433 100644 return; sk->sk_data_ready(sk); -@@ -4813,10 +4875,14 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4814,10 +4876,14 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) bool fragstolen; int eaten; @@ -4984,7 +5032,7 @@ index 0ebba83dbe22..777c1301e433 100644 skb_dst_drop(skb); __skb_pull(skb, tcp_hdr(skb)->doff * 4); -@@ -4827,7 +4893,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4828,7 +4894,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) * Out of sequence packets to the out_of_order_queue. */ if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { @@ -4993,7 +5041,7 @@ index 0ebba83dbe22..777c1301e433 100644 NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPZEROWINDOWDROP); goto out_of_window; } -@@ -4843,7 +4909,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4844,7 +4910,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) } eaten = tcp_queue_rcv(sk, skb, &fragstolen); @@ -5002,7 +5050,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_event_data_recv(sk, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) tcp_fin(sk); -@@ -4865,7 +4931,11 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4866,7 +4932,11 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (eaten > 0) kfree_skb_partial(skb, fragstolen); @@ -5015,7 +5063,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_data_ready(sk); return; } -@@ -4885,7 +4955,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4886,7 +4956,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) } /* Out of window. F.e. zero window probe. */ @@ -5025,7 +5073,7 @@ index 0ebba83dbe22..777c1301e433 100644 goto out_of_window; if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { -@@ -4895,7 +4966,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +@@ -4896,7 +4967,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) /* If window is closed, drop tail of packet. But after * remembering D-SACK for its head made in previous line. */ @@ -5034,7 +5082,7 @@ index 0ebba83dbe22..777c1301e433 100644 NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPZEROWINDOWDROP); goto out_of_window; } -@@ -5208,7 +5279,7 @@ static int tcp_prune_queue(struct sock *sk) +@@ -5209,7 +5280,7 @@ static int tcp_prune_queue(struct sock *sk) return -1; } @@ -5043,7 +5091,7 @@ index 0ebba83dbe22..777c1301e433 100644 { const struct tcp_sock *tp = tcp_sk(sk); -@@ -5243,7 +5314,7 @@ static void tcp_new_space(struct sock *sk) +@@ -5244,7 +5315,7 @@ static void tcp_new_space(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -5052,7 +5100,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_sndbuf_expand(sk); tp->snd_cwnd_stamp = tcp_jiffies32; } -@@ -5267,10 +5338,11 @@ void tcp_check_space(struct sock *sk) +@@ -5268,10 +5339,11 @@ void tcp_check_space(struct sock *sk) sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); /* pairs with tcp_poll() */ smp_mb(); @@ -5067,7 +5115,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); } } -@@ -5289,6 +5361,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) +@@ -5290,6 +5362,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) { struct tcp_sock *tp = tcp_sk(sk); unsigned long rtt, delay; @@ -5076,7 +5124,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && -@@ -5297,8 +5371,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) +@@ -5298,8 +5372,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) * If application uses SO_RCVLOWAT, we want send ack now if * we have not received enough bytes to satisfy the condition. */ @@ -5087,7 +5135,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* We ACK each frame or... */ tcp_in_quickack_mode(sk) || /* Protocol state mandates a one-time immediate ACK */ -@@ -5434,6 +5508,10 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t +@@ -5435,6 +5509,10 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t { struct tcp_sock *tp = tcp_sk(sk); @@ -5098,7 +5146,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Check if we get a new urgent pointer - normally not. */ if (th->urg) tcp_check_urg(sk, th); -@@ -5576,9 +5654,15 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, +@@ -5577,9 +5655,15 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, goto discard; } @@ -5114,7 +5162,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_drop(sk, skb); return false; } -@@ -5635,6 +5719,10 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb) +@@ -5636,6 +5720,10 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb) tp->rx_opt.saw_tstamp = 0; @@ -5125,7 +5173,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* pred_flags is 0xS?10 << 16 + snd_wnd * if header_prediction is to be made * 'S' will always be tp->tcp_header_len >> 2 -@@ -5809,7 +5897,7 @@ void tcp_init_transfer(struct sock *sk, int bpf_op) +@@ -5810,7 +5898,7 @@ void tcp_init_transfer(struct sock *sk, int bpf_op) tcp_call_bpf(sk, bpf_op, 0, NULL); tcp_init_congestion_control(sk); @@ -5134,7 +5182,7 @@ index 0ebba83dbe22..777c1301e433 100644 } void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) -@@ -5846,17 +5934,24 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, +@@ -5847,17 +5935,24 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, struct tcp_fastopen_cookie *cookie) { struct tcp_sock *tp = tcp_sk(sk); @@ -5161,7 +5209,7 @@ index 0ebba83dbe22..777c1301e433 100644 mss = opt.mss_clamp; } -@@ -5880,7 +5975,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, +@@ -5881,7 +5976,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); @@ -5174,7 +5222,7 @@ index 0ebba83dbe22..777c1301e433 100644 skb_rbtree_walk_from(data) { if (__tcp_retransmit_skb(sk, data, 1)) break; -@@ -5935,9 +6034,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -5936,9 +6035,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_cookie foc = { .len = -1 }; int saved_clamp = tp->rx_opt.mss_clamp; @@ -5189,7 +5237,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) tp->rx_opt.rcv_tsecr -= tp->tsoffset; -@@ -5998,11 +6101,41 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -5999,11 +6102,41 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_try_undo_spurious_syn(sk); tcp_ack(sk, skb, FLAG_SLOWPATH); @@ -5231,7 +5279,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* RFC1323: The window in SYN & SYN/ACK segments is * never scaled. -@@ -6024,6 +6157,11 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -6025,6 +6158,11 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tp->tcp_header_len = sizeof(struct tcphdr); } @@ -5243,7 +5291,7 @@ index 0ebba83dbe22..777c1301e433 100644 tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); tcp_initialize_rcv_mss(sk); -@@ -6047,9 +6185,12 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -6048,9 +6186,12 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, } if (fastopen_fail) return -1; @@ -5258,7 +5306,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Save one ACK. Data will be ready after * several ticks, if write_pending is set. * -@@ -6088,6 +6229,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -6089,6 +6230,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_paws_reject(&tp->rx_opt, 0)) goto discard_and_undo; @@ -5266,7 +5314,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (th->syn) { /* We see SYN without ACK. It is attempt of * simultaneous connect with crossed SYNs. -@@ -6104,9 +6246,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, +@@ -6105,9 +6247,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tp->tcp_header_len = sizeof(struct tcphdr); } @@ -5282,7 +5330,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* RFC1323: The window in SYN & SYN/ACK segments is * never scaled. -@@ -6194,6 +6342,7 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) +@@ -6195,6 +6343,7 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) */ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) @@ -5290,7 +5338,7 @@ index 0ebba83dbe22..777c1301e433 100644 { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); -@@ -6236,6 +6385,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6237,6 +6386,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) tp->rx_opt.saw_tstamp = 0; tcp_mstamp_refresh(tp); queued = tcp_rcv_synsent_state_process(sk, skb, th); @@ -5307,7 +5355,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (queued >= 0) return queued; -@@ -6308,6 +6467,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6309,6 +6468,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) if (tp->rx_opt.tstamp_ok) tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; @@ -5316,7 +5364,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (!inet_csk(sk)->icsk_ca_ops->cong_control) tcp_update_pacing_rate(sk); -@@ -6317,9 +6478,34 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6318,9 +6479,34 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) tcp_initialize_rcv_mss(sk); tcp_fast_path_on(tp); @@ -5351,7 +5399,7 @@ index 0ebba83dbe22..777c1301e433 100644 int tmo; if (req) -@@ -6357,7 +6543,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6358,7 +6544,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) tmo = tcp_fin_time(sk); if (tmo > TCP_TIMEWAIT_LEN) { inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); @@ -5361,7 +5409,7 @@ index 0ebba83dbe22..777c1301e433 100644 /* Bad case. We could lose such FIN otherwise. * It is not a big problem, but it looks confusing * and not so rare event. We still can lose it now, -@@ -6366,7 +6553,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6367,7 +6554,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) */ inet_csk_reset_keepalive_timer(sk, tmo); } else { @@ -5370,7 +5418,7 @@ index 0ebba83dbe22..777c1301e433 100644 goto discard; } break; -@@ -6374,7 +6561,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6375,7 +6562,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) case TCP_CLOSING: if (tp->snd_una == tp->write_seq) { @@ -5379,7 +5427,7 @@ index 0ebba83dbe22..777c1301e433 100644 goto discard; } break; -@@ -6386,6 +6573,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6387,6 +6574,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) goto discard; } break; @@ -5389,7 +5437,7 @@ index 0ebba83dbe22..777c1301e433 100644 } /* step 6: check the URG bit */ -@@ -6407,7 +6597,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +@@ -6408,7 +6598,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) */ if (sk->sk_shutdown & RCV_SHUTDOWN) { if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && @@ -5399,7 +5447,7 @@ index 0ebba83dbe22..777c1301e433 100644 NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); tcp_reset(sk); return 1; -@@ -6509,6 +6700,8 @@ static void tcp_openreq_init(struct request_sock *req, +@@ -6510,6 +6701,8 @@ static void tcp_openreq_init(struct request_sock *req, ireq->wscale_ok = rx_opt->wscale_ok; ireq->acked = 0; ireq->ecn_ok = 0; @@ -5408,16 +5456,16 @@ index 0ebba83dbe22..777c1301e433 100644 ireq->ir_rmt_port = tcp_hdr(skb)->source; ireq->ir_num = ntohs(tcp_hdr(skb)->dest); ireq->ir_mark = inet_request_mark(sk, skb); -@@ -6639,12 +6832,17 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, +@@ -6640,11 +6833,17 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, /* TW buckets are converted to open requests without * limitations, they conserve resources and peer is * evidently real one. + * + * MPTCP: new subflows cannot be established in a stateless manner. */ -- if ((net->ipv4.sysctl_tcp_syncookies == 2 || -+ if (((!is_meta_sk(sk) && net->ipv4.sysctl_tcp_syncookies == 2) || - inet_csk_reqsk_queue_is_full(sk)) && !isn) { +- if ((syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) && !isn) { ++ if (((!is_meta_sk(sk) && syncookies == 2) || ++ inet_csk_reqsk_queue_is_full(sk)) && !isn) { want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name); if (!want_cookie) goto drop; @@ -5427,7 +5475,7 @@ index 0ebba83dbe22..777c1301e433 100644 } if (sk_acceptq_is_full(sk)) { -@@ -6661,8 +6860,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, +@@ -6662,8 +6861,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = af_ops->mss_clamp; tmp_opt.user_mss = tp->rx_opt.user_mss; @@ -5438,7 +5486,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); -@@ -6677,7 +6876,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, +@@ -6678,7 +6877,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, /* Note: tcp_v6_init_req() might override ir_iif for link locals */ inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); @@ -5448,7 +5496,7 @@ index 0ebba83dbe22..777c1301e433 100644 if (security_inet_conn_request(sk, skb, req)) goto drop_and_free; -@@ -6715,7 +6915,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, +@@ -6716,7 +6916,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, tcp_ecn_create_request(req, skb, sk, dst); if (want_cookie) { @@ -5457,7 +5505,7 @@ index 0ebba83dbe22..777c1301e433 100644 req->cookie_ts = tmp_opt.tstamp_ok; if (!tmp_opt.tstamp_ok) inet_rsk(req)->ecn_ok = 0; -@@ -6730,17 +6930,31 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, +@@ -6731,17 +6931,31 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); } if (fastopen_sk) { @@ -5492,7 +5540,7 @@ index 0ebba83dbe22..777c1301e433 100644 } else { tcp_rsk(req)->tfo_listener = false; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index b95e1a3487c8..c6f13e32fdd0 100644 +index a54505c29a5c..2247bee65783 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -62,6 +62,8 @@ @@ -5513,7 +5561,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; -@@ -430,7 +434,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -432,7 +436,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) struct inet_sock *inet; const int type = icmp_hdr(icmp_skb)->type; const int code = icmp_hdr(icmp_skb)->code; @@ -5522,7 +5570,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 struct sk_buff *skb; struct request_sock *fastopen; u32 seq, snd_una; -@@ -460,13 +464,19 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -462,13 +466,19 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) return 0; } @@ -5544,7 +5592,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); } -@@ -479,7 +489,6 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -481,7 +491,6 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) } icsk = inet_csk(sk); @@ -5552,7 +5600,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ fastopen = rcu_dereference(tp->fastopen_rsk); snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; -@@ -491,7 +500,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -493,7 +502,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) switch (type) { case ICMP_REDIRECT: @@ -5561,7 +5609,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 do_redirect(icmp_skb, sk); goto out; case ICMP_SOURCE_QUENCH: -@@ -513,11 +522,13 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -515,11 +524,13 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) goto out; WRITE_ONCE(tp->mtu_info, info); @@ -5576,7 +5624,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 } goto out; } -@@ -531,7 +542,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -533,7 +544,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) !icsk->icsk_backoff || fastopen) break; @@ -5585,7 +5633,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 break; skb = tcp_rtx_queue_head(sk); -@@ -555,7 +566,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -557,7 +568,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) } else { /* RTO revert clocked out retransmission. * Will retransmit now */ @@ -5594,7 +5642,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 } break; -@@ -575,7 +586,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -577,7 +588,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) if (fastopen && !fastopen->sk) break; @@ -5603,7 +5651,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 sk->sk_err = err; sk->sk_error_report(sk); -@@ -604,7 +615,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -606,7 +617,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) */ inet = inet_sk(sk); @@ -5612,7 +5660,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 sk->sk_err = err; sk->sk_error_report(sk); } else { /* Only an error on timeout */ -@@ -612,7 +623,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) +@@ -614,7 +625,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) } out: @@ -5621,7 +5669,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 sock_put(sk); return 0; } -@@ -648,7 +659,7 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) +@@ -650,7 +661,7 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) * Exception: precedence violation. We do not implement it in any case. */ @@ -5630,7 +5678,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { const struct tcphdr *th = tcp_hdr(skb); struct { -@@ -800,10 +811,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) +@@ -802,10 +813,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) */ static void tcp_v4_send_ack(const struct sock *sk, @@ -5643,7 +5691,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { const struct tcphdr *th = tcp_hdr(skb); struct { -@@ -812,6 +823,10 @@ static void tcp_v4_send_ack(const struct sock *sk, +@@ -814,6 +825,10 @@ static void tcp_v4_send_ack(const struct sock *sk, #ifdef CONFIG_TCP_MD5SIG + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif @@ -5654,7 +5702,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 ]; } rep; struct net *net = sock_net(sk); -@@ -858,6 +873,21 @@ static void tcp_v4_send_ack(const struct sock *sk, +@@ -860,6 +875,21 @@ static void tcp_v4_send_ack(const struct sock *sk, ip_hdr(skb)->daddr, &rep.th); } #endif @@ -5676,7 +5724,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 arg.flags = reply_flags; arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, /* XXX */ -@@ -889,28 +919,36 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) +@@ -891,28 +921,36 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) { struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); @@ -5718,7 +5766,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 tcp_sk(sk)->snd_nxt; /* RFC 7323 2.3 -@@ -919,7 +957,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +@@ -921,7 +959,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, * Rcv.Wind.Shift bits: */ tcp_v4_send_ack(sk, skb, seq, @@ -5727,7 +5775,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, req->ts_recent, -@@ -927,7 +965,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +@@ -929,7 +967,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, @@ -5736,7 +5784,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 } /* -@@ -935,11 +973,11 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +@@ -937,11 +975,11 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, * This still operates on a request_sock only, not on a big * socket. */ @@ -5753,7 +5801,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { const struct inet_request_sock *ireq = inet_rsk(req); struct flowi4 fl4; -@@ -969,7 +1007,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, +@@ -971,7 +1009,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, /* * IPv4 request_sock destructor. */ @@ -5762,7 +5810,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); } -@@ -1354,9 +1392,10 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk, +@@ -1356,9 +1394,10 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk, return false; } @@ -5776,7 +5824,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { struct inet_request_sock *ireq = inet_rsk(req); struct net *net = sock_net(sk_listener); -@@ -1364,6 +1403,8 @@ static void tcp_v4_init_req(struct request_sock *req, +@@ -1366,6 +1405,8 @@ static void tcp_v4_init_req(struct request_sock *req, sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); @@ -5785,7 +5833,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 } static struct dst_entry *tcp_v4_route_req(const struct sock *sk, -@@ -1531,7 +1572,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +@@ -1533,7 +1574,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, } EXPORT_SYMBOL(tcp_v4_syn_recv_sock); @@ -5794,7 +5842,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 { #ifdef CONFIG_SYN_COOKIES const struct tcphdr *th = tcp_hdr(skb); -@@ -1569,6 +1610,9 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) +@@ -1571,6 +1612,9 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { struct sock *rsk; @@ -5802,9 +5850,9 @@ index b95e1a3487c8..c6f13e32fdd0 100644 + return mptcp_v4_do_rcv(sk, skb); + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ - struct dst_entry *dst = sk->sk_rx_dst; + struct dst_entry *dst; -@@ -1814,6 +1858,10 @@ static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, +@@ -1819,6 +1863,10 @@ static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + skb->len - th->doff * 4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); @@ -5815,7 +5863,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); TCP_SKB_CB(skb)->tcp_tw_isn = 0; TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); -@@ -1833,8 +1881,8 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -1838,8 +1886,8 @@ int tcp_v4_rcv(struct sk_buff *skb) int sdif = inet_sdif(skb); const struct iphdr *iph; const struct tcphdr *th; @@ -5825,7 +5873,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 int ret; if (skb->pkt_type != PACKET_HOST) -@@ -1888,7 +1936,11 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -1893,7 +1941,11 @@ int tcp_v4_rcv(struct sk_buff *skb) reqsk_put(req); goto csum_error; } @@ -5838,7 +5886,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; } -@@ -1897,6 +1949,7 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -1902,6 +1954,7 @@ int tcp_v4_rcv(struct sk_buff *skb) */ sock_hold(sk); refcounted = true; @@ -5846,7 +5894,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 nsk = NULL; if (!tcp_filter(sk, skb)) { th = (const struct tcphdr *)skb->data; -@@ -1957,19 +2010,28 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -1962,19 +2015,28 @@ int tcp_v4_rcv(struct sk_buff *skb) sk_incoming_cpu_update(sk); @@ -5879,7 +5927,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 if (skb_to_free) __kfree_skb(skb_to_free); -@@ -1985,6 +2047,19 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -1990,6 +2052,19 @@ int tcp_v4_rcv(struct sk_buff *skb) tcp_v4_fill_cb(skb, iph, th); @@ -5899,7 +5947,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 if (tcp_checksum_complete(skb)) { csum_error: __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); -@@ -2033,6 +2108,18 @@ int tcp_v4_rcv(struct sk_buff *skb) +@@ -2038,6 +2113,18 @@ int tcp_v4_rcv(struct sk_buff *skb) refcounted = false; goto process; } @@ -5918,7 +5966,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 } /* to ACK */ /* fall through */ -@@ -2102,7 +2189,12 @@ static int tcp_v4_init_sock(struct sock *sk) +@@ -2107,7 +2194,12 @@ static int tcp_v4_init_sock(struct sock *sk) tcp_init_sock(sk); @@ -5932,7 +5980,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 #ifdef CONFIG_TCP_MD5SIG tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; -@@ -2121,6 +2213,11 @@ void tcp_v4_destroy_sock(struct sock *sk) +@@ -2126,6 +2218,11 @@ void tcp_v4_destroy_sock(struct sock *sk) tcp_cleanup_congestion_control(sk); @@ -5944,7 +5992,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 tcp_cleanup_ulp(sk); /* Cleanup up the write buffer. */ -@@ -2626,6 +2723,11 @@ struct proto tcp_prot = { +@@ -2631,6 +2728,11 @@ struct proto tcp_prot = { .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp_sock), @@ -5956,7 +6004,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 .slab_flags = SLAB_TYPESAFE_BY_RCU, .twsk_prot = &tcp_timewait_sock_ops, .rsk_prot = &tcp_request_sock_ops, -@@ -2636,6 +2738,9 @@ struct proto tcp_prot = { +@@ -2641,6 +2743,9 @@ struct proto tcp_prot = { .compat_getsockopt = compat_tcp_getsockopt, #endif .diag_destroy = tcp_abort, @@ -5967,7 +6015,7 @@ index b95e1a3487c8..c6f13e32fdd0 100644 EXPORT_SYMBOL(tcp_prot); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c -index 324f43fadb37..9bcd0b8aa0af 100644 +index 324f43fadb37..4f87543c4d5f 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -19,11 +19,13 @@ @@ -6159,7 +6207,7 @@ index 324f43fadb37..9bcd0b8aa0af 100644 if (!tcp_oow_rate_limited(sock_net(sk), skb, LINUX_MIB_TCPACKSKIPPEDSYNRECV, &tcp_rsk(req)->last_oow_ack_time) && -@@ -767,17 +826,40 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, +@@ -767,17 +826,43 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * ESTABLISHED STATE. If it will be dropped after * socket is created, wait for troubles. */ @@ -6184,6 +6232,9 @@ index 324f43fadb37..9bcd0b8aa0af 100644 + return mptcp_check_req_child(sk, child, req, skb, &mopt); + } + ++ /* Fallback to regular TCP */ ++ tcp_sk(child)->mpc = 0; ++ + if (meta_locked) + bh_unlock_sock(sk); + @@ -6200,7 +6251,7 @@ index 324f43fadb37..9bcd0b8aa0af 100644 if (!sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow) { inet_rsk(req)->acked = 1; return NULL; -@@ -823,12 +905,13 @@ int tcp_child_process(struct sock *parent, struct sock *child, +@@ -823,12 +908,13 @@ int tcp_child_process(struct sock *parent, struct sock *child, { int ret = 0; int state = child->sk_state; @@ -6215,7 +6266,7 @@ index 324f43fadb37..9bcd0b8aa0af 100644 ret = tcp_rcv_state_process(child, skb); /* Wakeup parent, send SIGIO */ if (state == TCP_SYN_RECV && child->sk_state != state) -@@ -838,10 +921,14 @@ int tcp_child_process(struct sock *parent, struct sock *child, +@@ -838,10 +924,14 @@ int tcp_child_process(struct sock *parent, struct sock *child, * in main socket hash table and lock on listening * socket does not protect us more. */ @@ -6232,7 +6283,7 @@ index 324f43fadb37..9bcd0b8aa0af 100644 return ret; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c -index c37028af0db0..08c79424fbc3 100644 +index b4a9f6948cb5..e2af0626147b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -37,6 +37,12 @@ @@ -6565,7 +6616,7 @@ index c37028af0db0..08c79424fbc3 100644 /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. * As additional protections, we do not touch cwnd in retransmission phases, -@@ -1684,8 +1727,11 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) +@@ -1689,8 +1732,11 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) * 2) not cwnd limited (this else condition) * 3) no more data to send (tcp_write_queue_empty()) * 4) application is hitting buffer limit (SOCK_NOSPACE) @@ -6577,7 +6628,7 @@ index c37028af0db0..08c79424fbc3 100644 test_bit(SOCK_NOSPACE, &sk->sk_socket->flags) && (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) tcp_chrono_start(sk, TCP_CHRONO_SNDBUF_LIMITED); -@@ -1707,8 +1753,8 @@ static bool tcp_minshall_check(const struct tcp_sock *tp) +@@ -1712,8 +1758,8 @@ static bool tcp_minshall_check(const struct tcp_sock *tp) * But we can avoid doing the divide again given we already have * skb_pcount = skb->len / mss_now */ @@ -6588,7 +6639,7 @@ index c37028af0db0..08c79424fbc3 100644 { if (skb->len < tcp_skb_pcount(skb) * mss_now) tp->snd_sml = TCP_SKB_CB(skb)->end_seq; -@@ -1754,7 +1800,7 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, +@@ -1759,7 +1805,7 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, /* Return the number of segments we want in the skb we are transmitting. * See if congestion control module wants to decide; otherwise, autosize. */ @@ -6597,7 +6648,7 @@ index c37028af0db0..08c79424fbc3 100644 { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; u32 min_tso, tso_segs; -@@ -1768,11 +1814,11 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) +@@ -1773,11 +1819,11 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) } /* Returns the portion of skb which can be sent right away */ @@ -6614,7 +6665,7 @@ index c37028af0db0..08c79424fbc3 100644 { const struct tcp_sock *tp = tcp_sk(sk); u32 partial, needed, window, max_len; -@@ -1802,13 +1848,14 @@ static unsigned int tcp_mss_split_point(const struct sock *sk, +@@ -1807,13 +1853,14 @@ static unsigned int tcp_mss_split_point(const struct sock *sk, /* Can at least one segment of SKB be sent right now, according to the * congestion window rules? If so, return how many segments are allowed. */ @@ -6632,7 +6683,7 @@ index c37028af0db0..08c79424fbc3 100644 tcp_skb_pcount(skb) == 1) return 1; -@@ -1823,12 +1870,13 @@ static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, +@@ -1828,12 +1875,13 @@ static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, halfcwnd = max(cwnd >> 1, 1U); return min(halfcwnd, cwnd - in_flight); } @@ -6647,7 +6698,7 @@ index c37028af0db0..08c79424fbc3 100644 { int tso_segs = tcp_skb_pcount(skb); -@@ -1843,8 +1891,8 @@ static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) +@@ -1848,8 +1896,8 @@ static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) /* Return true if the Nagle test allows this packet to be * sent now. */ @@ -6658,7 +6709,7 @@ index c37028af0db0..08c79424fbc3 100644 { /* Nagle rule does not apply to frames, which sit in the middle of the * write_queue (they have no chances to get new data). -@@ -1856,7 +1904,8 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf +@@ -1861,7 +1909,8 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf return true; /* Don't use the nagle rule for urgent data (or for the final FIN). */ @@ -6668,7 +6719,7 @@ index c37028af0db0..08c79424fbc3 100644 return true; if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) -@@ -1866,9 +1915,8 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf +@@ -1871,9 +1920,8 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf } /* Does at least the first segment of SKB fit into the send window? */ @@ -6680,7 +6731,7 @@ index c37028af0db0..08c79424fbc3 100644 { u32 end_seq = TCP_SKB_CB(skb)->end_seq; -@@ -1877,6 +1925,7 @@ static bool tcp_snd_wnd_test(const struct tcp_sock *tp, +@@ -1882,6 +1930,7 @@ static bool tcp_snd_wnd_test(const struct tcp_sock *tp, return !after(end_seq, tcp_wnd_end(tp)); } @@ -6688,7 +6739,7 @@ index c37028af0db0..08c79424fbc3 100644 /* Trim TSO SKB to LEN bytes, put the remaining data into a new packet * which is put after SKB on the list. It is very much like -@@ -1912,6 +1961,12 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, +@@ -1917,6 +1966,12 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; @@ -6701,7 +6752,7 @@ index c37028af0db0..08c79424fbc3 100644 /* PSH and FIN should only be set in the second packet. */ flags = TCP_SKB_CB(skb)->tcp_flags; TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH); -@@ -2035,7 +2090,8 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb, +@@ -2040,7 +2095,8 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb, /* If this packet won't get more data, do not wait. */ if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) || @@ -6711,7 +6762,7 @@ index c37028af0db0..08c79424fbc3 100644 goto send_now; return true; -@@ -2368,7 +2424,7 @@ void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type) +@@ -2373,7 +2429,7 @@ void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type) * Returns true, if no segments are in flight and we have queued segments, * but cannot send anything now because of SWS or another problem. */ @@ -6720,7 +6771,7 @@ index c37028af0db0..08c79424fbc3 100644 int push_one, gfp_t gfp) { struct tcp_sock *tp = tcp_sk(sk); -@@ -2382,7 +2438,12 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, +@@ -2387,7 +2443,12 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, sent_pkts = 0; tcp_mstamp_refresh(tp); @@ -6734,7 +6785,7 @@ index c37028af0db0..08c79424fbc3 100644 /* Do MTU probing. */ result = tcp_mtu_probe(sk); if (!result) { -@@ -2578,7 +2639,7 @@ void tcp_send_loss_probe(struct sock *sk) +@@ -2583,7 +2644,7 @@ void tcp_send_loss_probe(struct sock *sk) skb = tcp_send_head(sk); if (skb && tcp_snd_wnd_test(tp, skb, mss)) { pcount = tp->packets_out; @@ -6743,7 +6794,7 @@ index c37028af0db0..08c79424fbc3 100644 if (tp->packets_out > pcount) goto probe_sent; goto rearm_timer; -@@ -2640,8 +2701,8 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, +@@ -2645,8 +2706,8 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, if (unlikely(sk->sk_state == TCP_CLOSE)) return; @@ -6754,7 +6805,7 @@ index c37028af0db0..08c79424fbc3 100644 tcp_check_probe_timer(sk); } -@@ -2654,7 +2715,8 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now) +@@ -2659,7 +2720,8 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now) BUG_ON(!skb || skb->len < mss_now); @@ -6764,7 +6815,7 @@ index c37028af0db0..08c79424fbc3 100644 } /* This function returns the amount that we can raise the -@@ -2876,6 +2938,10 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, +@@ -2881,6 +2943,10 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) return; @@ -6775,7 +6826,7 @@ index c37028af0db0..08c79424fbc3 100644 skb_rbtree_walk_from_safe(skb, tmp) { if (!tcp_can_collapse(sk, skb)) break; -@@ -3367,7 +3433,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, +@@ -3372,7 +3438,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(min(req->rsk_rcv_wnd, 65535U)); @@ -6784,7 +6835,7 @@ index c37028af0db0..08c79424fbc3 100644 th->doff = (tcp_header_size >> 2); __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); -@@ -3449,13 +3515,13 @@ static void tcp_connect_init(struct sock *sk) +@@ -3454,13 +3520,13 @@ static void tcp_connect_init(struct sock *sk) if (rcv_wnd == 0) rcv_wnd = dst_metric(dst, RTAX_INITRWND); @@ -6792,7 +6843,7 @@ index c37028af0db0..08c79424fbc3 100644 - tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), - &tp->rcv_wnd, - &tp->window_clamp, -- sock_net(sk)->ipv4.sysctl_tcp_window_scaling, +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling), - &rcv_wscale, - rcv_wnd); + tp->ops->select_initial_window(sk, tcp_full_space(sk), @@ -6805,7 +6856,7 @@ index c37028af0db0..08c79424fbc3 100644 tp->rx_opt.rcv_wscale = rcv_wscale; tp->rcv_ssthresh = tp->rcv_wnd; -@@ -3475,11 +3541,43 @@ static void tcp_connect_init(struct sock *sk) +@@ -3480,11 +3546,43 @@ static void tcp_connect_init(struct sock *sk) else tp->rcv_tstamp = tcp_jiffies32; tp->rcv_wup = tp->rcv_nxt; @@ -6849,7 +6900,7 @@ index c37028af0db0..08c79424fbc3 100644 } static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) -@@ -3746,6 +3844,7 @@ void tcp_send_ack(struct sock *sk) +@@ -3751,6 +3849,7 @@ void tcp_send_ack(struct sock *sk) { __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } @@ -6857,7 +6908,7 @@ index c37028af0db0..08c79424fbc3 100644 /* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. -@@ -3758,7 +3857,7 @@ void tcp_send_ack(struct sock *sk) +@@ -3763,7 +3862,7 @@ void tcp_send_ack(struct sock *sk) * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is * out-of-date with SND.UNA-1 to probe window. */ @@ -6866,7 +6917,7 @@ index c37028af0db0..08c79424fbc3 100644 { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; -@@ -3845,7 +3944,7 @@ void tcp_send_probe0(struct sock *sk) +@@ -3850,7 +3949,7 @@ void tcp_send_probe0(struct sock *sk) unsigned long timeout; int err; @@ -7153,7 +7204,7 @@ index 56f396ecc26b..768a8717dc10 100644 struct inet_sock *inet; struct ipv6_pinfo *np; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c -index 5352c7e68c42..534a9d2e4858 100644 +index 1d7fad8269e6..cae39519c26b 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -44,6 +44,8 @@ @@ -7165,7 +7216,7 @@ index 5352c7e68c42..534a9d2e4858 100644 #include #include #include -@@ -221,7 +223,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, +@@ -227,7 +229,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sock_prot_inuse_add(net, &tcp_prot, 1); local_bh_enable(); sk->sk_prot = &tcp_prot; @@ -7179,7 +7230,7 @@ index 5352c7e68c42..534a9d2e4858 100644 sk->sk_socket->ops = &inet_stream_ops; sk->sk_family = PF_INET; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); -@@ -345,6 +352,17 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, +@@ -351,6 +358,17 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (val == -1) val = 0; np->tclass = val; @@ -7290,7 +7341,7 @@ index 7e5550546594..248255d2883a 100644 return ret; out_free: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c -index 063898cae3e5..7f3804814657 100644 +index e84b79357b2f..f6334e6db1f7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -58,6 +58,8 @@ @@ -7373,7 +7424,7 @@ index 063898cae3e5..7f3804814657 100644 sk->sk_backlog_rcv = tcp_v6_do_rcv; #ifdef CONFIG_TCP_MD5SIG tp->af_specific = &tcp_sock_ipv6_specific; -@@ -340,7 +345,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, +@@ -342,7 +347,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, return err; } @@ -7382,7 +7433,7 @@ index 063898cae3e5..7f3804814657 100644 { struct dst_entry *dst; u32 mtu; -@@ -376,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -378,7 +383,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct ipv6_pinfo *np; struct tcp_sock *tp; __u32 seq, snd_una; @@ -7391,7 +7442,7 @@ index 063898cae3e5..7f3804814657 100644 bool fatal; int err; -@@ -402,8 +407,14 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -404,8 +409,14 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return 0; } @@ -7408,7 +7459,7 @@ index 063898cae3e5..7f3804814657 100644 __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); if (sk->sk_state == TCP_CLOSE) -@@ -414,7 +425,6 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -416,7 +427,6 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, goto out; } @@ -7416,7 +7467,7 @@ index 063898cae3e5..7f3804814657 100644 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ fastopen = rcu_dereference(tp->fastopen_rsk); snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; -@@ -427,7 +437,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -429,7 +439,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, np = tcp_inet6_sk(sk); if (type == NDISC_REDIRECT) { @@ -7425,7 +7476,7 @@ index 063898cae3e5..7f3804814657 100644 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); if (dst) -@@ -454,11 +464,15 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -456,11 +466,15 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, WRITE_ONCE(tp->mtu_info, mtu); @@ -7445,7 +7496,7 @@ index 063898cae3e5..7f3804814657 100644 goto out; } -@@ -473,7 +487,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -475,7 +489,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (fastopen && !fastopen->sk) break; @@ -7454,7 +7505,7 @@ index 063898cae3e5..7f3804814657 100644 sk->sk_err = err; sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ -@@ -483,14 +497,14 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +@@ -485,14 +499,14 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, goto out; } @@ -7471,7 +7522,7 @@ index 063898cae3e5..7f3804814657 100644 sock_put(sk); return 0; } -@@ -538,8 +552,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, +@@ -540,8 +554,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, return err; } @@ -7481,7 +7532,7 @@ index 063898cae3e5..7f3804814657 100644 { kfree(inet_rsk(req)->ipv6_opt); kfree_skb(inet_rsk(req)->pktopts); -@@ -757,9 +770,10 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk, +@@ -759,9 +772,10 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk, return false; } @@ -7495,7 +7546,7 @@ index 063898cae3e5..7f3804814657 100644 { bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); struct inet_request_sock *ireq = inet_rsk(req); -@@ -781,6 +795,8 @@ static void tcp_v6_init_req(struct request_sock *req, +@@ -783,6 +797,8 @@ static void tcp_v6_init_req(struct request_sock *req, refcount_inc(&skb->users); ireq->pktopts = skb; } @@ -7504,7 +7555,7 @@ index 063898cae3e5..7f3804814657 100644 } static struct dst_entry *tcp_v6_route_req(const struct sock *sk, -@@ -818,9 +834,9 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = { +@@ -820,9 +836,9 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = { }; static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, @@ -7516,7 +7567,7 @@ index 063898cae3e5..7f3804814657 100644 { const struct tcphdr *th = tcp_hdr(skb); struct tcphdr *t1; -@@ -839,7 +855,10 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 +@@ -841,7 +857,10 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 if (key) tot_len += TCPOLEN_MD5SIG_ALIGNED; #endif @@ -7528,7 +7579,7 @@ index 063898cae3e5..7f3804814657 100644 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (!buff) -@@ -877,6 +896,17 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 +@@ -879,6 +898,17 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 tcp_v6_md5_hash_hdr((__u8 *)topt, key, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, t1); @@ -7546,7 +7597,7 @@ index 063898cae3e5..7f3804814657 100644 } #endif -@@ -935,7 +965,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 +@@ -937,7 +967,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 kfree_skb(buff); } @@ -7555,7 +7606,7 @@ index 063898cae3e5..7f3804814657 100644 { const struct tcphdr *th = tcp_hdr(skb); struct ipv6hdr *ipv6h = ipv6_hdr(skb); -@@ -1020,8 +1050,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) +@@ -1022,8 +1052,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) label = ip6_flowlabel(ipv6h); } @@ -7566,7 +7617,7 @@ index 063898cae3e5..7f3804814657 100644 #ifdef CONFIG_TCP_MD5SIG out: -@@ -1030,30 +1060,37 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) +@@ -1032,30 +1062,37 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) } static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, @@ -7611,7 +7662,7 @@ index 063898cae3e5..7f3804814657 100644 { /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV * sk->sk_state == TCP_SYN_RECV -> for Fast Open. -@@ -1063,18 +1100,18 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, +@@ -1065,18 +1102,18 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, * exception of segments, MUST be right-shifted by * Rcv.Wind.Shift bits: */ @@ -7634,7 +7685,7 @@ index 063898cae3e5..7f3804814657 100644 { #ifdef CONFIG_SYN_COOKIES const struct tcphdr *th = tcp_hdr(skb); -@@ -1100,7 +1137,7 @@ u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph, +@@ -1102,7 +1139,7 @@ u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph, return mss; } @@ -7643,7 +7694,7 @@ index 063898cae3e5..7f3804814657 100644 { if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_conn_request(sk, skb); -@@ -1131,11 +1168,11 @@ static void tcp_v6_restore_cb(struct sk_buff *skb) +@@ -1133,11 +1170,11 @@ static void tcp_v6_restore_cb(struct sk_buff *skb) sizeof(struct inet6_skb_parm)); } @@ -7660,7 +7711,7 @@ index 063898cae3e5..7f3804814657 100644 { struct inet_request_sock *ireq; struct ipv6_pinfo *newnp; -@@ -1171,7 +1208,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1173,7 +1210,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * newnp->saddr = newsk->sk_v6_rcv_saddr; @@ -7669,7 +7720,7 @@ index 063898cae3e5..7f3804814657 100644 + /* We must check on the request-socket because the listener + * socket's flag may have been changed halfway through. + */ -+ if (!inet_rsk(req)->saw_mpc) ++ if (inet_rsk(req)->saw_mpc) + inet_csk(newsk)->icsk_af_ops = &mptcp_v6_mapped; + else +#endif @@ -7677,7 +7728,7 @@ index 063898cae3e5..7f3804814657 100644 newsk->sk_backlog_rcv = tcp_v4_do_rcv; #ifdef CONFIG_TCP_MD5SIG newtp->af_specific = &tcp_sock_ipv6_mapped_specific; -@@ -1218,6 +1263,14 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1220,6 +1265,14 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * if (!newsk) goto out_nonewsk; @@ -7692,7 +7743,7 @@ index 063898cae3e5..7f3804814657 100644 /* * No need to charge this sock to the relevant IPv6 refcnt debug socks * count here, tcp_create_openreq_child now does this for us, see the -@@ -1355,7 +1408,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1357,7 +1410,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * * This is because we cannot sleep with the original spinlock * held. */ @@ -7701,7 +7752,7 @@ index 063898cae3e5..7f3804814657 100644 { struct ipv6_pinfo *np = tcp_inet6_sk(sk); struct sk_buff *opt_skb = NULL; -@@ -1372,6 +1425,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) +@@ -1374,6 +1427,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_do_rcv(sk, skb); @@ -7711,7 +7762,7 @@ index 063898cae3e5..7f3804814657 100644 /* * socket locking is here for SMP purposes as backlog rcv * is currently called with bh processing disabled. -@@ -1499,6 +1555,10 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, +@@ -1504,6 +1560,10 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); @@ -7722,7 +7773,7 @@ index 063898cae3e5..7f3804814657 100644 TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); TCP_SKB_CB(skb)->tcp_tw_isn = 0; TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); -@@ -1513,8 +1573,8 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) +@@ -1518,8 +1578,8 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) int sdif = inet6_sdif(skb); const struct tcphdr *th; const struct ipv6hdr *hdr; @@ -7732,7 +7783,7 @@ index 063898cae3e5..7f3804814657 100644 int ret; struct net *net = dev_net(skb->dev); -@@ -1568,12 +1628,17 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) +@@ -1573,12 +1633,17 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) reqsk_put(req); goto csum_error; } @@ -7751,7 +7802,7 @@ index 063898cae3e5..7f3804814657 100644 nsk = NULL; if (!tcp_filter(sk, skb)) { th = (const struct tcphdr *)skb->data; -@@ -1632,19 +1697,28 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) +@@ -1637,19 +1702,28 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) sk_incoming_cpu_update(sk); @@ -7784,7 +7835,7 @@ index 063898cae3e5..7f3804814657 100644 if (skb_to_free) __kfree_skb(skb_to_free); put_and_return: -@@ -1658,6 +1732,19 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) +@@ -1663,6 +1737,19 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) tcp_v6_fill_cb(skb, hdr, th); @@ -7804,7 +7855,7 @@ index 063898cae3e5..7f3804814657 100644 if (tcp_checksum_complete(skb)) { csum_error: __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); -@@ -1710,6 +1797,18 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) +@@ -1715,6 +1802,18 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) refcounted = false; goto process; } @@ -7823,7 +7874,7 @@ index 063898cae3e5..7f3804814657 100644 } /* to ACK */ /* fall through */ -@@ -1764,13 +1863,13 @@ INDIRECT_CALLABLE_SCOPE void tcp_v6_early_demux(struct sk_buff *skb) +@@ -1769,13 +1868,13 @@ void tcp_v6_early_demux(struct sk_buff *skb) } } @@ -7839,7 +7890,7 @@ index 063898cae3e5..7f3804814657 100644 .queue_xmit = inet6_csk_xmit, .send_check = tcp_v6_send_check, .rebuild_header = inet6_sk_rebuild_header, -@@ -1801,7 +1900,7 @@ INDIRECT_CALLABLE_SCOPE void tcp_v6_early_demux(struct sk_buff *skb) +@@ -1806,7 +1905,7 @@ void tcp_v6_early_demux(struct sk_buff *skb) /* * TCP over IPv4 via INET6 API */ @@ -7848,7 +7899,7 @@ index 063898cae3e5..7f3804814657 100644 .queue_xmit = ip_queue_xmit, .send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, -@@ -1837,7 +1936,12 @@ static int tcp_v6_init_sock(struct sock *sk) +@@ -1842,7 +1941,12 @@ static int tcp_v6_init_sock(struct sock *sk) tcp_init_sock(sk); @@ -7862,7 +7913,7 @@ index 063898cae3e5..7f3804814657 100644 #ifdef CONFIG_TCP_MD5SIG tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; -@@ -1846,7 +1950,7 @@ static int tcp_v6_init_sock(struct sock *sk) +@@ -1851,7 +1955,7 @@ static int tcp_v6_init_sock(struct sock *sk) return 0; } @@ -7871,7 +7922,7 @@ index 063898cae3e5..7f3804814657 100644 { tcp_v4_destroy_sock(sk); inet6_destroy_sock(sk); -@@ -2069,6 +2173,11 @@ struct proto tcpv6_prot = { +@@ -2074,6 +2178,11 @@ struct proto tcpv6_prot = { .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp6_sock), @@ -7883,7 +7934,7 @@ index 063898cae3e5..7f3804814657 100644 .slab_flags = SLAB_TYPESAFE_BY_RCU, .twsk_prot = &tcp6_timewait_sock_ops, .rsk_prot = &tcp6_request_sock_ops, -@@ -2079,6 +2188,9 @@ struct proto tcpv6_prot = { +@@ -2084,6 +2193,9 @@ struct proto tcpv6_prot = { .compat_getsockopt = compat_tcp_getsockopt, #endif .diag_destroy = tcp_abort, @@ -7892,13 +7943,13 @@ index 063898cae3e5..7f3804814657 100644 +#endif }; - /* thinking of making this const? Don't. + static const struct inet6_protocol tcpv6_protocol = { diff --git a/net/mptcp/Kconfig b/net/mptcp/Kconfig new file mode 100644 -index 000000000000..c3d2053a61b2 +index 000000000000..e8fbf85da412 --- /dev/null +++ b/net/mptcp/Kconfig -@@ -0,0 +1,162 @@ +@@ -0,0 +1,176 @@ +# +# MPTCP configuration +# @@ -8043,6 +8094,18 @@ index 000000000000..c3d2053a61b2 + This is the redundant scheduler, sending packets redundantly over + all the subflows. + ++ config DEFAULT_BLEST ++ bool "BLEST" if MPTCP_BLEST=y ++ ---help--- ++ This is the BLEST scheduler, sending packets following the ++ BLocking ESTimation-based algorithm. ++ ++ config DEFAULT_ECF ++ bool "ECF" if MPTCP_ECF=y ++ ---help--- ++ This is the ECF scheduler, sending packets following the ++ Earliest Completion First algorithm. ++ +endchoice +endif + @@ -8052,6 +8115,8 @@ index 000000000000..c3d2053a61b2 + default "default" if DEFAULT_SCHEDULER + default "roundrobin" if DEFAULT_ROUNDROBIN + default "redundant" if DEFAULT_REDUNDANT ++ default "BLEST" if DEFAULT_BLEST ++ default "ECF" if DEFAULT_ECF + default "default" + +config MPTCP_DEBUG_LOCK @@ -9618,10 +9683,10 @@ index 000000000000..9eb7628053f6 +MODULE_VERSION("0.1"); diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c new file mode 100644 -index 000000000000..ae45253219bd +index 000000000000..4dd1ed2f2b0d --- /dev/null +++ b/net/mptcp/mptcp_ctrl.c -@@ -0,0 +1,3608 @@ +@@ -0,0 +1,3607 @@ +/* + * MPTCP implementation - MPTCP-control + * @@ -12041,6 +12106,8 @@ index 000000000000..ae45253219bd + mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { + struct sock *subsk = mptcp_to_sock(mptcp); + ++ BUG_ON(spin_is_locked(&subsk->sk_lock.slock)); ++ + tcp_sk(subsk)->tcp_disconnect = 1; + + meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); @@ -12152,12 +12219,14 @@ index 000000000000..ae45253219bd + * must still remove it. + */ + MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); -+ mptcp_reqsk_remove_tk(req); + return 1; + } + + /* mopt can be NULL when coming from FAST-OPEN */ -+ if (mopt && mopt->saw_mpc && mtreq->mptcp_ver == MPTCP_VERSION_1) { ++ if (mopt && mtreq->mptcp_ver == MPTCP_VERSION_1) { ++ if (!mopt->saw_mpc) ++ return 1; ++ + mtreq->mptcp_rem_key = mopt->mptcp_sender_key; + mtreq->rem_key_set = 1; + } @@ -12186,11 +12255,6 @@ index 000000000000..ae45253219bd + mpcb->dss_csum = mtreq->dss_csum; + mpcb->server_side = 1; + -+ /* Needs to be done here additionally, because when accepting a -+ * new connection we pass by __reqsk_free and not reqsk_free. -+ */ -+ mptcp_reqsk_remove_tk(req); -+ + return 0; +} + @@ -13433,10 +13497,10 @@ index 000000000000..6b976b2b0c72 +MODULE_VERSION("0.95"); diff --git a/net/mptcp/mptcp_fullmesh.c b/net/mptcp/mptcp_fullmesh.c new file mode 100644 -index 000000000000..ef2c15cbbeaa +index 000000000000..440d90f42d68 --- /dev/null +++ b/net/mptcp/mptcp_fullmesh.c -@@ -0,0 +1,1949 @@ +@@ -0,0 +1,1902 @@ +#include +#include + @@ -14791,8 +14855,10 @@ index 000000000000..ef2c15cbbeaa + else + fmp->announced_addrs_v6 |= (1 << index); + -+ for (i = fmp->add_addr; i && fmp->add_addr; i--) -+ tcp_send_ack(mpcb->master_sk); ++ /* Only version 0 can send ADD_ADDR right at the beginning */ ++ if (mpcb->mptcp_ver == MPTCP_VERSION_0) ++ for (i = fmp->add_addr; i && fmp->add_addr; i--) ++ tcp_send_ack(mpcb->master_sk); + + if (master_tp->mptcp->send_mp_prio) + tcp_send_ack(mpcb->master_sk); @@ -15028,39 +15094,17 @@ index 000000000000..ef2c15cbbeaa + + /* IPv4 */ + unannouncedv4 = (~fmp->announced_addrs_v4) & mptcp_local->loc4_bits; -+ if (unannouncedv4 && -+ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) || -+ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1))) { ++ if (unannouncedv4 && mptcp_options_add_addr4_enough_space(mpcb, *size)) { + int ind = mptcp_find_free_index(~unannouncedv4); + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_ADD_ADDR; -+ opts->add_addr4.addr_id = mptcp_local->locaddr4[ind].loc4_id; -+ opts->add_addr4.addr = mptcp_local->locaddr4[ind].addr; -+ opts->add_addr_v4 = 1; -+ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { -+ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; -+ -+ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, -+ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, -+ 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, -+ 4, (u8 *)&opts->add_addr4.addr.s_addr); -+ opts->add_addr4.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; -+ } ++ *size += mptcp_options_fill_add_addr4(mpcb, opts, ++ &mptcp_local->locaddr4[ind]); + + if (skb) { + fmp->announced_addrs_v4 |= (1 << ind); + fmp->add_addr--; + } + -+ if (mpcb->mptcp_ver < MPTCP_VERSION_1) -+ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; -+ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) -+ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; -+ -+ mpcb->add_addr_signal++; + goto skip_ipv6; + } + @@ -15069,38 +15113,16 @@ index 000000000000..ef2c15cbbeaa +skip_ipv4: + /* IPv6 */ + unannouncedv6 = (~fmp->announced_addrs_v6) & mptcp_local->loc6_bits; -+ if (unannouncedv6 && -+ ((mpcb->mptcp_ver == MPTCP_VERSION_0 && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) || -+ (mpcb->mptcp_ver >= MPTCP_VERSION_1 && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1))) { ++ if (unannouncedv6 && mptcp_options_add_addr6_enough_space(mpcb, *size)) { + int ind = mptcp_find_free_index(~unannouncedv6); + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_ADD_ADDR; -+ opts->add_addr6.addr_id = mptcp_local->locaddr6[ind].loc6_id; -+ opts->add_addr6.addr = mptcp_local->locaddr6[ind].addr; -+ opts->add_addr_v6 = 1; -+ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { -+ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; -+ -+ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, -+ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, -+ 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, -+ 16, (u8 *)&opts->add_addr6.addr.s6_addr); -+ opts->add_addr6.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; -+ } ++ *size += mptcp_options_fill_add_addr6(mpcb, opts, ++ &mptcp_local->locaddr6[ind]); + + if (skb) { + fmp->announced_addrs_v6 |= (1 << ind); + fmp->add_addr--; + } -+ if (mpcb->mptcp_ver < MPTCP_VERSION_1) -+ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; -+ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) -+ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; -+ -+ mpcb->add_addr_signal++; + } + +skip_ipv6: @@ -15110,21 +15132,16 @@ index 000000000000..ef2c15cbbeaa + fmp->add_addr--; + +remove_addr: -+ if (likely(!fmp->remove_addrs)) -+ goto exit; ++ if (unlikely(fmp->remove_addrs) && ++ mptcp_options_rm_addr_enough_space(fmp->remove_addrs, ++ &remove_addr_len, *size)) { ++ *size += mptcp_options_fill_rm_addr(opts, fmp->remove_addrs, ++ remove_addr_len); + -+ remove_addr_len = mptcp_sub_len_remove_addr_align(fmp->remove_addrs); -+ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) -+ goto exit; ++ if (skb) ++ fmp->remove_addrs = 0; ++ } + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_REMOVE_ADDR; -+ opts->remove_addrs = fmp->remove_addrs; -+ *size += remove_addr_len; -+ if (skb) -+ fmp->remove_addrs = 0; -+ -+exit: + mpcb->addr_signal = !!(fmp->add_addr || fmp->remove_addrs); +} + @@ -15388,7 +15405,7 @@ index 000000000000..ef2c15cbbeaa +MODULE_VERSION("0.88"); diff --git a/net/mptcp/mptcp_input.c b/net/mptcp/mptcp_input.c new file mode 100644 -index 000000000000..41a511b3ef63 +index 000000000000..d5c1e8cec703 --- /dev/null +++ b/net/mptcp/mptcp_input.c @@ -0,0 +1,2656 @@ @@ -17102,7 +17119,7 @@ index 000000000000..41a511b3ef63 + * this becomes our data_ack. + */ + if (after(meta_tp->snd_una, tp->mptcp->last_end_data_seq - (tp->snd_nxt - tp->snd_una))) { -+ /* Remmeber that meta snd_una is ahead of the game */ ++ /* Remember that meta snd_una is ahead of the game */ + mpcb->infinite_send_una_ahead = 1; + tp->mptcp->rx_opt.data_ack = meta_tp->snd_una; + } else { @@ -19157,10 +19174,10 @@ index 000000000000..cf019990447c +MODULE_VERSION("0.88"); diff --git a/net/mptcp/mptcp_netlink.c b/net/mptcp/mptcp_netlink.c new file mode 100644 -index 000000000000..dd44a87a2971 +index 000000000000..c59f5d0f3547 --- /dev/null +++ b/net/mptcp/mptcp_netlink.c -@@ -0,0 +1,1278 @@ +@@ -0,0 +1,1262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* MPTCP implementation - Netlink Path Manager + * @@ -19691,59 +19708,39 @@ index 000000000000..dd44a87a2971 + int remove_addr_len; + + unannounced = (~priv->announced4) & priv->loc4_bits; -+ if (unannounced && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR4_ALIGN) { ++ if (unannounced && mptcp_options_add_addr4_enough_space(mpcb, *size)) { + int i = mptcp_nl_find_free_index(~unannounced); + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_ADD_ADDR; -+ opts->add_addr4.addr_id = priv->locaddr4[i].loc4_id; -+ opts->add_addr4.addr = priv->locaddr4[i].addr; -+ opts->add_addr_v4 = 1; ++ *size += mptcp_options_fill_add_addr4(mpcb, opts, ++ &priv->locaddr4[i]); + + if (skb) + priv->announced4 |= (1 << i); -+ *size += MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; -+ -+ mpcb->add_addr_signal++; + } + +#if IS_ENABLED(CONFIG_IPV6) + unannounced = (~priv->announced6) & priv->loc6_bits; -+ if (unannounced && -+ MAX_TCP_OPTION_SPACE - *size >= MPTCP_SUB_LEN_ADD_ADDR6_ALIGN) { ++ if (unannounced && mptcp_options_add_addr6_enough_space(mpcb, *size)) { + int i = mptcp_nl_find_free_index(~unannounced); + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_ADD_ADDR; -+ opts->add_addr6.addr_id = priv->locaddr6[i].loc6_id; -+ opts->add_addr6.addr = priv->locaddr6[i].addr; -+ opts->add_addr_v6 = 1; ++ *size += mptcp_options_fill_add_addr6(mpcb, opts, ++ &priv->locaddr6[i]); + + if (skb) + priv->announced6 |= (1 << i); -+ *size += MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; -+ -+ mpcb->add_addr_signal++; + } +#endif + -+ if (likely(!priv->remove_addrs)) -+ goto exit; ++ if (unlikely(priv->remove_addrs) && ++ mptcp_options_rm_addr_enough_space(priv->remove_addrs, ++ &remove_addr_len, *size)) { ++ *size += mptcp_options_fill_rm_addr(opts, priv->remove_addrs, ++ remove_addr_len); + -+ remove_addr_len = mptcp_sub_len_remove_addr_align(priv->remove_addrs); -+ if (MAX_TCP_OPTION_SPACE - *size < remove_addr_len) -+ goto exit; ++ if (skb) ++ priv->remove_addrs = 0; ++ } + -+ opts->options |= OPTION_MPTCP; -+ opts->mptcp_options |= OPTION_REMOVE_ADDR; -+ opts->remove_addrs = priv->remove_addrs; -+ -+ if (skb) -+ priv->remove_addrs = 0; -+ *size += remove_addr_len; -+ -+exit: + mpcb->addr_signal = !!((~priv->announced4) & priv->loc4_bits || +#if IS_ENABLED(CONFIG_IPV6) + (~priv->announced6) & priv->loc6_bits || @@ -19863,11 +19860,15 @@ index 000000000000..dd44a87a2971 + + mpcb->addr_signal = 1; + -+ rcu_read_lock_bh(); -+ subsk = mptcp_select_ack_sock(meta_sk); -+ if (subsk) -+ tcp_send_ack(subsk); -+ rcu_read_unlock_bh(); ++ /* Only version 0 can send ADD_ADDR right at the beginning */ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1 || ++ tcp_sk(meta_sk)->mptcp->fully_established) { ++ rcu_read_lock_bh(); ++ subsk = mptcp_select_ack_sock(meta_sk); ++ if (subsk) ++ tcp_send_ack(subsk); ++ rcu_read_unlock_bh(); ++ } + +exit: + release_sock(meta_sk); @@ -20763,10 +20764,10 @@ index 000000000000..161a63f336d7 +MODULE_VERSION("0.1"); diff --git a/net/mptcp/mptcp_output.c b/net/mptcp/mptcp_output.c new file mode 100644 -index 000000000000..c26e14a702fd +index 000000000000..75e25ac60d06 --- /dev/null +++ b/net/mptcp/mptcp_output.c -@@ -0,0 +1,2038 @@ +@@ -0,0 +1,2121 @@ +/* + * MPTCP implementation - Sending side + * @@ -21963,12 +21964,18 @@ index 000000000000..c26e14a702fd + } + + if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && -+ mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { -+ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ mpcb->mptcp_ver >= MPTCP_VERSION_1 && ++ skb && tp->mptcp->fully_established) { + -+ if (opts->add_addr_v6) -+ /* Skip subsequent options */ -+ return; ++ if (!mptcp_is_data_seq(skb)) { ++ mpcb->pm_ops->addr_signal(sk, size, opts, skb); ++ ++ if (opts->add_addr_v6) ++ /* Skip subsequent options */ ++ return; ++ } else { ++ tcp_send_ack(sk); ++ } + } + + if (!tp->mptcp->include_mpc && !tp->mptcp->pre_established) { @@ -21978,7 +21985,8 @@ index 000000000000..c26e14a702fd + * assume that the DSS-option will be set for the data-packet. + */ + if (skb && !mptcp_is_data_seq(skb) && mpcb->rem_key_set) { -+ *size += MPTCP_SUB_LEN_ACK_ALIGN; ++ *size += MPTCP_SUB_LEN_ACK_ALIGN + ++ MPTCP_SUB_LEN_DSS_ALIGN; + } else if ((skb && mptcp_is_data_mpcapable(skb)) || + (!skb && tp->mpcb->send_mptcpv1_mpcapable)) { + *size += MPTCPV1_SUB_LEN_CAPABLE_DATA_ALIGN; @@ -21991,9 +21999,10 @@ index 000000000000..c26e14a702fd + MPTCP_SUB_LEN_SEQ_ALIGN; + else + *size += MPTCP_SUB_LEN_SEQ_ALIGN; ++ ++ *size += MPTCP_SUB_LEN_DSS_ALIGN; + } + -+ *size += MPTCP_SUB_LEN_DSS_ALIGN; + } + + /* In fallback mp_fail-mode, we have to repeat it until the fallback @@ -22805,6 +22814,81 @@ index 000000000000..c26e14a702fd + + return max(xmit_size_goal, mss_now); +} ++ ++unsigned int mptcp_options_fill_add_addr4(struct mptcp_cb *mpcb, ++ struct tcp_out_options *opts, ++ struct mptcp_loc4 *loc) ++{ ++ u16 port = 0; /* for ADD_ADDRv1, not supported yet */ ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr4.addr_id = loc->loc4_id; ++ opts->add_addr4.addr = loc->addr; ++ opts->add_addr_v4 = 1; ++ ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 3, ++ 1, (u8 *)&loc->loc4_id, ++ 4, (u8 *)&loc->addr.s_addr, ++ 2, (u8 *)&port); ++ opts->add_addr4.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; ++ } ++ ++ mpcb->add_addr_signal++; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ return MPTCP_SUB_LEN_ADD_ADDR4_ALIGN; ++ ++ return MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1; ++} ++EXPORT_SYMBOL(mptcp_options_fill_add_addr4); ++ ++unsigned int mptcp_options_fill_add_addr6(struct mptcp_cb *mpcb, ++ struct tcp_out_options *opts, ++ struct mptcp_loc6 *loc) ++{ ++ u16 port = 0; /* for ADD_ADDRv1, not supported yet */ ++ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_ADD_ADDR; ++ opts->add_addr6.addr_id = loc->loc6_id; ++ opts->add_addr6.addr = loc->addr; ++ opts->add_addr_v6 = 1; ++ ++ if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { ++ u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; ++ ++ mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, ++ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 3, ++ 1, (u8 *)&loc->loc6_id, ++ 16, (u8 *)loc->addr.s6_addr, ++ 2, (u8 *)&port); ++ opts->add_addr6.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; ++ } ++ ++ mpcb->add_addr_signal++; ++ ++ if (mpcb->mptcp_ver < MPTCP_VERSION_1) ++ return MPTCP_SUB_LEN_ADD_ADDR6_ALIGN; ++ ++ return MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1; ++} ++EXPORT_SYMBOL(mptcp_options_fill_add_addr6); ++ ++unsigned int mptcp_options_fill_rm_addr(struct tcp_out_options *opts, ++ u16 remove_addrs, int remove_addr_len) ++{ ++ opts->options |= OPTION_MPTCP; ++ opts->mptcp_options |= OPTION_REMOVE_ADDR; ++ opts->remove_addrs = remove_addrs; ++ ++ return remove_addr_len; ++} ++EXPORT_SYMBOL(mptcp_options_fill_rm_addr); diff --git a/net/mptcp/mptcp_pm.c b/net/mptcp/mptcp_pm.c new file mode 100644 index 000000000000..184c2cca0607 @@ -24762,160 +24846,3 @@ index cb0631098f91..b9de598828e9 100644 BPF_TCP_MAX_STATES /* Leave at the end! */ }; -diff --git a/net/mptcp/mptcp_output.c b/net/mptcp/mptcp_output.c -index c26e14a702fd..00d2e18aaf96 100644 ---- a/net/mptcp/mptcp_output.c -+++ b/net/mptcp/mptcp_output.c -@@ -1194,7 +1194,9 @@ void mptcp_established_options(struct sock *sk, struct sk_buff *skb, - } - - if (unlikely(mpcb->addr_signal) && mpcb->pm_ops->addr_signal && -- mpcb->mptcp_ver >= MPTCP_VERSION_1 && skb && !mptcp_is_data_seq(skb)) { -+ mpcb->mptcp_ver >= MPTCP_VERSION_1 && -+ skb && !mptcp_is_data_seq(skb) && -+ tp->mptcp->fully_established) { - mpcb->pm_ops->addr_signal(sk, size, opts, skb); - - if (opts->add_addr_v6) -diff --git a/net/mptcp/mptcp_fullmesh.c b/net/mptcp/mptcp_fullmesh.c -index ef2c15cbbeaa..4b97986de824 100644 ---- a/net/mptcp/mptcp_fullmesh.c -+++ b/net/mptcp/mptcp_fullmesh.c -@@ -1603,11 +1603,13 @@ static void full_mesh_addr_signal(struct sock *sk, unsigned *size, - opts->add_addr_v4 = 1; - if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { - u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; -+ u16 port = 0; - - mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, -- (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, -+ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 3, - 1, (u8 *)&mptcp_local->locaddr4[ind].loc4_id, -- 4, (u8 *)&opts->add_addr4.addr.s_addr); -+ 4, (u8 *)&opts->add_addr4.addr.s_addr, -+ 2, (u8 *)&port); - opts->add_addr4.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; - } - -@@ -1644,11 +1646,13 @@ static void full_mesh_addr_signal(struct sock *sk, unsigned *size, - opts->add_addr_v6 = 1; - if (mpcb->mptcp_ver >= MPTCP_VERSION_1) { - u8 mptcp_hash_mac[SHA256_DIGEST_SIZE]; -+ u16 port = 0; - - mptcp_hmac(mpcb->mptcp_ver, (u8 *)&mpcb->mptcp_loc_key, -- (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 2, -+ (u8 *)&mpcb->mptcp_rem_key, mptcp_hash_mac, 3, - 1, (u8 *)&mptcp_local->locaddr6[ind].loc6_id, -- 16, (u8 *)&opts->add_addr6.addr.s6_addr); -+ 16, (u8 *)opts->add_addr6.addr.s6_addr, -+ 2, (u8 *)&port); - opts->add_addr6.trunc_mac = *(u64 *)&mptcp_hash_mac[SHA256_DIGEST_SIZE - sizeof(u64)]; - } - -diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c -index d54127de9c3a..0c4db7d5177f 100644 ---- a/net/ipv4/tcp_minisocks.c -+++ b/net/ipv4/tcp_minisocks.c -@@ -847,6 +847,9 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, - return mptcp_check_req_child(sk, child, req, skb, &mopt); - } - -+ /* Fallback to regular TCP */ -+ tcp_sk(child)->mpc = 0; -+ - if (meta_locked) - bh_unlock_sock(sk); - -diff --git a/net/mptcp/mptcp_input.c b/net/mptcp/mptcp_input.c -index 41a511b3ef63..d5c1e8cec703 100644 ---- a/net/mptcp/mptcp_input.c -+++ b/net/mptcp/mptcp_input.c -@@ -1708,7 +1708,7 @@ bool mptcp_handle_ack_in_infinite(struct sock *sk, const struct sk_buff *skb, - * this becomes our data_ack. - */ - if (after(meta_tp->snd_una, tp->mptcp->last_end_data_seq - (tp->snd_nxt - tp->snd_una))) { -- /* Remmeber that meta snd_una is ahead of the game */ -+ /* Remember that meta snd_una is ahead of the game */ - mpcb->infinite_send_una_ahead = 1; - tp->mptcp->rx_opt.data_ack = meta_tp->snd_una; - } else { -diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c -index dfeff4e15882..f8b17ac89152 100644 ---- a/net/mptcp/mptcp_ctrl.c -+++ b/net/mptcp/mptcp_ctrl.c -@@ -2533,7 +2533,10 @@ static int __mptcp_check_req_master(struct sock *child, - } - - /* mopt can be NULL when coming from FAST-OPEN */ -- if (mopt && mopt->saw_mpc && mtreq->mptcp_ver == MPTCP_VERSION_1) { -+ if (mopt && mtreq->mptcp_ver == MPTCP_VERSION_1) { -+ if (!mopt->saw_mpc) -+ return 1; -+ - mtreq->mptcp_rem_key = mopt->mptcp_sender_key; - mtreq->rem_key_set = 1; - } -diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c -index f8b17ac89152..76eae7ec7d5c 100644 ---- a/net/mptcp/mptcp_ctrl.c -+++ b/net/mptcp/mptcp_ctrl.c -@@ -2528,7 +2528,6 @@ static int __mptcp_check_req_master(struct sock *child, - * must still remove it. - */ - MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK); -- mptcp_reqsk_remove_tk(req); - return 1; - } - -@@ -2565,11 +2564,6 @@ static int __mptcp_check_req_master(struct sock *child, - mpcb->dss_csum = mtreq->dss_csum; - mpcb->server_side = 1; - -- /* Needs to be done here additionally, because when accepting a -- * new connection we pass by __reqsk_free and not reqsk_free. -- */ -- mptcp_reqsk_remove_tk(req); -- - return 0; - } - -diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c -index 1ab36a72d93e..181018192f5d 100644 ---- a/net/ipv4/inet_connection_sock.c -+++ b/net/ipv4/inet_connection_sock.c -@@ -934,13 +934,15 @@ struct sock *inet_csk_reqsk_queue_add(struct sock *sk, - - spin_lock(&queue->rskq_lock); - if (unlikely(sk->sk_state != TCP_LISTEN)) { -- struct tcp_sock *tp = tcp_sk(sk); -+ if (sk->sk_protocol == IPPROTO_TCP) { -+ struct tcp_sock *child_tp = tcp_sk(child); - -- /* in case of mptcp, two locks may been taken, one -- * on the meta, the other on master_sk -- */ -- if (mptcp(tp) && tp->mpcb && tp->mpcb->master_sk) -- bh_unlock_sock(tp->mpcb->master_sk); -+ /* in case of mptcp, two locks may been taken, one -+ * on the meta, the other on master_sk -+ */ -+ if (mptcp(child_tp) && child_tp->mpcb && child_tp->mpcb->master_sk) -+ bh_unlock_sock(child_tp->mpcb->master_sk); -+ } - - inet_child_forget(sk, req, child); - child = NULL; -diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c -index 76eae7ec7d5c..8049dea0ded1 100644 ---- a/net/mptcp/mptcp_ctrl.c -+++ b/net/mptcp/mptcp_ctrl.c -@@ -2417,6 +2417,8 @@ void mptcp_disconnect(struct sock *meta_sk) - mptcp_for_each_sub_safe(meta_tp->mpcb, mptcp, tmp) { - struct sock *subsk = mptcp_to_sock(mptcp); - -+ BUG_ON(spin_is_locked(&subsk->sk_lock.slock)); -+ - tcp_sk(subsk)->tcp_disconnect = 1; - - meta_sk->sk_prot->disconnect(subsk, O_NONBLOCK); diff --git a/root/target/linux/generic/hack-5.4/693-tcp_bbr2.patch b/root/target/linux/generic/hack-5.4/693-tcp_bbr2.patch index 0d12ef53..653416c1 100644 --- a/root/target/linux/generic/hack-5.4/693-tcp_bbr2.patch +++ b/root/target/linux/generic/hack-5.4/693-tcp_bbr2.patch @@ -3244,14 +3244,14 @@ index be6d22b8190f..4943f96aade8 100644 /* Link BUFF into the send queue. */ @@ -1743,13 +1750,12 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, - static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) + u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; - u32 min_tso, tso_segs; - - min_tso = ca_ops->min_tso_segs ? - ca_ops->min_tso_segs(sk) : -- sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs; +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); + u32 tso_segs; - tso_segs = tcp_tso_autosize(sk, mss_now, min_tso); diff --git a/root/target/linux/generic/hack-5.4/695-Quectel-RM520N.patch b/root/target/linux/generic/hack-5.4/695-Quectel-RM520N.patch deleted file mode 100644 index edfb8ee5..00000000 --- a/root/target/linux/generic/hack-5.4/695-Quectel-RM520N.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index a5e8374a8d71..e716395268fe 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -256,5 +256,7 @@ static void option_instat_callback(struct urb *urb); - #define QUECTEL_PRODUCT_EM12 0x0512 - #define QUECTEL_PRODUCT_RM500Q 0x0800 -+#define QUECTEL_PRODUCT_RM520N 0x0801 -+#define QUECTEL_PRODUCT_RM500U_CN 0x0900 - #define QUECTEL_PRODUCT_EC200S_CN 0x6002 - #define QUECTEL_PRODUCT_EC200T 0x6026 - #define QUECTEL_PRODUCT_RM500K 0x7001 -@@ -1159,6 +1160,11 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10), - .driver_info = ZLP }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500U_CN, 0xff, 0, 0), -+ .driver_info = ZLP }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, -diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c -index 709e3c59e340..0cb187def5bc 100644 ---- a/drivers/net/usb/qmi_wwan.c -+++ b/drivers/net/usb/qmi_wwan.c -@@ -1087,6 +1087,8 @@ static const struct usb_device_id products[] = { - {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ - {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ - {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ -+ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ -+ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0900)}, /* Quectel RM500U_CN */ - - /* 3. Combined interface devices matching on interface number */ - {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ diff --git a/root/target/linux/generic/hack-5.4/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/root/target/linux/generic/hack-5.4/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 23e3b66a..a25ed559 100644 --- a/root/target/linux/generic/hack-5.4/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/root/target/linux/generic/hack-5.4/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -12,12 +12,12 @@ struct list_head *br_ip_list); --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -826,6 +826,10 @@ struct sk_buff { +@@ -827,6 +827,10 @@ struct sk_buff { #endif - __u8 gro_skip:1; + __u8 scm_io_uring:1; +#ifdef CONFIG_SHORTCUT_FE -+ __u16 fast_forwarded:1; ++ __u8 fast_forwarded:1; +#endif + #ifdef CONFIG_NET_SCHED @@ -49,7 +49,7 @@ int (*fcn)(unsigned int events, struct nf_ct_event *item); --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c -@@ -746,6 +746,28 @@ void br_port_flags_change(struct net_bri +@@ -763,6 +763,28 @@ void br_port_flags_change(struct net_bri br_recalculate_neigh_suppress_enabled(br); } @@ -78,10 +78,9 @@ bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) { struct net_bridge_port *p; - --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3189,8 +3189,17 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, +@@ -3197,9 +3197,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -93,13 +92,14 @@ +#endif if (dev_nit_active(dev)) dev_queue_xmit_nit(skb, dev); +- +#ifdef CONFIG_SHORTCUT_FE + } +#endif - #ifdef CONFIG_ETHERNET_PACKET_MANGLE if (!dev->eth_mangle_tx || -@@ -4683,6 +4691,11 @@ void netdev_rx_handler_unregister(struct + (skb = dev->eth_mangle_tx(dev, skb)) != NULL) +@@ -4715,6 +4723,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -111,7 +111,7 @@ /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -4733,6 +4746,10 @@ static int __netif_receive_skb_core(stru +@@ -4765,6 +4778,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -119,10 +119,10 @@ + int (*fast_recv)(struct sk_buff *skb); +#endif + - net_timestamp_check(!netdev_tstamp_prequeue, skb); + net_timestamp_check(!READ_ONCE(netdev_tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -4772,6 +4789,16 @@ another_round: +@@ -4804,6 +4821,16 @@ another_round: goto out; } @@ -172,7 +172,7 @@ static int nf_ct_tcp_loose __read_mostly = 1; --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c -@@ -162,7 +162,11 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, +@@ -158,7 +158,11 @@ int nf_conntrack_eventmask_report(unsign rcu_read_lock(); notify = rcu_dereference(net->ct.nf_conntrack_event_cb); @@ -184,7 +184,7 @@ goto out_unlock; e = nf_ct_ecache_find(ct); -@@ -181,7 +185,14 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, +@@ -177,7 +181,14 @@ int nf_conntrack_eventmask_report(unsign if (!((eventmask | missed) & e->ctmask)) goto out_unlock; @@ -199,7 +199,7 @@ if (unlikely(ret < 0 || missed)) { spin_lock_bh(&ct->lock); if (ret < 0) { -@@ -263,7 +274,11 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) +@@ -259,7 +270,11 @@ void nf_ct_deliver_cached_events(struct rcu_read_lock(); notify = rcu_dereference(net->ct.nf_conntrack_event_cb); @@ -211,7 +211,7 @@ goto out_unlock; e = nf_ct_ecache_find(ct); -@@ -287,7 +302,15 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) +@@ -283,7 +298,15 @@ void nf_ct_deliver_cached_events(struct item.portid = 0; item.report = 0; @@ -227,9 +227,9 @@ if (likely(ret == 0 && !missed)) goto out_unlock; -@@ -340,6 +363,11 @@ int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb) +@@ -337,6 +360,11 @@ int nf_conntrack_register_notifier(struc { - return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); + return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); } +int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb) +{ @@ -239,7 +239,7 @@ #else int nf_conntrack_register_notifier(struct net *net, struct nf_ct_event_notifier *new) -@@ -369,6 +397,11 @@ int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb) +@@ -366,6 +394,11 @@ int nf_conntrack_unregister_notifier(str { return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); } diff --git a/root/tools/meson/Makefile b/root/tools/meson/Makefile new file mode 100644 index 00000000..d53ed897 --- /dev/null +++ b/root/tools/meson/Makefile @@ -0,0 +1,35 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=meson +PKG_VERSION:=0.61.5 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://github.com/mesonbuild/meson/releases/download/$(PKG_VERSION) +PKG_HASH:=5e9a0d65c1a51936362b9686d1c5e9e184a6fd245d57e7269750ce50c20f5d9a + +PKG_MAINTAINER:=Andre Heider +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=COPYING + +include $(INCLUDE_DIR)/host-build.mk + +define Host/Configure +endef + +define Host/Compile +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin + $(HOST_BUILD_DIR)/packaging/create_zipapp.py $(HOST_BUILD_DIR) --outfile $(STAGING_DIR_HOST)/bin/meson.py + $(INSTALL_DIR) $(STAGING_DIR_HOST)/lib/meson + $(INSTALL_CONF) files/openwrt-cross.txt.in $(STAGING_DIR_HOST)/lib/meson/ + $(INSTALL_CONF) files/openwrt-native.txt.in $(STAGING_DIR_HOST)/lib/meson/ +endef + +define Host/Clean + $(call Host/Clean/Default) + rm -rf $(STAGING_DIR_HOST)/lib/meson +endef + +$(eval $(call HostBuild)) diff --git a/root/tools/meson/files/openwrt-cross.txt.in b/root/tools/meson/files/openwrt-cross.txt.in new file mode 100644 index 00000000..ec4b027f --- /dev/null +++ b/root/tools/meson/files/openwrt-cross.txt.in @@ -0,0 +1,25 @@ +[binaries] +c = [@CC@] +cpp = [@CXX@] +ar = '@AR@' +strip = '@STRIP@' +nm = '@NM@' +pkgconfig = '@PKGCONFIG@' +cmake = '@CMAKE@' +python = '@PYTHON@' + +[built-in options] +c_args = [@CFLAGS@] +c_link_args = [@LDFLAGS@] +cpp_args = [@CXXFLAGS@] +cpp_link_args = [@LDFLAGS@] +prefix = '/usr' + +[host_machine] +system = 'linux' +cpu_family = '@ARCH@' +cpu = '@CPU@' +endian = '@ENDIAN@' + +[properties] +needs_exe_wrapper = true diff --git a/root/tools/meson/files/openwrt-native.txt.in b/root/tools/meson/files/openwrt-native.txt.in new file mode 100644 index 00000000..48e09ece --- /dev/null +++ b/root/tools/meson/files/openwrt-native.txt.in @@ -0,0 +1,15 @@ +[binaries] +c = [@CC@] +cpp = [@CXX@] +pkgconfig = '@PKGCONFIG@' +cmake = '@CMAKE@' +python = '@PYTHON@' + +[built-in options] +c_args = [@CFLAGS@] +c_link_args = [@LDFLAGS@] +cpp_args = [@CXXFLAGS@] +cpp_link_args = [@LDFLAGS@] +prefix = '@PREFIX@' +sbindir = 'bin' +libdir = 'lib' diff --git a/root/tools/meson/patches/010-wsl2.patch b/root/tools/meson/patches/010-wsl2.patch new file mode 100644 index 00000000..4ab799d6 --- /dev/null +++ b/root/tools/meson/patches/010-wsl2.patch @@ -0,0 +1,21 @@ +From 7d1ef4343ed5b2b7ab51469177a42c32c47f0528 Mon Sep 17 00:00:00 2001 +From: Rosen Penev +Date: Tue, 6 Sep 2022 01:36:17 -0700 +Subject: [PATCH] minstall: handle extra error for selinuxenabled + +Microsoft's WSL2 uses a Plan 9 filesystem, which returns IOError when file is missing. +--- + mesonbuild/minstall.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mesonbuild/minstall.py ++++ b/mesonbuild/minstall.py +@@ -229,7 +229,7 @@ def restore_selinux_contexts() -> None: + ''' + try: + subprocess.check_call(['selinuxenabled']) +- except (FileNotFoundError, NotADirectoryError, PermissionError, subprocess.CalledProcessError): ++ except (FileNotFoundError, NotADirectoryError, OSError, PermissionError, subprocess.CalledProcessError): + # If we don't have selinux or selinuxenabled returned 1, failure + # is ignored quietly. + return diff --git a/root/tools/ninja/Makefile b/root/tools/ninja/Makefile new file mode 100644 index 00000000..c5c83d9b --- /dev/null +++ b/root/tools/ninja/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ninja +PKG_VERSION:=1.11.0 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/ninja-build/ninja/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=3c6ba2e66400fe3f1ae83deb4b235faf3137ec20bd5b08c29bfc368db143e4c6 + +include $(INCLUDE_DIR)/host-build.mk + +CONFIGURE_ARGS:= +ifneq ($(findstring c,$(OPENWRT_VERBOSE)),) + CONFIGURE_ARGS+=--verbose +endif + +define Host/Configure +endef + +define Host/Compile + cd $(HOST_BUILD_DIR) && \ + CXX="$(HOSTCXX_NOCACHE)" \ + CXXFLAGS="$(HOST_CXXFLAGS) $(HOST_CPPFLAGS)" \ + LDFLAGS="$(HOST_LDFLAGS)" \ + $(STAGING_DIR_HOST)/bin/$(PYTHON) configure.py --bootstrap $(CONFIGURE_ARGS) +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin + $(INSTALL_BIN) $(HOST_BUILD_DIR)/ninja $(STAGING_DIR_HOST)/bin/ +endef + +define Host/Clean + $(call Host/Clean/Default) + rm -f $(STAGING_DIR_HOST)/bin/ninja +endef + +$(eval $(call HostBuild)) diff --git a/root/tools/ninja/patches/100-make_jobserver_support.patch b/root/tools/ninja/patches/100-make_jobserver_support.patch new file mode 100644 index 00000000..7dac8ef8 --- /dev/null +++ b/root/tools/ninja/patches/100-make_jobserver_support.patch @@ -0,0 +1,4290 @@ +From 17d13fd7881fd3ce9f9b9d44ce435d6caf4b8f28 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Tue, 22 Mar 2016 13:48:07 +0200 +Subject: [PATCH 01/11] Add GNU make jobserver client support + +- add new TokenPool interface +- GNU make implementation for TokenPool parses and verifies the magic + information from the MAKEFLAGS environment variable +- RealCommandRunner tries to acquire TokenPool + * if no token pool is available then there is no change in behaviour +- When a token pool is available then RealCommandRunner behaviour + changes as follows + * CanRunMore() only returns true if TokenPool::Acquire() returns true + * StartCommand() calls TokenPool::Reserve() + * WaitForCommand() calls TokenPool::Release() + +Documentation for GNU make jobserver + + http://make.mad-scientist.net/papers/jobserver-implementation/ + +Fixes https://github.com/ninja-build/ninja/issues/1139 +--- + configure.py | 2 + + src/build.cc | 63 ++++++++---- + src/build.h | 3 + + src/tokenpool-gnu-make.cc | 211 ++++++++++++++++++++++++++++++++++++++ + src/tokenpool-none.cc | 27 +++++ + src/tokenpool.h | 26 +++++ + 6 files changed, 310 insertions(+), 22 deletions(-) + create mode 100644 src/tokenpool-gnu-make.cc + create mode 100644 src/tokenpool-none.cc + create mode 100644 src/tokenpool.h + +diff --git a/configure.py b/configure.py +index 43904349a8..db3492c93c 100755 +--- a/configure.py ++++ b/configure.py +@@ -522,6 +522,7 @@ def has_re2c(): + objs += cxx(name, variables=cxxvariables) + if platform.is_windows(): + for name in ['subprocess-win32', ++ 'tokenpool-none', + 'includes_normalize-win32', + 'msvc_helper-win32', + 'msvc_helper_main-win32']: +@@ -531,6 +532,7 @@ def has_re2c(): + objs += cc('getopt') + else: + objs += cxx('subprocess-posix') ++ objs += cxx('tokenpool-gnu-make') + if platform.is_aix(): + objs += cc('getopt') + if platform.is_msvc(): +diff --git a/src/build.cc b/src/build.cc +index 6f11ed7a3c..fa096eac33 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -35,6 +35,7 @@ + #include "state.h" + #include "status.h" + #include "subprocess.h" ++#include "tokenpool.h" + #include "util.h" + + using namespace std; +@@ -149,7 +150,7 @@ void Plan::EdgeWanted(const Edge* edge) { + } + + Edge* Plan::FindWork() { +- if (ready_.empty()) ++ if (!more_ready()) + return NULL; + EdgeSet::iterator e = ready_.begin(); + Edge* edge = *e; +@@ -448,8 +449,8 @@ void Plan::Dump() const { + } + + struct RealCommandRunner : public CommandRunner { +- explicit RealCommandRunner(const BuildConfig& config) : config_(config) {} +- virtual ~RealCommandRunner() {} ++ explicit RealCommandRunner(const BuildConfig& config); ++ virtual ~RealCommandRunner(); + virtual bool CanRunMore() const; + virtual bool StartCommand(Edge* edge); + virtual bool WaitForCommand(Result* result); +@@ -458,9 +459,18 @@ struct RealCommandRunner : public CommandRunner { + + const BuildConfig& config_; + SubprocessSet subprocs_; ++ TokenPool *tokens_; + map subproc_to_edge_; + }; + ++RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { ++ tokens_ = TokenPool::Get(); ++} ++ ++RealCommandRunner::~RealCommandRunner() { ++ delete tokens_; ++} ++ + vector RealCommandRunner::GetActiveEdges() { + vector edges; + for (map::iterator e = subproc_to_edge_.begin(); +@@ -471,14 +481,18 @@ vector RealCommandRunner::GetActiveEdges() { + + void RealCommandRunner::Abort() { + subprocs_.Clear(); ++ if (tokens_) ++ tokens_->Clear(); + } + + bool RealCommandRunner::CanRunMore() const { + size_t subproc_number = + subprocs_.running_.size() + subprocs_.finished_.size(); + return (int)subproc_number < config_.parallelism +- && ((subprocs_.running_.empty() || config_.max_load_average <= 0.0f) +- || GetLoadAverage() < config_.max_load_average); ++ && (subprocs_.running_.empty() || ++ ((config_.max_load_average <= 0.0f || ++ GetLoadAverage() < config_.max_load_average) ++ && (!tokens_ || tokens_->Acquire()))); + } + + bool RealCommandRunner::StartCommand(Edge* edge) { +@@ -486,6 +500,8 @@ bool RealCommandRunner::StartCommand(Edge* edge) { + Subprocess* subproc = subprocs_.Add(command, edge->use_console()); + if (!subproc) + return false; ++ if (tokens_) ++ tokens_->Reserve(); + subproc_to_edge_.insert(make_pair(subproc, edge)); + + return true; +@@ -499,6 +515,9 @@ bool RealCommandRunner::WaitForCommand(Result* result) { + return false; + } + ++ if (tokens_) ++ tokens_->Release(); ++ + result->status = subproc->Finish(); + result->output = subproc->GetOutput(); + +@@ -621,31 +640,31 @@ bool Builder::Build(string* err) { + // Second, we attempt to wait for / reap the next finished command. + while (plan_.more_to_do()) { + // See if we can start any more commands. +- if (failures_allowed && command_runner_->CanRunMore()) { +- if (Edge* edge = plan_.FindWork()) { +- if (edge->GetBindingBool("generator")) { ++ if (failures_allowed && plan_.more_ready() && ++ command_runner_->CanRunMore()) { ++ Edge* edge = plan_.FindWork(); ++ if (edge->GetBindingBool("generator")) { + scan_.build_log()->Close(); + } + +- if (!StartEdge(edge, err)) { ++ if (!StartEdge(edge, err)) { ++ Cleanup(); ++ status_->BuildFinished(); ++ return false; ++ } ++ ++ if (edge->is_phony()) { ++ if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) { + Cleanup(); + status_->BuildFinished(); + return false; + } +- +- if (edge->is_phony()) { +- if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) { +- Cleanup(); +- status_->BuildFinished(); +- return false; +- } +- } else { +- ++pending_commands; +- } +- +- // We made some progress; go back to the main loop. +- continue; ++ } else { ++ ++pending_commands; + } ++ ++ // We made some progress; go back to the main loop. ++ continue; + } + + // See if we can reap any finished commands. +diff --git a/src/build.h b/src/build.h +index d697dfb89e..7dcd111e61 100644 +--- a/src/build.h ++++ b/src/build.h +@@ -52,6 +52,9 @@ struct Plan { + /// Returns true if there's more work to be done. + bool more_to_do() const { return wanted_edges_ > 0 && command_edges_ > 0; } + ++ /// Returns true if there's more edges ready to start ++ bool more_ready() const { return !ready_.empty(); } ++ + /// Dumps the current state of the plan. + void Dump() const; + +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +new file mode 100644 +index 0000000000..a8f9b7139d +--- /dev/null ++++ b/src/tokenpool-gnu-make.cc +@@ -0,0 +1,211 @@ ++// Copyright 2016 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// TokenPool implementation for GNU make jobserver ++// (http://make.mad-scientist.net/papers/jobserver-implementation/) ++struct GNUmakeTokenPool : public TokenPool { ++ GNUmakeTokenPool(); ++ virtual ~GNUmakeTokenPool(); ++ ++ virtual bool Acquire(); ++ virtual void Reserve(); ++ virtual void Release(); ++ virtual void Clear(); ++ ++ bool Setup(); ++ ++ private: ++ int available_; ++ int used_; ++ ++#ifdef _WIN32 ++ // @TODO ++#else ++ int rfd_; ++ int wfd_; ++ ++ struct sigaction old_act_; ++ bool restore_; ++ ++ static int dup_rfd_; ++ static void CloseDupRfd(int signum); ++ ++ bool CheckFd(int fd); ++ bool SetAlarmHandler(); ++#endif ++ ++ void Return(); ++}; ++ ++// every instance owns an implicit token -> available_ == 1 ++GNUmakeTokenPool::GNUmakeTokenPool() : available_(1), used_(0), ++ rfd_(-1), wfd_(-1), restore_(false) { ++} ++ ++GNUmakeTokenPool::~GNUmakeTokenPool() { ++ Clear(); ++ if (restore_) ++ sigaction(SIGALRM, &old_act_, NULL); ++} ++ ++bool GNUmakeTokenPool::CheckFd(int fd) { ++ if (fd < 0) ++ return false; ++ int ret = fcntl(fd, F_GETFD); ++ if (ret < 0) ++ return false; ++ return true; ++} ++ ++int GNUmakeTokenPool::dup_rfd_ = -1; ++ ++void GNUmakeTokenPool::CloseDupRfd(int signum) { ++ close(dup_rfd_); ++ dup_rfd_ = -1; ++} ++ ++bool GNUmakeTokenPool::SetAlarmHandler() { ++ struct sigaction act; ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGALRM, &act, &old_act_) < 0) { ++ perror("sigaction:"); ++ return(false); ++ } else { ++ restore_ = true; ++ return(true); ++ } ++} ++ ++bool GNUmakeTokenPool::Setup() { ++ const char *value = getenv("MAKEFLAGS"); ++ if (value) { ++ // GNU make <= 4.1 ++ const char *jobserver = strstr(value, "--jobserver-fds="); ++ // GNU make => 4.2 ++ if (!jobserver) ++ jobserver = strstr(value, "--jobserver-auth="); ++ if (jobserver) { ++ int rfd = -1; ++ int wfd = -1; ++ if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && ++ CheckFd(rfd) && ++ CheckFd(wfd) && ++ SetAlarmHandler()) { ++ printf("ninja: using GNU make jobserver.\n"); ++ rfd_ = rfd; ++ wfd_ = wfd; ++ return true; ++ } ++ } ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPool::Acquire() { ++ if (available_ > 0) ++ return true; ++ ++#ifdef USE_PPOLL ++ pollfd pollfds[] = {{rfd_, POLLIN, 0}}; ++ int ret = poll(pollfds, 1, 0); ++#else ++ fd_set set; ++ struct timeval timeout = { 0, 0 }; ++ FD_ZERO(&set); ++ FD_SET(rfd_, &set); ++ int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); ++#endif ++ if (ret > 0) { ++ dup_rfd_ = dup(rfd_); ++ ++ if (dup_rfd_ != -1) { ++ struct sigaction act, old_act; ++ int ret = 0; ++ ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGCHLD, &act, &old_act) == 0) { ++ char buf; ++ ++ // block until token read, child exits or timeout ++ alarm(1); ++ ret = read(dup_rfd_, &buf, 1); ++ alarm(0); ++ ++ sigaction(SIGCHLD, &old_act, NULL); ++ } ++ ++ CloseDupRfd(0); ++ ++ if (ret > 0) { ++ available_++; ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++void GNUmakeTokenPool::Reserve() { ++ available_--; ++ used_++; ++} ++ ++void GNUmakeTokenPool::Return() { ++ const char buf = '+'; ++ while (1) { ++ int ret = write(wfd_, &buf, 1); ++ if (ret > 0) ++ available_--; ++ if ((ret != -1) || (errno != EINTR)) ++ return; ++ // write got interrupted - retry ++ } ++} ++ ++void GNUmakeTokenPool::Release() { ++ available_++; ++ used_--; ++ if (available_ > 1) ++ Return(); ++} ++ ++void GNUmakeTokenPool::Clear() { ++ while (used_ > 0) ++ Release(); ++ while (available_ > 1) ++ Return(); ++} ++ ++struct TokenPool *TokenPool::Get(void) { ++ GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; ++ if (tokenpool->Setup()) ++ return tokenpool; ++ else ++ delete tokenpool; ++ return NULL; ++} +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +new file mode 100644 +index 0000000000..602b3316f5 +--- /dev/null ++++ b/src/tokenpool-none.cc +@@ -0,0 +1,27 @@ ++// Copyright 2016 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// No-op TokenPool implementation ++struct TokenPool *TokenPool::Get(void) { ++ return NULL; ++} +diff --git a/src/tokenpool.h b/src/tokenpool.h +new file mode 100644 +index 0000000000..f560b1083b +--- /dev/null ++++ b/src/tokenpool.h +@@ -0,0 +1,26 @@ ++// Copyright 2016 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++// interface to token pool ++struct TokenPool { ++ virtual ~TokenPool() {} ++ ++ virtual bool Acquire() = 0; ++ virtual void Reserve() = 0; ++ virtual void Release() = 0; ++ virtual void Clear() = 0; ++ ++ // returns NULL if token pool is not available ++ static struct TokenPool *Get(void); ++}; + +From ccaccc610cd456f6068758f82e72006364c7380b Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Fri, 27 May 2016 16:47:10 +0300 +Subject: [PATCH 02/11] Add TokenPool monitoring to SubprocessSet::DoWork() + +Improve on the original jobserver client implementation. This makes +ninja a more aggressive GNU make jobserver client. + +- add monitor interface to TokenPool +- TokenPool is passed down when main loop indicates that more work is + ready and would be allowed to start if a token becomes available +- posix: update DoWork() to monitor TokenPool read file descriptor +- WaitForCommand() exits when DoWork() sets token flag +- Main loop starts over when WaitForCommand() sets token exit status +--- + src/build.cc | 53 +++++++++++++++++++++++++++++---------- + src/build.h | 3 ++- + src/build_test.cc | 9 +++++-- + src/exit_status.h | 3 ++- + src/subprocess-posix.cc | 33 ++++++++++++++++++++++-- + src/subprocess-win32.cc | 2 +- + src/subprocess.h | 8 +++++- + src/subprocess_test.cc | 47 +++++++++++++++++++++++----------- + src/tokenpool-gnu-make.cc | 5 ++++ + src/tokenpool.h | 6 +++++ + 10 files changed, 134 insertions(+), 35 deletions(-) + +diff --git a/src/build.cc b/src/build.cc +index fa096eac33..a25c349050 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -48,8 +48,9 @@ struct DryRunCommandRunner : public CommandRunner { + + // Overridden from CommandRunner: + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + + private: + queue finished_; +@@ -59,12 +60,16 @@ bool DryRunCommandRunner::CanRunMore() const { + return true; + } + ++bool DryRunCommandRunner::AcquireToken() { ++ return true; ++} ++ + bool DryRunCommandRunner::StartCommand(Edge* edge) { + finished_.push(edge); + return true; + } + +-bool DryRunCommandRunner::WaitForCommand(Result* result) { ++bool DryRunCommandRunner::WaitForCommand(Result* result, bool more_ready) { + if (finished_.empty()) + return false; + +@@ -452,8 +457,9 @@ struct RealCommandRunner : public CommandRunner { + explicit RealCommandRunner(const BuildConfig& config); + virtual ~RealCommandRunner(); + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + virtual vector GetActiveEdges(); + virtual void Abort(); + +@@ -490,9 +496,12 @@ bool RealCommandRunner::CanRunMore() const { + subprocs_.running_.size() + subprocs_.finished_.size(); + return (int)subproc_number < config_.parallelism + && (subprocs_.running_.empty() || +- ((config_.max_load_average <= 0.0f || +- GetLoadAverage() < config_.max_load_average) +- && (!tokens_ || tokens_->Acquire()))); ++ (config_.max_load_average <= 0.0f || ++ GetLoadAverage() < config_.max_load_average)); ++} ++ ++bool RealCommandRunner::AcquireToken() { ++ return (!tokens_ || tokens_->Acquire()); + } + + bool RealCommandRunner::StartCommand(Edge* edge) { +@@ -507,14 +516,23 @@ bool RealCommandRunner::StartCommand(Edge* edge) { + return true; + } + +-bool RealCommandRunner::WaitForCommand(Result* result) { ++bool RealCommandRunner::WaitForCommand(Result* result, bool more_ready) { + Subprocess* subproc; +- while ((subproc = subprocs_.NextFinished()) == NULL) { +- bool interrupted = subprocs_.DoWork(); ++ subprocs_.ResetTokenAvailable(); ++ while (((subproc = subprocs_.NextFinished()) == NULL) && ++ !subprocs_.IsTokenAvailable()) { ++ bool interrupted = subprocs_.DoWork(more_ready ? tokens_ : NULL); + if (interrupted) + return false; + } + ++ // token became available ++ if (subproc == NULL) { ++ result->status = ExitTokenAvailable; ++ return true; ++ } ++ ++ // command completed + if (tokens_) + tokens_->Release(); + +@@ -639,9 +657,14 @@ bool Builder::Build(string* err) { + // command runner. + // Second, we attempt to wait for / reap the next finished command. + while (plan_.more_to_do()) { +- // See if we can start any more commands. +- if (failures_allowed && plan_.more_ready() && +- command_runner_->CanRunMore()) { ++ // See if we can start any more commands... ++ bool can_run_more = ++ failures_allowed && ++ plan_.more_ready() && ++ command_runner_->CanRunMore(); ++ ++ // ... but we also need a token to do that. ++ if (can_run_more && command_runner_->AcquireToken()) { + Edge* edge = plan_.FindWork(); + if (edge->GetBindingBool("generator")) { + scan_.build_log()->Close(); +@@ -670,7 +693,7 @@ bool Builder::Build(string* err) { + // See if we can reap any finished commands. + if (pending_commands) { + CommandRunner::Result result; +- if (!command_runner_->WaitForCommand(&result) || ++ if (!command_runner_->WaitForCommand(&result, can_run_more) || + result.status == ExitInterrupted) { + Cleanup(); + status_->BuildFinished(); +@@ -678,6 +701,10 @@ bool Builder::Build(string* err) { + return false; + } + ++ // We might be able to start another command; start the main loop over. ++ if (result.status == ExitTokenAvailable) ++ continue; ++ + --pending_commands; + if (!FinishCommand(&result, err)) { + Cleanup(); +diff --git a/src/build.h b/src/build.h +index 7dcd111e61..35c7b97d12 100644 +--- a/src/build.h ++++ b/src/build.h +@@ -139,6 +139,7 @@ struct Plan { + struct CommandRunner { + virtual ~CommandRunner() {} + virtual bool CanRunMore() const = 0; ++ virtual bool AcquireToken() = 0; + virtual bool StartCommand(Edge* edge) = 0; + + /// The result of waiting for a command. +@@ -150,7 +151,7 @@ struct CommandRunner { + bool success() const { return status == ExitSuccess; } + }; + /// Wait for a command to complete, or return false if interrupted. +- virtual bool WaitForCommand(Result* result) = 0; ++ virtual bool WaitForCommand(Result* result, bool more_ready) = 0; + + virtual std::vector GetActiveEdges() { return std::vector(); } + virtual void Abort() {} +diff --git a/src/build_test.cc b/src/build_test.cc +index 4ef62b2113..7a5ff4015a 100644 +--- a/src/build_test.cc ++++ b/src/build_test.cc +@@ -474,8 +474,9 @@ struct FakeCommandRunner : public CommandRunner { + + // CommandRunner impl + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + virtual vector GetActiveEdges(); + virtual void Abort(); + +@@ -578,6 +579,10 @@ bool FakeCommandRunner::CanRunMore() const { + return active_edges_.size() < max_active_edges_; + } + ++bool FakeCommandRunner::AcquireToken() { ++ return true; ++} ++ + bool FakeCommandRunner::StartCommand(Edge* edge) { + assert(active_edges_.size() < max_active_edges_); + assert(find(active_edges_.begin(), active_edges_.end(), edge) +@@ -649,7 +654,7 @@ bool FakeCommandRunner::StartCommand(Edge* edge) { + return true; + } + +-bool FakeCommandRunner::WaitForCommand(Result* result) { ++bool FakeCommandRunner::WaitForCommand(Result* result, bool more_ready) { + if (active_edges_.empty()) + return false; + +diff --git a/src/exit_status.h b/src/exit_status.h +index a714ece791..75ebf6a7a0 100644 +--- a/src/exit_status.h ++++ b/src/exit_status.h +@@ -18,7 +18,8 @@ + enum ExitStatus { + ExitSuccess, + ExitFailure, +- ExitInterrupted ++ ExitTokenAvailable, ++ ExitInterrupted, + }; + + #endif // NINJA_EXIT_STATUS_H_ +diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc +index 8e785406c9..74451b0be2 100644 +--- a/src/subprocess-posix.cc ++++ b/src/subprocess-posix.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include + #include +@@ -249,7 +250,7 @@ Subprocess *SubprocessSet::Add(const string& command, bool use_console) { + } + + #ifdef USE_PPOLL +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(struct TokenPool* tokens) { + vector fds; + nfds_t nfds = 0; + +@@ -263,6 +264,12 @@ bool SubprocessSet::DoWork() { + ++nfds; + } + ++ if (tokens) { ++ pollfd pfd = { tokens->GetMonitorFd(), POLLIN | POLLPRI, 0 }; ++ fds.push_back(pfd); ++ ++nfds; ++ } ++ + interrupted_ = 0; + int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_); + if (ret == -1) { +@@ -295,11 +302,20 @@ bool SubprocessSet::DoWork() { + ++i; + } + ++ if (tokens) { ++ pollfd *pfd = &fds[nfds - 1]; ++ if (pfd->fd >= 0) { ++ assert(pfd->fd == tokens->GetMonitorFd()); ++ if (pfd->revents != 0) ++ token_available_ = true; ++ } ++ } ++ + return IsInterrupted(); + } + + #else // !defined(USE_PPOLL) +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(struct TokenPool* tokens) { + fd_set set; + int nfds = 0; + FD_ZERO(&set); +@@ -314,6 +330,13 @@ bool SubprocessSet::DoWork() { + } + } + ++ if (tokens) { ++ int fd = tokens->GetMonitorFd(); ++ FD_SET(fd, &set); ++ if (nfds < fd+1) ++ nfds = fd+1; ++ } ++ + interrupted_ = 0; + int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_); + if (ret == -1) { +@@ -342,6 +365,12 @@ bool SubprocessSet::DoWork() { + ++i; + } + ++ if (tokens) { ++ int fd = tokens->GetMonitorFd(); ++ if ((fd >= 0) && FD_ISSET(fd, &set)) ++ token_available_ = true; ++ } ++ + return IsInterrupted(); + } + #endif // !defined(USE_PPOLL) +diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc +index ff3baaca7f..66d2c2c430 100644 +--- a/src/subprocess-win32.cc ++++ b/src/subprocess-win32.cc +@@ -251,7 +251,7 @@ Subprocess *SubprocessSet::Add(const string& command, bool use_console) { + return subprocess; + } + +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(struct TokenPool* tokens) { + DWORD bytes_read; + Subprocess* subproc; + OVERLAPPED* overlapped; +diff --git a/src/subprocess.h b/src/subprocess.h +index 9e3d2ee98f..9ea67ea477 100644 +--- a/src/subprocess.h ++++ b/src/subprocess.h +@@ -76,6 +76,8 @@ struct Subprocess { + friend struct SubprocessSet; + }; + ++struct TokenPool; ++ + /// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses. + /// DoWork() waits for any state change in subprocesses; finished_ + /// is a queue of subprocesses as they finish. +@@ -84,13 +86,17 @@ struct SubprocessSet { + ~SubprocessSet(); + + Subprocess* Add(const std::string& command, bool use_console = false); +- bool DoWork(); ++ bool DoWork(struct TokenPool* tokens); + Subprocess* NextFinished(); + void Clear(); + + std::vector running_; + std::queue finished_; + ++ bool token_available_; ++ bool IsTokenAvailable() { return token_available_; } ++ void ResetTokenAvailable() { token_available_ = false; } ++ + #ifdef _WIN32 + static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType); + static HANDLE ioport_; +diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc +index 073fe86931..4bc8083e26 100644 +--- a/src/subprocess_test.cc ++++ b/src/subprocess_test.cc +@@ -45,10 +45,12 @@ TEST_F(SubprocessTest, BadCommandStderr) { + Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { + // Pretend we discovered that stderr was ready for writing. +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -59,10 +61,12 @@ TEST_F(SubprocessTest, NoSuchCommand) { + Subprocess* subproc = subprocs_.Add("ninja_no_such_command"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { + // Pretend we discovered that stderr was ready for writing. +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -78,9 +82,11 @@ TEST_F(SubprocessTest, InterruptChild) { + Subprocess* subproc = subprocs_.Add("kill -INT $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -90,7 +96,7 @@ TEST_F(SubprocessTest, InterruptParent) { + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -102,9 +108,11 @@ TEST_F(SubprocessTest, InterruptChildWithSigTerm) { + Subprocess* subproc = subprocs_.Add("kill -TERM $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -114,7 +122,7 @@ TEST_F(SubprocessTest, InterruptParentWithSigTerm) { + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -126,9 +134,11 @@ TEST_F(SubprocessTest, InterruptChildWithSigHup) { + Subprocess* subproc = subprocs_.Add("kill -HUP $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -138,7 +148,7 @@ TEST_F(SubprocessTest, InterruptParentWithSigHup) { + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -153,9 +163,11 @@ TEST_F(SubprocessTest, Console) { + subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true); + ASSERT_NE((Subprocess*)0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitSuccess, subproc->Finish()); + } +@@ -167,9 +179,11 @@ TEST_F(SubprocessTest, SetWithSingle) { + Subprocess* subproc = subprocs_.Add(kSimpleCommand); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_NE("", subproc->GetOutput()); + +@@ -200,12 +214,13 @@ TEST_F(SubprocessTest, SetWithMulti) { + ASSERT_EQ("", processes[i]->GetOutput()); + } + ++ subprocs_.ResetTokenAvailable(); + while (!processes[0]->Done() || !processes[1]->Done() || + !processes[2]->Done()) { + ASSERT_GT(subprocs_.running_.size(), 0u); +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } +- ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + ASSERT_EQ(0u, subprocs_.running_.size()); + ASSERT_EQ(3u, subprocs_.finished_.size()); + +@@ -237,8 +252,10 @@ TEST_F(SubprocessTest, SetWithLots) { + ASSERT_NE((Subprocess *) 0, subproc); + procs.push_back(subproc); + } ++ subprocs_.ResetTokenAvailable(); + while (!subprocs_.running_.empty()) +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + for (size_t i = 0; i < procs.size(); ++i) { + ASSERT_EQ(ExitSuccess, procs[i]->Finish()); + ASSERT_NE("", procs[i]->GetOutput()); +@@ -254,9 +271,11 @@ TEST_F(SubprocessTest, SetWithLots) { + // that stdin is closed. + TEST_F(SubprocessTest, ReadStdin) { + Subprocess* subproc = subprocs_.Add("cat -"); ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_EQ(false, subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_EQ(1u, subprocs_.finished_.size()); + } +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index a8f9b7139d..396bb7d874 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -33,6 +33,7 @@ struct GNUmakeTokenPool : public TokenPool { + virtual void Reserve(); + virtual void Release(); + virtual void Clear(); ++ virtual int GetMonitorFd(); + + bool Setup(); + +@@ -201,6 +202,10 @@ void GNUmakeTokenPool::Clear() { + Return(); + } + ++int GNUmakeTokenPool::GetMonitorFd() { ++ return(rfd_); ++} ++ + struct TokenPool *TokenPool::Get(void) { + GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; + if (tokenpool->Setup()) +diff --git a/src/tokenpool.h b/src/tokenpool.h +index f560b1083b..301e1998ee 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -21,6 +21,12 @@ struct TokenPool { + virtual void Release() = 0; + virtual void Clear() = 0; + ++#ifdef _WIN32 ++ // @TODO ++#else ++ virtual int GetMonitorFd() = 0; ++#endif ++ + // returns NULL if token pool is not available + static struct TokenPool *Get(void); + }; + +From d09f3d77821b3b1fdf09fc0ef8e814907675eafb Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Sun, 12 Nov 2017 16:58:55 +0200 +Subject: [PATCH 03/11] Ignore jobserver when -jN is forced on command line + +This emulates the behaviour of GNU make. + +- add parallelism_from_cmdline flag to build configuration +- set the flag when -jN is given on command line +- pass the flag to TokenPool::Get() +- GNUmakeTokenPool::Setup() + * prints a warning when the flag is true and jobserver was detected + * returns false, i.e. jobserver will be ignored +- ignore config.parallelism in CanRunMore() when we have a valid + TokenPool, because it gets always initialized to a default when not + given on the command line +--- + src/build.cc | 10 ++++++---- + src/build.h | 4 +++- + src/ninja.cc | 1 + + src/tokenpool-gnu-make.cc | 34 +++++++++++++++++++--------------- + src/tokenpool-none.cc | 4 ++-- + src/tokenpool.h | 4 ++-- + 6 files changed, 33 insertions(+), 24 deletions(-) + +diff --git a/src/build.cc b/src/build.cc +index a25c349050..406a84ec39 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -470,7 +470,7 @@ struct RealCommandRunner : public CommandRunner { + }; + + RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { +- tokens_ = TokenPool::Get(); ++ tokens_ = TokenPool::Get(config_.parallelism_from_cmdline); + } + + RealCommandRunner::~RealCommandRunner() { +@@ -492,9 +492,11 @@ void RealCommandRunner::Abort() { + } + + bool RealCommandRunner::CanRunMore() const { +- size_t subproc_number = +- subprocs_.running_.size() + subprocs_.finished_.size(); +- return (int)subproc_number < config_.parallelism ++ bool parallelism_limit_not_reached = ++ tokens_ || // ignore config_.parallelism ++ ((int) (subprocs_.running_.size() + ++ subprocs_.finished_.size()) < config_.parallelism); ++ return parallelism_limit_not_reached + && (subprocs_.running_.empty() || + (config_.max_load_average <= 0.0f || + GetLoadAverage() < config_.max_load_average)); +diff --git a/src/build.h b/src/build.h +index 35c7b97d12..dfde576573 100644 +--- a/src/build.h ++++ b/src/build.h +@@ -159,7 +159,8 @@ struct CommandRunner { + + /// Options (e.g. verbosity, parallelism) passed to a build. + struct BuildConfig { +- BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1), ++ BuildConfig() : verbosity(NORMAL), dry_run(false), ++ parallelism(1), parallelism_from_cmdline(false), + failures_allowed(1), max_load_average(-0.0f) {} + + enum Verbosity { +@@ -171,6 +172,7 @@ struct BuildConfig { + Verbosity verbosity; + bool dry_run; + int parallelism; ++ bool parallelism_from_cmdline; + int failures_allowed; + /// The maximum load average we must not exceed. A negative value + /// means that we do not have any limit. +diff --git a/src/ninja.cc b/src/ninja.cc +index df39ba92d1..d904c56c4e 100644 +--- a/src/ninja.cc ++++ b/src/ninja.cc +@@ -1447,6 +1447,7 @@ int ReadFlags(int* argc, char*** argv, + // We want to run N jobs in parallel. For N = 0, INT_MAX + // is close enough to infinite for most sane builds. + config->parallelism = value > 0 ? value : INT_MAX; ++ config->parallelism_from_cmdline = true; + deferGuessParallelism.needGuess = false; + break; + } +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index 396bb7d874..af4be05a31 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -1,4 +1,4 @@ +-// Copyright 2016 Google Inc. All Rights Reserved. ++// Copyright 2016-2017 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -35,7 +35,7 @@ struct GNUmakeTokenPool : public TokenPool { + virtual void Clear(); + virtual int GetMonitorFd(); + +- bool Setup(); ++ bool Setup(bool ignore); + + private: + int available_; +@@ -100,7 +100,7 @@ bool GNUmakeTokenPool::SetAlarmHandler() { + } + } + +-bool GNUmakeTokenPool::Setup() { ++bool GNUmakeTokenPool::Setup(bool ignore) { + const char *value = getenv("MAKEFLAGS"); + if (value) { + // GNU make <= 4.1 +@@ -109,16 +109,20 @@ bool GNUmakeTokenPool::Setup() { + if (!jobserver) + jobserver = strstr(value, "--jobserver-auth="); + if (jobserver) { +- int rfd = -1; +- int wfd = -1; +- if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && +- CheckFd(rfd) && +- CheckFd(wfd) && +- SetAlarmHandler()) { +- printf("ninja: using GNU make jobserver.\n"); +- rfd_ = rfd; +- wfd_ = wfd; +- return true; ++ if (ignore) { ++ printf("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); ++ } else { ++ int rfd = -1; ++ int wfd = -1; ++ if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && ++ CheckFd(rfd) && ++ CheckFd(wfd) && ++ SetAlarmHandler()) { ++ printf("ninja: using GNU make jobserver.\n"); ++ rfd_ = rfd; ++ wfd_ = wfd; ++ return true; ++ } + } + } + } +@@ -206,9 +210,9 @@ int GNUmakeTokenPool::GetMonitorFd() { + return(rfd_); + } + +-struct TokenPool *TokenPool::Get(void) { ++struct TokenPool *TokenPool::Get(bool ignore) { + GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; +- if (tokenpool->Setup()) ++ if (tokenpool->Setup(ignore)) + return tokenpool; + else + delete tokenpool; +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +index 602b3316f5..199b22264b 100644 +--- a/src/tokenpool-none.cc ++++ b/src/tokenpool-none.cc +@@ -1,4 +1,4 @@ +-// Copyright 2016 Google Inc. All Rights Reserved. ++// Copyright 2016-2017 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -22,6 +22,6 @@ + #include + + // No-op TokenPool implementation +-struct TokenPool *TokenPool::Get(void) { ++struct TokenPool *TokenPool::Get(bool ignore) { + return NULL; + } +diff --git a/src/tokenpool.h b/src/tokenpool.h +index 301e1998ee..878a0933c2 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -1,4 +1,4 @@ +-// Copyright 2016 Google Inc. All Rights Reserved. ++// Copyright 2016-2017 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -28,5 +28,5 @@ struct TokenPool { + #endif + + // returns NULL if token pool is not available +- static struct TokenPool *Get(void); ++ static struct TokenPool *Get(bool ignore); + }; + +From dfe4ca753caee65bf9041e2b4e883dfa172a5c6a Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Sun, 12 Nov 2017 18:04:12 +0200 +Subject: [PATCH 04/11] Honor -lN from MAKEFLAGS + +This emulates the behaviour of GNU make. + +- build: make a copy of max_load_average and pass it to TokenPool. +- GNUmakeTokenPool: if we detect a jobserver and a valid -lN argument in + MAKEFLAGS then set max_load_average to N. +--- + src/build.cc | 10 +++++++--- + src/tokenpool-gnu-make.cc | 19 +++++++++++++++---- + src/tokenpool-none.cc | 2 +- + src/tokenpool.h | 2 +- + 4 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/src/build.cc b/src/build.cc +index 406a84ec39..9e6272d035 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -464,13 +464,17 @@ struct RealCommandRunner : public CommandRunner { + virtual void Abort(); + + const BuildConfig& config_; ++ // copy of config_.max_load_average; can be modified by TokenPool setup ++ double max_load_average_; + SubprocessSet subprocs_; + TokenPool *tokens_; + map subproc_to_edge_; + }; + + RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { +- tokens_ = TokenPool::Get(config_.parallelism_from_cmdline); ++ max_load_average_ = config.max_load_average; ++ tokens_ = TokenPool::Get(config_.parallelism_from_cmdline, ++ max_load_average_); + } + + RealCommandRunner::~RealCommandRunner() { +@@ -498,8 +502,8 @@ bool RealCommandRunner::CanRunMore() const { + subprocs_.finished_.size()) < config_.parallelism); + return parallelism_limit_not_reached + && (subprocs_.running_.empty() || +- (config_.max_load_average <= 0.0f || +- GetLoadAverage() < config_.max_load_average)); ++ (max_load_average_ <= 0.0f || ++ GetLoadAverage() < max_load_average_)); + } + + bool RealCommandRunner::AcquireToken() { +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index af4be05a31..fb654c4d88 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -35,7 +35,7 @@ struct GNUmakeTokenPool : public TokenPool { + virtual void Clear(); + virtual int GetMonitorFd(); + +- bool Setup(bool ignore); ++ bool Setup(bool ignore, double& max_load_average); + + private: + int available_; +@@ -100,7 +100,7 @@ bool GNUmakeTokenPool::SetAlarmHandler() { + } + } + +-bool GNUmakeTokenPool::Setup(bool ignore) { ++bool GNUmakeTokenPool::Setup(bool ignore, double& max_load_average) { + const char *value = getenv("MAKEFLAGS"); + if (value) { + // GNU make <= 4.1 +@@ -118,9 +118,20 @@ bool GNUmakeTokenPool::Setup(bool ignore) { + CheckFd(rfd) && + CheckFd(wfd) && + SetAlarmHandler()) { ++ const char *l_arg = strstr(value, " -l"); ++ int load_limit = -1; ++ + printf("ninja: using GNU make jobserver.\n"); + rfd_ = rfd; + wfd_ = wfd; ++ ++ // translate GNU make -lN to ninja -lN ++ if (l_arg && ++ (sscanf(l_arg + 3, "%d ", &load_limit) == 1) && ++ (load_limit > 0)) { ++ max_load_average = load_limit; ++ } ++ + return true; + } + } +@@ -210,9 +221,9 @@ int GNUmakeTokenPool::GetMonitorFd() { + return(rfd_); + } + +-struct TokenPool *TokenPool::Get(bool ignore) { ++struct TokenPool *TokenPool::Get(bool ignore, double& max_load_average) { + GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; +- if (tokenpool->Setup(ignore)) ++ if (tokenpool->Setup(ignore, max_load_average)) + return tokenpool; + else + delete tokenpool; +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +index 199b22264b..e8e25426c3 100644 +--- a/src/tokenpool-none.cc ++++ b/src/tokenpool-none.cc +@@ -22,6 +22,6 @@ + #include + + // No-op TokenPool implementation +-struct TokenPool *TokenPool::Get(bool ignore) { ++struct TokenPool *TokenPool::Get(bool ignore, double& max_load_average) { + return NULL; + } +diff --git a/src/tokenpool.h b/src/tokenpool.h +index 878a0933c2..f9e8cc2ee0 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -28,5 +28,5 @@ struct TokenPool { + #endif + + // returns NULL if token pool is not available +- static struct TokenPool *Get(bool ignore); ++ static struct TokenPool *Get(bool ignore, double& max_load_average); + }; + +From 1c10047fc6a3269ba42839da19361e09cbc06ff0 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Wed, 6 Dec 2017 22:14:21 +0200 +Subject: [PATCH 05/11] Use LinePrinter for TokenPool messages + +- replace printf() with calls to LinePrinter +- print GNU make jobserver message only when verbose build is requested +--- + src/build.cc | 1 + + src/tokenpool-gnu-make.cc | 22 ++++++++++++++++------ + src/tokenpool-none.cc | 4 +++- + src/tokenpool.h | 4 +++- + 4 files changed, 23 insertions(+), 8 deletions(-) + +diff --git a/src/build.cc b/src/build.cc +index 9e6272d035..662e4bd7be 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -474,6 +474,7 @@ struct RealCommandRunner : public CommandRunner { + RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { + max_load_average_ = config.max_load_average; + tokens_ = TokenPool::Get(config_.parallelism_from_cmdline, ++ config_.verbosity == BuildConfig::VERBOSE, + max_load_average_); + } + +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index fb654c4d88..b0d3e6ebc4 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -23,6 +23,8 @@ + #include + #include + ++#include "line_printer.h" ++ + // TokenPool implementation for GNU make jobserver + // (http://make.mad-scientist.net/papers/jobserver-implementation/) + struct GNUmakeTokenPool : public TokenPool { +@@ -35,7 +37,7 @@ struct GNUmakeTokenPool : public TokenPool { + virtual void Clear(); + virtual int GetMonitorFd(); + +- bool Setup(bool ignore, double& max_load_average); ++ bool Setup(bool ignore, bool verbose, double& max_load_average); + + private: + int available_; +@@ -100,7 +102,9 @@ bool GNUmakeTokenPool::SetAlarmHandler() { + } + } + +-bool GNUmakeTokenPool::Setup(bool ignore, double& max_load_average) { ++bool GNUmakeTokenPool::Setup(bool ignore, ++ bool verbose, ++ double& max_load_average) { + const char *value = getenv("MAKEFLAGS"); + if (value) { + // GNU make <= 4.1 +@@ -109,8 +113,10 @@ bool GNUmakeTokenPool::Setup(bool ignore, double& max_load_average) { + if (!jobserver) + jobserver = strstr(value, "--jobserver-auth="); + if (jobserver) { ++ LinePrinter printer; ++ + if (ignore) { +- printf("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); ++ printer.PrintOnNewLine("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); + } else { + int rfd = -1; + int wfd = -1; +@@ -121,7 +127,9 @@ bool GNUmakeTokenPool::Setup(bool ignore, double& max_load_average) { + const char *l_arg = strstr(value, " -l"); + int load_limit = -1; + +- printf("ninja: using GNU make jobserver.\n"); ++ if (verbose) { ++ printer.PrintOnNewLine("ninja: using GNU make jobserver.\n"); ++ } + rfd_ = rfd; + wfd_ = wfd; + +@@ -221,9 +229,11 @@ int GNUmakeTokenPool::GetMonitorFd() { + return(rfd_); + } + +-struct TokenPool *TokenPool::Get(bool ignore, double& max_load_average) { ++struct TokenPool *TokenPool::Get(bool ignore, ++ bool verbose, ++ double& max_load_average) { + GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; +- if (tokenpool->Setup(ignore, max_load_average)) ++ if (tokenpool->Setup(ignore, verbose, max_load_average)) + return tokenpool; + else + delete tokenpool; +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +index e8e25426c3..1c1c499c8d 100644 +--- a/src/tokenpool-none.cc ++++ b/src/tokenpool-none.cc +@@ -22,6 +22,8 @@ + #include + + // No-op TokenPool implementation +-struct TokenPool *TokenPool::Get(bool ignore, double& max_load_average) { ++struct TokenPool *TokenPool::Get(bool ignore, ++ bool verbose, ++ double& max_load_average) { + return NULL; + } +diff --git a/src/tokenpool.h b/src/tokenpool.h +index f9e8cc2ee0..4bf477f20c 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -28,5 +28,7 @@ struct TokenPool { + #endif + + // returns NULL if token pool is not available +- static struct TokenPool *Get(bool ignore, double& max_load_average); ++ static struct TokenPool *Get(bool ignore, ++ bool verbose, ++ double& max_load_average); + }; + +From fdbf68416e3574add3bffd0b637d0694fbaba320 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Sat, 7 Apr 2018 17:11:21 +0300 +Subject: [PATCH 06/11] Prepare PR for merging + +- fix Windows build error in no-op TokenPool implementation +- improve Acquire() to block for a maximum of 100ms +- address review comments +--- + src/build.h | 2 ++ + src/tokenpool-gnu-make.cc | 53 +++++++++++++++++++++++++++++++++------ + src/tokenpool-none.cc | 7 +----- + 3 files changed, 49 insertions(+), 13 deletions(-) + +diff --git a/src/build.h b/src/build.h +index dfde576573..66ddefb888 100644 +--- a/src/build.h ++++ b/src/build.h +@@ -151,6 +151,8 @@ struct CommandRunner { + bool success() const { return status == ExitSuccess; } + }; + /// Wait for a command to complete, or return false if interrupted. ++ /// If more_ready is true then the optional TokenPool is monitored too ++ /// and we return when a token becomes available. + virtual bool WaitForCommand(Result* result, bool more_ready) = 0; + + virtual std::vector GetActiveEdges() { return std::vector(); } +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index b0d3e6ebc4..4132bb06d9 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -1,4 +1,4 @@ +-// Copyright 2016-2017 Google Inc. All Rights Reserved. ++// Copyright 2016-2018 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -153,6 +154,15 @@ bool GNUmakeTokenPool::Acquire() { + if (available_ > 0) + return true; + ++ // Please read ++ // ++ // http://make.mad-scientist.net/papers/jobserver-implementation/ ++ // ++ // for the reasoning behind the following code. ++ // ++ // Try to read one character from the pipe. Returns true on success. ++ // ++ // First check if read() would succeed without blocking. + #ifdef USE_PPOLL + pollfd pollfds[] = {{rfd_, POLLIN, 0}}; + int ret = poll(pollfds, 1, 0); +@@ -164,33 +174,62 @@ bool GNUmakeTokenPool::Acquire() { + int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); + #endif + if (ret > 0) { ++ // Handle potential race condition: ++ // - the above check succeeded, i.e. read() should not block ++ // - the character disappears before we call read() ++ // ++ // Create a duplicate of rfd_. The duplicate file descriptor dup_rfd_ ++ // can safely be closed by signal handlers without affecting rfd_. + dup_rfd_ = dup(rfd_); + + if (dup_rfd_ != -1) { + struct sigaction act, old_act; + int ret = 0; + ++ // Temporarily replace SIGCHLD handler with our own + memset(&act, 0, sizeof(act)); + act.sa_handler = CloseDupRfd; + if (sigaction(SIGCHLD, &act, &old_act) == 0) { +- char buf; +- +- // block until token read, child exits or timeout +- alarm(1); +- ret = read(dup_rfd_, &buf, 1); +- alarm(0); ++ struct itimerval timeout; ++ ++ // install a 100ms timeout that generates SIGALARM on expiration ++ memset(&timeout, 0, sizeof(timeout)); ++ timeout.it_value.tv_usec = 100 * 1000; // [ms] -> [usec] ++ if (setitimer(ITIMER_REAL, &timeout, NULL) == 0) { ++ char buf; ++ ++ // Now try to read() from dup_rfd_. Return values from read(): ++ // ++ // 1. token read -> 1 ++ // 2. pipe closed -> 0 ++ // 3. alarm expires -> -1 (EINTR) ++ // 4. child exits -> -1 (EINTR) ++ // 5. alarm expired before entering read() -> -1 (EBADF) ++ // 6. child exited before entering read() -> -1 (EBADF) ++ // 7. child exited before handler is installed -> go to 1 - 3 ++ ret = read(dup_rfd_, &buf, 1); ++ ++ // disarm timer ++ memset(&timeout, 0, sizeof(timeout)); ++ setitimer(ITIMER_REAL, &timeout, NULL); ++ } + + sigaction(SIGCHLD, &old_act, NULL); + } + + CloseDupRfd(0); + ++ // Case 1 from above list + if (ret > 0) { + available_++; + return true; + } + } + } ++ ++ // read() would block, i.e. no token available, ++ // cases 2-6 from above list or ++ // select() / poll() / dup() / sigaction() / setitimer() failed + return false; + } + +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +index 1c1c499c8d..4c592875b4 100644 +--- a/src/tokenpool-none.cc ++++ b/src/tokenpool-none.cc +@@ -1,4 +1,4 @@ +-// Copyright 2016-2017 Google Inc. All Rights Reserved. ++// Copyright 2016-2018 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -14,11 +14,6 @@ + + #include "tokenpool.h" + +-#include +-#include +-#include +-#include +-#include + #include + + // No-op TokenPool implementation + +From ec6220a0baf7d3a6eaf1a2b75bf8960ddfe24c2f Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Fri, 25 May 2018 00:17:07 +0300 +Subject: [PATCH 07/11] Add tests for TokenPool + +- TokenPool setup +- GetMonitorFd() API +- implicit token and tokens in jobserver pipe +- Acquire() / Reserve() / Release() protocol +- Clear() API +--- + configure.py | 1 + + src/tokenpool_test.cc | 198 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 199 insertions(+) + create mode 100644 src/tokenpool_test.cc + +diff --git a/configure.py b/configure.py +index db3492c93c..dc8a0066b7 100755 +--- a/configure.py ++++ b/configure.py +@@ -590,6 +590,7 @@ def has_re2c(): + 'string_piece_util_test', + 'subprocess_test', + 'test', ++ 'tokenpool_test', + 'util_test']: + objs += cxx(name, variables=cxxvariables) + if platform.is_windows(): +diff --git a/src/tokenpool_test.cc b/src/tokenpool_test.cc +new file mode 100644 +index 0000000000..6c89064ca4 +--- /dev/null ++++ b/src/tokenpool_test.cc +@@ -0,0 +1,198 @@ ++// Copyright 2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++#include "test.h" ++ ++#ifndef _WIN32 ++#include ++#include ++#include ++ ++#define ENVIRONMENT_CLEAR() unsetenv("MAKEFLAGS") ++#define ENVIRONMENT_INIT(v) setenv("MAKEFLAGS", v, true); ++#endif ++ ++namespace { ++ ++const double kLoadAverageDefault = -1.23456789; ++ ++struct TokenPoolTest : public testing::Test { ++ double load_avg_; ++ TokenPool *tokens_; ++#ifndef _WIN32 ++ char buf_[1024]; ++ int fds_[2]; ++#endif ++ ++ virtual void SetUp() { ++ load_avg_ = kLoadAverageDefault; ++ tokens_ = NULL; ++#ifndef _WIN32 ++ ENVIRONMENT_CLEAR(); ++ if (pipe(fds_) < 0) ++ ASSERT_TRUE(false); ++#endif ++ } ++ ++ void CreatePool(const char *format, bool ignore_jobserver) { ++#ifndef _WIN32 ++ if (format) { ++ sprintf(buf_, format, fds_[0], fds_[1]); ++ ENVIRONMENT_INIT(buf_); ++ } ++#endif ++ tokens_ = TokenPool::Get(ignore_jobserver, false, load_avg_); ++ } ++ ++ void CreateDefaultPool() { ++ CreatePool("foo --jobserver-auth=%d,%d bar", false); ++ } ++ ++ virtual void TearDown() { ++ if (tokens_) ++ delete tokens_; ++#ifndef _WIN32 ++ close(fds_[0]); ++ close(fds_[1]); ++ ENVIRONMENT_CLEAR(); ++#endif ++ } ++}; ++ ++} // anonymous namespace ++ ++// verifies none implementation ++TEST_F(TokenPoolTest, NoTokenPool) { ++ CreatePool(NULL, false); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++#ifndef _WIN32 ++TEST_F(TokenPoolTest, SuccessfulOldSetup) { ++ // GNUmake <= 4.1 ++ CreatePool("foo --jobserver-fds=%d,%d bar", false); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, SuccessfulNewSetup) { ++ // GNUmake => 4.2 ++ CreateDefaultPool(); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, IgnoreWithJN) { ++ CreatePool("foo --jobserver-auth=%d,%d bar", true); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, HonorLN) { ++ CreatePool("foo -l9 --jobserver-auth=%d,%d bar", false); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(9.0, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, MonitorFD) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_EQ(fds_[0], tokens_->GetMonitorFd()); ++} ++ ++TEST_F(TokenPoolTest, ImplicitToken) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++} ++ ++TEST_F(TokenPoolTest, TwoTokens) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // jobserver offers 2nd token ++ ASSERT_EQ(1u, write(fds_[1], "T", 1)); ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // release 2nd token ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // release implict token - must return 2nd token back to jobserver ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // there must be one token in the pipe ++ EXPECT_EQ(1u, read(fds_[0], buf_, sizeof(buf_))); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++} ++ ++TEST_F(TokenPoolTest, Clear) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // jobserver offers 2nd & 3rd token ++ ASSERT_EQ(2u, write(fds_[1], "TT", 2)); ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ tokens_->Clear(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // there must be two tokens in the pipe ++ EXPECT_EQ(2u, read(fds_[0], buf_, sizeof(buf_))); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++} ++#endif + +From e59d8858327126d1593fd0b8e607975a79072e92 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Thu, 24 May 2018 18:52:45 +0300 +Subject: [PATCH 08/11] Add tests for subprocess module + +- add TokenPoolTest stub to provide TokenPool::GetMonitorFd() +- add two tests + * both tests set up a dummy GNUmake jobserver pipe + * both tests call DoWork() with TokenPoolTest + * test 1: verify that DoWork() detects when a token is available + * test 2: verify that DoWork() works as before without a token +- the tests are not compiled in under Windows +--- + src/subprocess_test.cc | 76 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + +diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc +index 4bc8083e26..6264c8bf11 100644 +--- a/src/subprocess_test.cc ++++ b/src/subprocess_test.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include "test.h" + +@@ -34,8 +35,23 @@ const char* kSimpleCommand = "cmd /c dir \\"; + const char* kSimpleCommand = "ls /"; + #endif + ++struct TokenPoolTest : public TokenPool { ++ bool Acquire() { return false; } ++ void Reserve() {} ++ void Release() {} ++ void Clear() {} ++ ++#ifdef _WIN32 ++ // @TODO ++#else ++ int _fd; ++ int GetMonitorFd() { return _fd; } ++#endif ++}; ++ + struct SubprocessTest : public testing::Test { + SubprocessSet subprocs_; ++ TokenPoolTest tokens_; + }; + + } // anonymous namespace +@@ -280,3 +296,63 @@ TEST_F(SubprocessTest, ReadStdin) { + ASSERT_EQ(1u, subprocs_.finished_.size()); + } + #endif // _WIN32 ++ ++// @TODO: remove once TokenPool implementation for Windows is available ++#ifndef _WIN32 ++TEST_F(SubprocessTest, TokenAvailable) { ++ Subprocess* subproc = subprocs_.Add(kSimpleCommand); ++ ASSERT_NE((Subprocess *) 0, subproc); ++ ++ // simulate GNUmake jobserver pipe with 1 token ++ int fds[2]; ++ ASSERT_EQ(0u, pipe(fds)); ++ tokens_._fd = fds[0]; ++ ASSERT_EQ(1u, write(fds[1], "T", 1)); ++ ++ subprocs_.ResetTokenAvailable(); ++ subprocs_.DoWork(&tokens_); ++ ++ EXPECT_TRUE(subprocs_.IsTokenAvailable()); ++ EXPECT_EQ(0u, subprocs_.finished_.size()); ++ ++ // remove token to let DoWork() wait for command again ++ char token; ++ ASSERT_EQ(1u, read(fds[0], &token, 1)); ++ ++ while (!subproc->Done()) { ++ subprocs_.DoWork(&tokens_); ++ } ++ ++ close(fds[1]); ++ close(fds[0]); ++ ++ EXPECT_EQ(ExitSuccess, subproc->Finish()); ++ EXPECT_NE("", subproc->GetOutput()); ++ ++ EXPECT_EQ(1u, subprocs_.finished_.size()); ++} ++ ++TEST_F(SubprocessTest, TokenNotAvailable) { ++ Subprocess* subproc = subprocs_.Add(kSimpleCommand); ++ ASSERT_NE((Subprocess *) 0, subproc); ++ ++ // simulate GNUmake jobserver pipe with 0 tokens ++ int fds[2]; ++ ASSERT_EQ(0u, pipe(fds)); ++ tokens_._fd = fds[0]; ++ ++ subprocs_.ResetTokenAvailable(); ++ while (!subproc->Done()) { ++ subprocs_.DoWork(&tokens_); ++ } ++ ++ close(fds[1]); ++ close(fds[0]); ++ ++ EXPECT_FALSE(subprocs_.IsTokenAvailable()); ++ EXPECT_EQ(ExitSuccess, subproc->Finish()); ++ EXPECT_NE("", subproc->GetOutput()); ++ ++ EXPECT_EQ(1u, subprocs_.finished_.size()); ++} ++#endif // _WIN32 + +From 0145e2d4db64ea6c21aeb371928e4071f65164eb Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Sat, 26 May 2018 23:17:51 +0300 +Subject: [PATCH 09/11] Add tests for build module + +Add tests that verify the token functionality of the builder main loop. +We replace the default fake command runner with a special version where +the tests can control each call to AcquireToken(), CanRunMore() and +WaitForCommand(). +--- + src/build_test.cc | 364 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 364 insertions(+) + +diff --git a/src/build_test.cc b/src/build_test.cc +index 7a5ff4015a..dd41dfbe1d 100644 +--- a/src/build_test.cc ++++ b/src/build_test.cc +@@ -15,6 +15,7 @@ + #include "build.h" + + #include ++#include + + #include "build_log.h" + #include "deps_log.h" +@@ -3990,3 +3991,366 @@ TEST_F(BuildTest, ValidationWithCircularDependency) { + EXPECT_FALSE(builder_.AddTarget("out", &err)); + EXPECT_EQ("dependency cycle: validate -> validate_in -> validate", err); + } ++ ++/// The token tests are concerned with the main loop functionality when ++// the CommandRunner has an active TokenPool. It is therefore intentional ++// that the plan doesn't complete and that builder_.Build() returns false! ++ ++/// Fake implementation of CommandRunner that simulates a TokenPool ++struct FakeTokenCommandRunner : public CommandRunner { ++ explicit FakeTokenCommandRunner() {} ++ ++ // CommandRunner impl ++ virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); ++ virtual bool StartCommand(Edge* edge); ++ virtual bool WaitForCommand(Result* result, bool more_ready); ++ virtual vector GetActiveEdges(); ++ virtual void Abort(); ++ ++ vector commands_ran_; ++ vector edges_; ++ ++ vector acquire_token_; ++ vector can_run_more_; ++ vector wait_for_command_; ++}; ++ ++bool FakeTokenCommandRunner::CanRunMore() const { ++ if (can_run_more_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::CanRunMore()"); ++ return false; ++ } ++ ++ bool result = can_run_more_[0]; ++ ++ // Unfortunately CanRunMore() isn't "const" for tests ++ const_cast(this)->can_run_more_.erase( ++ const_cast(this)->can_run_more_.begin() ++ ); ++ ++ return result; ++} ++ ++bool FakeTokenCommandRunner::AcquireToken() { ++ if (acquire_token_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::AcquireToken()"); ++ return false; ++ } ++ ++ bool result = acquire_token_[0]; ++ acquire_token_.erase(acquire_token_.begin()); ++ return result; ++} ++ ++bool FakeTokenCommandRunner::StartCommand(Edge* edge) { ++ commands_ran_.push_back(edge->EvaluateCommand()); ++ edges_.push_back(edge); ++ return true; ++} ++ ++bool FakeTokenCommandRunner::WaitForCommand(Result* result, bool more_ready) { ++ if (wait_for_command_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::WaitForCommand()"); ++ return false; ++ } ++ ++ bool expected = wait_for_command_[0]; ++ if (expected != more_ready) { ++ EXPECT_EQ(expected, more_ready); ++ return false; ++ } ++ wait_for_command_.erase(wait_for_command_.begin()); ++ ++ if (edges_.size() == 0) ++ return false; ++ ++ Edge* edge = edges_[0]; ++ result->edge = edge; ++ ++ if (more_ready && ++ (edge->rule().name() == "token-available")) { ++ result->status = ExitTokenAvailable; ++ } else { ++ edges_.erase(edges_.begin()); ++ result->status = ExitSuccess; ++ } ++ ++ return true; ++} ++ ++vector FakeTokenCommandRunner::GetActiveEdges() { ++ return edges_; ++} ++ ++void FakeTokenCommandRunner::Abort() { ++ edges_.clear(); ++} ++ ++struct BuildTokenTest : public BuildTest { ++ virtual void SetUp(); ++ virtual void TearDown(); ++ ++ FakeTokenCommandRunner token_command_runner_; ++ ++ void ExpectAcquireToken(int count, ...); ++ void ExpectCanRunMore(int count, ...); ++ void ExpectWaitForCommand(int count, ...); ++ ++private: ++ void EnqueueBooleans(vector& booleans, int count, va_list ao); ++}; ++ ++void BuildTokenTest::SetUp() { ++ BuildTest::SetUp(); ++ ++ // replace FakeCommandRunner with FakeTokenCommandRunner ++ builder_.command_runner_.release(); ++ builder_.command_runner_.reset(&token_command_runner_); ++} ++void BuildTokenTest::TearDown() { ++ EXPECT_EQ(0u, token_command_runner_.acquire_token_.size()); ++ EXPECT_EQ(0u, token_command_runner_.can_run_more_.size()); ++ EXPECT_EQ(0u, token_command_runner_.wait_for_command_.size()); ++ ++ BuildTest::TearDown(); ++} ++ ++void BuildTokenTest::ExpectAcquireToken(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.acquire_token_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::ExpectCanRunMore(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.can_run_more_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::ExpectWaitForCommand(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.wait_for_command_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::EnqueueBooleans(vector& booleans, int count, va_list ap) { ++ while (count--) { ++ int value = va_arg(ap, int); ++ booleans.push_back(!!value); // force bool ++ } ++} ++ ++TEST_F(BuildTokenTest, CompleteNoWork) { ++ // plan should not execute anything ++ string err; ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); ++} ++ ++TEST_F(BuildTokenTest, DoNotAquireToken) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // pretend we can't run anything ++ ExpectCanRunMore(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); ++} ++ ++TEST_F(BuildTokenTest, DoNotStartWithoutToken) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // we could run a command but do not have a token for it ++ ExpectCanRunMore(1, true); ++ ExpectAcquireToken(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); ++} ++ ++TEST_F(BuildTokenTest, CompleteOneStep) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(1, true); ++ ExpectAcquireToken(1, true); ++ // block and wait for command to finalize ++ ExpectWaitForCommand(1, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1"); ++} ++ ++TEST_F(BuildTokenTest, AcquireOneToken) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(3, true, false, false); ++ ExpectAcquireToken(1, true); ++ // block and wait for command to finalize ++ ExpectWaitForCommand(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ // any of the two dependencies could have been executed ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1" || ++ token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"); ++} ++ ++TEST_F(BuildTokenTest, WantTwoTokens) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(3, true, true, false); ++ ExpectAcquireToken(2, true, false); ++ // wait for command to finalize or token to become available ++ ExpectWaitForCommand(1, true); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ // any of the two dependencies could have been executed ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1" || ++ token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"); ++} ++ ++TEST_F(BuildTokenTest, CompleteTwoSteps) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"build out1: cat in1\n" ++"build out2: cat out1\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out2", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of two commands ++ ExpectCanRunMore(2, true, true); ++ ExpectAcquireToken(2, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(2, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(2u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > out1"); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[1] == "cat out1 > out2"); ++} ++ ++TEST_F(BuildTokenTest, TwoCommandsInParallel) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"rule token-available\n" ++" command = cat $in > $out\n" ++"build out1: token-available in1\n" ++"build out2: token-available in2\n" ++"build out12: cat out1 out2\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out12", &err)); ++ ASSERT_EQ("", err); ++ ++ // 1st command: token available -> allow running ++ // 2nd command: no token available but becomes available later ++ ExpectCanRunMore(4, true, true, true, false); ++ ExpectAcquireToken(3, true, false, true); ++ // 1st call waits for command to finalize or token to become available ++ // 2nd call waits for command to finalize ++ // 3rd call waits for command to finalize ++ ExpectWaitForCommand(3, true, false, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(2u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > out1" && ++ token_command_runner_.commands_ran_[1] == "cat in2 > out2") || ++ (token_command_runner_.commands_ran_[0] == "cat in2 > out2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > out1")); ++} ++ ++TEST_F(BuildTokenTest, CompleteThreeStepsSerial) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of all commands ++ ExpectCanRunMore(4, true, true, true, true); ++ ExpectAcquireToken(4, true, false, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(3, true, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(3u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > cat1" && ++ token_command_runner_.commands_ran_[1] == "cat in1 in2 > cat2") || ++ (token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > cat1" )); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[2] == "cat cat1 cat2 > cat12"); ++} ++ ++TEST_F(BuildTokenTest, CompleteThreeStepsParallel) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"rule token-available\n" ++" command = cat $in > $out\n" ++"build out1: token-available in1\n" ++"build out2: token-available in2\n" ++"build out12: cat out1 out2\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of all commands ++ ExpectCanRunMore(4, true, true, true, true); ++ ExpectAcquireToken(4, true, false, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(4, true, false, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(3u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > out1" && ++ token_command_runner_.commands_ran_[1] == "cat in2 > out2") || ++ (token_command_runner_.commands_ran_[0] == "cat in2 > out2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > out1")); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[2] == "cat out1 out2 > out12"); ++} + +From f016e5430c9123d34a73ea7ad28693b20ee59d6d Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Mon, 8 Oct 2018 17:47:50 +0300 +Subject: [PATCH 10/11] Add Win32 implementation for GNUmakeTokenPool + +GNU make uses a semaphore as jobserver protocol on Win32. See also + + https://www.gnu.org/software/make/manual/html_node/Windows-Jobserver.html + +Usage is pretty simple and straightforward, i.e. WaitForSingleObject() +to obtain a token and ReleaseSemaphore() to return it. + +Unfortunately subprocess-win32.cc uses an I/O completion port (IOCP). +IOCPs aren't waitable objects, i.e. we can't use WaitForMultipleObjects() +to wait on the IOCP and the token semaphore at the same time. + +Therefore GNUmakeTokenPoolWin32 creates a child thread that waits on the +token semaphore and posts a dummy I/O completion status on the IOCP when +it was able to obtain a token. That unblocks SubprocessSet::DoWork() and +it can then check if a token became available or not. + +- split existing GNUmakeTokenPool into common and platform bits +- add GNUmakeTokenPool interface +- move the Posix bits to GNUmakeTokenPoolPosix +- add the Win32 bits as GNUmakeTokenPoolWin32 +- move Setup() method up to TokenPool interface +- update Subprocess & TokenPool tests accordingly +--- + configure.py | 8 +- + src/build.cc | 11 +- + src/subprocess-win32.cc | 9 ++ + src/subprocess_test.cc | 34 ++++- + src/tokenpool-gnu-make-posix.cc | 203 +++++++++++++++++++++++++++ + src/tokenpool-gnu-make-win32.cc | 237 ++++++++++++++++++++++++++++++++ + src/tokenpool-gnu-make.cc | 203 ++------------------------- + src/tokenpool-gnu-make.h | 40 ++++++ + src/tokenpool-none.cc | 4 +- + src/tokenpool.h | 18 ++- + src/tokenpool_test.cc | 113 ++++++++++++--- + 11 files changed, 653 insertions(+), 227 deletions(-) + create mode 100644 src/tokenpool-gnu-make-posix.cc + create mode 100644 src/tokenpool-gnu-make-win32.cc + create mode 100644 src/tokenpool-gnu-make.h + +diff --git a/configure.py b/configure.py +index dc8a0066b7..a239b90eef 100755 +--- a/configure.py ++++ b/configure.py +@@ -517,12 +517,13 @@ def has_re2c(): + 'state', + 'status', + 'string_piece_util', ++ 'tokenpool-gnu-make', + 'util', + 'version']: + objs += cxx(name, variables=cxxvariables) + if platform.is_windows(): + for name in ['subprocess-win32', +- 'tokenpool-none', ++ 'tokenpool-gnu-make-win32', + 'includes_normalize-win32', + 'msvc_helper-win32', + 'msvc_helper_main-win32']: +@@ -531,8 +532,9 @@ def has_re2c(): + objs += cxx('minidump-win32', variables=cxxvariables) + objs += cc('getopt') + else: +- objs += cxx('subprocess-posix') +- objs += cxx('tokenpool-gnu-make') ++ for name in ['subprocess-posix', ++ 'tokenpool-gnu-make-posix']: ++ objs += cxx(name) + if platform.is_aix(): + objs += cc('getopt') + if platform.is_msvc(): +diff --git a/src/build.cc b/src/build.cc +index 662e4bd7be..20c3bdc2a0 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -473,9 +473,14 @@ struct RealCommandRunner : public CommandRunner { + + RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { + max_load_average_ = config.max_load_average; +- tokens_ = TokenPool::Get(config_.parallelism_from_cmdline, +- config_.verbosity == BuildConfig::VERBOSE, +- max_load_average_); ++ if ((tokens_ = TokenPool::Get()) != NULL) { ++ if (!tokens_->Setup(config_.parallelism_from_cmdline, ++ config_.verbosity == BuildConfig::VERBOSE, ++ max_load_average_)) { ++ delete tokens_; ++ tokens_ = NULL; ++ } ++ } + } + + RealCommandRunner::~RealCommandRunner() { +diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc +index 66d2c2c430..ce3e2c20a4 100644 +--- a/src/subprocess-win32.cc ++++ b/src/subprocess-win32.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include + #include +@@ -256,6 +257,9 @@ bool SubprocessSet::DoWork(struct TokenPool* tokens) { + Subprocess* subproc; + OVERLAPPED* overlapped; + ++ if (tokens) ++ tokens->WaitForTokenAvailability(ioport_); ++ + if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc, + &overlapped, INFINITE)) { + if (GetLastError() != ERROR_BROKEN_PIPE) +@@ -266,6 +270,11 @@ bool SubprocessSet::DoWork(struct TokenPool* tokens) { + // delivered by NotifyInterrupted above. + return true; + ++ if (tokens && tokens->TokenIsAvailable((ULONG_PTR)subproc)) { ++ token_available_ = true; ++ return false; ++ } ++ + subproc->OnPipeReady(); + + if (subproc->Done()) { +diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc +index 6264c8bf11..f625963462 100644 +--- a/src/subprocess_test.cc ++++ b/src/subprocess_test.cc +@@ -40,9 +40,16 @@ struct TokenPoolTest : public TokenPool { + void Reserve() {} + void Release() {} + void Clear() {} ++ bool Setup(bool ignore_unused, bool verbose, double& max_load_average) { return false; } + + #ifdef _WIN32 +- // @TODO ++ bool _token_available; ++ void WaitForTokenAvailability(HANDLE ioport) { ++ if (_token_available) ++ // unblock GetQueuedCompletionStatus() ++ PostQueuedCompletionStatus(ioport, 0, (ULONG_PTR) this, NULL); ++ } ++ bool TokenIsAvailable(ULONG_PTR key) { return key == (ULONG_PTR) this; } + #else + int _fd; + int GetMonitorFd() { return _fd; } +@@ -297,34 +304,48 @@ TEST_F(SubprocessTest, ReadStdin) { + } + #endif // _WIN32 + +-// @TODO: remove once TokenPool implementation for Windows is available +-#ifndef _WIN32 + TEST_F(SubprocessTest, TokenAvailable) { + Subprocess* subproc = subprocs_.Add(kSimpleCommand); + ASSERT_NE((Subprocess *) 0, subproc); + + // simulate GNUmake jobserver pipe with 1 token ++#ifdef _WIN32 ++ tokens_._token_available = true; ++#else + int fds[2]; + ASSERT_EQ(0u, pipe(fds)); + tokens_._fd = fds[0]; + ASSERT_EQ(1u, write(fds[1], "T", 1)); ++#endif + + subprocs_.ResetTokenAvailable(); + subprocs_.DoWork(&tokens_); ++#ifdef _WIN32 ++ tokens_._token_available = false; ++ // we need to loop here as we have no conrol where the token ++ // I/O completion post ends up in the queue ++ while (!subproc->Done() && !subprocs_.IsTokenAvailable()) { ++ subprocs_.DoWork(&tokens_); ++ } ++#endif + + EXPECT_TRUE(subprocs_.IsTokenAvailable()); + EXPECT_EQ(0u, subprocs_.finished_.size()); + + // remove token to let DoWork() wait for command again ++#ifndef _WIN32 + char token; + ASSERT_EQ(1u, read(fds[0], &token, 1)); ++#endif + + while (!subproc->Done()) { + subprocs_.DoWork(&tokens_); + } + ++#ifndef _WIN32 + close(fds[1]); + close(fds[0]); ++#endif + + EXPECT_EQ(ExitSuccess, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -337,17 +358,23 @@ TEST_F(SubprocessTest, TokenNotAvailable) { + ASSERT_NE((Subprocess *) 0, subproc); + + // simulate GNUmake jobserver pipe with 0 tokens ++#ifdef _WIN32 ++ tokens_._token_available = false; ++#else + int fds[2]; + ASSERT_EQ(0u, pipe(fds)); + tokens_._fd = fds[0]; ++#endif + + subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { + subprocs_.DoWork(&tokens_); + } + ++#ifndef _WIN32 + close(fds[1]); + close(fds[0]); ++#endif + + EXPECT_FALSE(subprocs_.IsTokenAvailable()); + EXPECT_EQ(ExitSuccess, subproc->Finish()); +@@ -355,4 +382,3 @@ TEST_F(SubprocessTest, TokenNotAvailable) { + + EXPECT_EQ(1u, subprocs_.finished_.size()); + } +-#endif // _WIN32 +diff --git a/src/tokenpool-gnu-make-posix.cc b/src/tokenpool-gnu-make-posix.cc +new file mode 100644 +index 0000000000..70d84bfff7 +--- /dev/null ++++ b/src/tokenpool-gnu-make-posix.cc +@@ -0,0 +1,203 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool-gnu-make.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// TokenPool implementation for GNU make jobserver - POSIX implementation ++// (http://make.mad-scientist.net/papers/jobserver-implementation/) ++struct GNUmakeTokenPoolPosix : public GNUmakeTokenPool { ++ GNUmakeTokenPoolPosix(); ++ virtual ~GNUmakeTokenPoolPosix(); ++ ++ virtual int GetMonitorFd(); ++ ++ virtual const char *GetEnv(const char *name) { return getenv(name); }; ++ virtual bool ParseAuth(const char *jobserver); ++ virtual bool AcquireToken(); ++ virtual bool ReturnToken(); ++ ++ private: ++ int rfd_; ++ int wfd_; ++ ++ struct sigaction old_act_; ++ bool restore_; ++ ++ static int dup_rfd_; ++ static void CloseDupRfd(int signum); ++ ++ bool CheckFd(int fd); ++ bool SetAlarmHandler(); ++}; ++ ++GNUmakeTokenPoolPosix::GNUmakeTokenPoolPosix() : rfd_(-1), wfd_(-1), restore_(false) { ++} ++ ++GNUmakeTokenPoolPosix::~GNUmakeTokenPoolPosix() { ++ Clear(); ++ if (restore_) ++ sigaction(SIGALRM, &old_act_, NULL); ++} ++ ++bool GNUmakeTokenPoolPosix::CheckFd(int fd) { ++ if (fd < 0) ++ return false; ++ int ret = fcntl(fd, F_GETFD); ++ if (ret < 0) ++ return false; ++ return true; ++} ++ ++int GNUmakeTokenPoolPosix::dup_rfd_ = -1; ++ ++void GNUmakeTokenPoolPosix::CloseDupRfd(int signum) { ++ close(dup_rfd_); ++ dup_rfd_ = -1; ++} ++ ++bool GNUmakeTokenPoolPosix::SetAlarmHandler() { ++ struct sigaction act; ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGALRM, &act, &old_act_) < 0) { ++ perror("sigaction:"); ++ return(false); ++ } else { ++ restore_ = true; ++ return(true); ++ } ++} ++ ++bool GNUmakeTokenPoolPosix::ParseAuth(const char *jobserver) { ++ int rfd = -1; ++ int wfd = -1; ++ if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && ++ CheckFd(rfd) && ++ CheckFd(wfd) && ++ SetAlarmHandler()) { ++ rfd_ = rfd; ++ wfd_ = wfd; ++ return true; ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPoolPosix::AcquireToken() { ++ // Please read ++ // ++ // http://make.mad-scientist.net/papers/jobserver-implementation/ ++ // ++ // for the reasoning behind the following code. ++ // ++ // Try to read one character from the pipe. Returns true on success. ++ // ++ // First check if read() would succeed without blocking. ++#ifdef USE_PPOLL ++ pollfd pollfds[] = {{rfd_, POLLIN, 0}}; ++ int ret = poll(pollfds, 1, 0); ++#else ++ fd_set set; ++ struct timeval timeout = { 0, 0 }; ++ FD_ZERO(&set); ++ FD_SET(rfd_, &set); ++ int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); ++#endif ++ if (ret > 0) { ++ // Handle potential race condition: ++ // - the above check succeeded, i.e. read() should not block ++ // - the character disappears before we call read() ++ // ++ // Create a duplicate of rfd_. The duplicate file descriptor dup_rfd_ ++ // can safely be closed by signal handlers without affecting rfd_. ++ dup_rfd_ = dup(rfd_); ++ ++ if (dup_rfd_ != -1) { ++ struct sigaction act, old_act; ++ int ret = 0; ++ ++ // Temporarily replace SIGCHLD handler with our own ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGCHLD, &act, &old_act) == 0) { ++ struct itimerval timeout; ++ ++ // install a 100ms timeout that generates SIGALARM on expiration ++ memset(&timeout, 0, sizeof(timeout)); ++ timeout.it_value.tv_usec = 100 * 1000; // [ms] -> [usec] ++ if (setitimer(ITIMER_REAL, &timeout, NULL) == 0) { ++ char buf; ++ ++ // Now try to read() from dup_rfd_. Return values from read(): ++ // ++ // 1. token read -> 1 ++ // 2. pipe closed -> 0 ++ // 3. alarm expires -> -1 (EINTR) ++ // 4. child exits -> -1 (EINTR) ++ // 5. alarm expired before entering read() -> -1 (EBADF) ++ // 6. child exited before entering read() -> -1 (EBADF) ++ // 7. child exited before handler is installed -> go to 1 - 3 ++ ret = read(dup_rfd_, &buf, 1); ++ ++ // disarm timer ++ memset(&timeout, 0, sizeof(timeout)); ++ setitimer(ITIMER_REAL, &timeout, NULL); ++ } ++ ++ sigaction(SIGCHLD, &old_act, NULL); ++ } ++ ++ CloseDupRfd(0); ++ ++ // Case 1 from above list ++ if (ret > 0) ++ return true; ++ } ++ } ++ ++ // read() would block, i.e. no token available, ++ // cases 2-6 from above list or ++ // select() / poll() / dup() / sigaction() / setitimer() failed ++ return false; ++} ++ ++bool GNUmakeTokenPoolPosix::ReturnToken() { ++ const char buf = '+'; ++ while (1) { ++ int ret = write(wfd_, &buf, 1); ++ if (ret > 0) ++ return true; ++ if ((ret != -1) || (errno != EINTR)) ++ return false; ++ // write got interrupted - retry ++ } ++} ++ ++int GNUmakeTokenPoolPosix::GetMonitorFd() { ++ return(rfd_); ++} ++ ++struct TokenPool *TokenPool::Get() { ++ return new GNUmakeTokenPoolPosix; ++} +diff --git a/src/tokenpool-gnu-make-win32.cc b/src/tokenpool-gnu-make-win32.cc +new file mode 100644 +index 0000000000..2719f2c1fc +--- /dev/null ++++ b/src/tokenpool-gnu-make-win32.cc +@@ -0,0 +1,237 @@ ++// Copyright 2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool-gnu-make.h" ++ ++// always include first to make sure other headers do the correct thing... ++#include ++ ++#include ++#include ++#include ++ ++#include "util.h" ++ ++// TokenPool implementation for GNU make jobserver - Win32 implementation ++// (https://www.gnu.org/software/make/manual/html_node/Windows-Jobserver.html) ++struct GNUmakeTokenPoolWin32 : public GNUmakeTokenPool { ++ GNUmakeTokenPoolWin32(); ++ virtual ~GNUmakeTokenPoolWin32(); ++ ++ virtual void WaitForTokenAvailability(HANDLE ioport); ++ virtual bool TokenIsAvailable(ULONG_PTR key); ++ ++ virtual const char *GetEnv(const char *name); ++ virtual bool ParseAuth(const char *jobserver); ++ virtual bool AcquireToken(); ++ virtual bool ReturnToken(); ++ ++ private: ++ // Semaphore for GNU make jobserver protocol ++ HANDLE semaphore_jobserver_; ++ // Semaphore Child -> Parent ++ // - child releases it before entering wait on jobserver semaphore ++ // - parent blocks on it to know when child enters wait ++ HANDLE semaphore_enter_wait_; ++ // Semaphore Parent -> Child ++ // - parent releases it to allow child to restart loop ++ // - child blocks on it to know when to restart loop ++ HANDLE semaphore_restart_; ++ // set to false if child should exit loop and terminate thread ++ bool running_; ++ // child thread ++ HANDLE child_; ++ // I/O completion port from SubprocessSet ++ HANDLE ioport_; ++ ++ ++ DWORD SemaphoreThread(); ++ void ReleaseSemaphore(HANDLE semaphore); ++ void WaitForObject(HANDLE object); ++ static DWORD WINAPI SemaphoreThreadWrapper(LPVOID param); ++ static void NoopAPCFunc(ULONG_PTR param); ++}; ++ ++GNUmakeTokenPoolWin32::GNUmakeTokenPoolWin32() : semaphore_jobserver_(NULL), ++ semaphore_enter_wait_(NULL), ++ semaphore_restart_(NULL), ++ running_(false), ++ child_(NULL), ++ ioport_(NULL) { ++} ++ ++GNUmakeTokenPoolWin32::~GNUmakeTokenPoolWin32() { ++ Clear(); ++ CloseHandle(semaphore_jobserver_); ++ semaphore_jobserver_ = NULL; ++ ++ if (child_) { ++ // tell child thread to exit ++ running_ = false; ++ ReleaseSemaphore(semaphore_restart_); ++ ++ // wait for child thread to exit ++ WaitForObject(child_); ++ CloseHandle(child_); ++ child_ = NULL; ++ } ++ ++ if (semaphore_restart_) { ++ CloseHandle(semaphore_restart_); ++ semaphore_restart_ = NULL; ++ } ++ ++ if (semaphore_enter_wait_) { ++ CloseHandle(semaphore_enter_wait_); ++ semaphore_enter_wait_ = NULL; ++ } ++} ++ ++const char *GNUmakeTokenPoolWin32::GetEnv(const char *name) { ++ // getenv() does not work correctly together with tokenpool_tests.cc ++ static char buffer[MAX_PATH + 1]; ++ if (GetEnvironmentVariable("MAKEFLAGS", buffer, sizeof(buffer)) == 0) ++ return NULL; ++ return(buffer); ++} ++ ++bool GNUmakeTokenPoolWin32::ParseAuth(const char *jobserver) { ++ // match "--jobserver-auth=gmake_semaphore_..." ++ const char *start = strchr(jobserver, '='); ++ if (start) { ++ const char *end = start; ++ unsigned int len; ++ char c, *auth; ++ ++ while ((c = *++end) != '\0') ++ if (!(isalnum(c) || (c == '_'))) ++ break; ++ len = end - start; // includes string terminator in count ++ ++ if ((len > 1) && ((auth = (char *)malloc(len)) != NULL)) { ++ strncpy(auth, start + 1, len - 1); ++ auth[len - 1] = '\0'; ++ ++ if ((semaphore_jobserver_ = OpenSemaphore(SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ ++ FALSE, /* Child processes DON'T inherit */ ++ auth /* Semaphore name */ ++ )) != NULL) { ++ free(auth); ++ return true; ++ } ++ ++ free(auth); ++ } ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPoolWin32::AcquireToken() { ++ return WaitForSingleObject(semaphore_jobserver_, 0) == WAIT_OBJECT_0; ++} ++ ++bool GNUmakeTokenPoolWin32::ReturnToken() { ++ ReleaseSemaphore(semaphore_jobserver_); ++ return true; ++} ++ ++DWORD GNUmakeTokenPoolWin32::SemaphoreThread() { ++ while (running_) { ++ // indicate to parent that we are entering wait ++ ReleaseSemaphore(semaphore_enter_wait_); ++ ++ // alertable wait forever on token semaphore ++ if (WaitForSingleObjectEx(semaphore_jobserver_, INFINITE, TRUE) == WAIT_OBJECT_0) { ++ // release token again for AcquireToken() ++ ReleaseSemaphore(semaphore_jobserver_); ++ ++ // indicate to parent on ioport that a token might be available ++ if (!PostQueuedCompletionStatus(ioport_, 0, (ULONG_PTR) this, NULL)) ++ Win32Fatal("PostQueuedCompletionStatus"); ++ } ++ ++ // wait for parent to allow loop restart ++ WaitForObject(semaphore_restart_); ++ // semaphore is now in nonsignaled state again for next run... ++ } ++ ++ return 0; ++} ++ ++DWORD WINAPI GNUmakeTokenPoolWin32::SemaphoreThreadWrapper(LPVOID param) { ++ GNUmakeTokenPoolWin32 *This = (GNUmakeTokenPoolWin32 *) param; ++ return This->SemaphoreThread(); ++} ++ ++void GNUmakeTokenPoolWin32::NoopAPCFunc(ULONG_PTR param) { ++} ++ ++void GNUmakeTokenPoolWin32::WaitForTokenAvailability(HANDLE ioport) { ++ if (child_ == NULL) { ++ // first invocation ++ // ++ // subprocess-win32.cc uses I/O completion port (IOCP) which can't be ++ // used as a waitable object. Therefore we can't use WaitMultipleObjects() ++ // to wait on the IOCP and the token semaphore at the same time. Create ++ // a child thread that waits on the semaphore and posts an I/O completion ++ ioport_ = ioport; ++ ++ // create both semaphores in nonsignaled state ++ if ((semaphore_enter_wait_ = CreateSemaphore(NULL, 0, 1, NULL)) ++ == NULL) ++ Win32Fatal("CreateSemaphore/enter_wait"); ++ if ((semaphore_restart_ = CreateSemaphore(NULL, 0, 1, NULL)) ++ == NULL) ++ Win32Fatal("CreateSemaphore/restart"); ++ ++ // start child thread ++ running_ = true; ++ if ((child_ = CreateThread(NULL, 0, &SemaphoreThreadWrapper, this, 0, NULL)) ++ == NULL) ++ Win32Fatal("CreateThread"); ++ ++ } else { ++ // all further invocations - allow child thread to loop ++ ReleaseSemaphore(semaphore_restart_); ++ } ++ ++ // wait for child thread to enter wait ++ WaitForObject(semaphore_enter_wait_); ++ // semaphore is now in nonsignaled state again for next run... ++ ++ // now SubprocessSet::DoWork() can enter GetQueuedCompletionStatus()... ++} ++ ++bool GNUmakeTokenPoolWin32::TokenIsAvailable(ULONG_PTR key) { ++ // alert child thread to break wait on token semaphore ++ QueueUserAPC(&NoopAPCFunc, child_, (ULONG_PTR)NULL); ++ ++ // return true when GetQueuedCompletionStatus() returned our key ++ return key == (ULONG_PTR) this; ++} ++ ++void GNUmakeTokenPoolWin32::ReleaseSemaphore(HANDLE semaphore) { ++ if (!::ReleaseSemaphore(semaphore, 1, NULL)) ++ Win32Fatal("ReleaseSemaphore"); ++} ++ ++void GNUmakeTokenPoolWin32::WaitForObject(HANDLE object) { ++ if (WaitForSingleObject(object, INFINITE) != WAIT_OBJECT_0) ++ Win32Fatal("WaitForSingleObject"); ++} ++ ++struct TokenPool *TokenPool::Get() { ++ return new GNUmakeTokenPoolWin32; ++} +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index 4132bb06d9..92ff611721 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -12,101 +12,26 @@ + // See the License for the specific language governing permissions and + // limitations under the License. + +-#include "tokenpool.h" ++#include "tokenpool-gnu-make.h" + +-#include +-#include +-#include +-#include +-#include +-#include ++#include + #include + #include +-#include + + #include "line_printer.h" + +-// TokenPool implementation for GNU make jobserver +-// (http://make.mad-scientist.net/papers/jobserver-implementation/) +-struct GNUmakeTokenPool : public TokenPool { +- GNUmakeTokenPool(); +- virtual ~GNUmakeTokenPool(); +- +- virtual bool Acquire(); +- virtual void Reserve(); +- virtual void Release(); +- virtual void Clear(); +- virtual int GetMonitorFd(); +- +- bool Setup(bool ignore, bool verbose, double& max_load_average); +- +- private: +- int available_; +- int used_; +- +-#ifdef _WIN32 +- // @TODO +-#else +- int rfd_; +- int wfd_; +- +- struct sigaction old_act_; +- bool restore_; +- +- static int dup_rfd_; +- static void CloseDupRfd(int signum); +- +- bool CheckFd(int fd); +- bool SetAlarmHandler(); +-#endif +- +- void Return(); +-}; +- ++// TokenPool implementation for GNU make jobserver - common bits + // every instance owns an implicit token -> available_ == 1 +-GNUmakeTokenPool::GNUmakeTokenPool() : available_(1), used_(0), +- rfd_(-1), wfd_(-1), restore_(false) { ++GNUmakeTokenPool::GNUmakeTokenPool() : available_(1), used_(0) { + } + + GNUmakeTokenPool::~GNUmakeTokenPool() { +- Clear(); +- if (restore_) +- sigaction(SIGALRM, &old_act_, NULL); +-} +- +-bool GNUmakeTokenPool::CheckFd(int fd) { +- if (fd < 0) +- return false; +- int ret = fcntl(fd, F_GETFD); +- if (ret < 0) +- return false; +- return true; +-} +- +-int GNUmakeTokenPool::dup_rfd_ = -1; +- +-void GNUmakeTokenPool::CloseDupRfd(int signum) { +- close(dup_rfd_); +- dup_rfd_ = -1; +-} +- +-bool GNUmakeTokenPool::SetAlarmHandler() { +- struct sigaction act; +- memset(&act, 0, sizeof(act)); +- act.sa_handler = CloseDupRfd; +- if (sigaction(SIGALRM, &act, &old_act_) < 0) { +- perror("sigaction:"); +- return(false); +- } else { +- restore_ = true; +- return(true); +- } + } + + bool GNUmakeTokenPool::Setup(bool ignore, + bool verbose, + double& max_load_average) { +- const char *value = getenv("MAKEFLAGS"); ++ const char *value = GetEnv("MAKEFLAGS"); + if (value) { + // GNU make <= 4.1 + const char *jobserver = strstr(value, "--jobserver-fds="); +@@ -119,20 +44,13 @@ bool GNUmakeTokenPool::Setup(bool ignore, + if (ignore) { + printer.PrintOnNewLine("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); + } else { +- int rfd = -1; +- int wfd = -1; +- if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && +- CheckFd(rfd) && +- CheckFd(wfd) && +- SetAlarmHandler()) { ++ if (ParseAuth(jobserver)) { + const char *l_arg = strstr(value, " -l"); + int load_limit = -1; + + if (verbose) { + printer.PrintOnNewLine("ninja: using GNU make jobserver.\n"); + } +- rfd_ = rfd; +- wfd_ = wfd; + + // translate GNU make -lN to ninja -lN + if (l_arg && +@@ -154,83 +72,14 @@ bool GNUmakeTokenPool::Acquire() { + if (available_ > 0) + return true; + +- // Please read +- // +- // http://make.mad-scientist.net/papers/jobserver-implementation/ +- // +- // for the reasoning behind the following code. +- // +- // Try to read one character from the pipe. Returns true on success. +- // +- // First check if read() would succeed without blocking. +-#ifdef USE_PPOLL +- pollfd pollfds[] = {{rfd_, POLLIN, 0}}; +- int ret = poll(pollfds, 1, 0); +-#else +- fd_set set; +- struct timeval timeout = { 0, 0 }; +- FD_ZERO(&set); +- FD_SET(rfd_, &set); +- int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); +-#endif +- if (ret > 0) { +- // Handle potential race condition: +- // - the above check succeeded, i.e. read() should not block +- // - the character disappears before we call read() +- // +- // Create a duplicate of rfd_. The duplicate file descriptor dup_rfd_ +- // can safely be closed by signal handlers without affecting rfd_. +- dup_rfd_ = dup(rfd_); +- +- if (dup_rfd_ != -1) { +- struct sigaction act, old_act; +- int ret = 0; +- +- // Temporarily replace SIGCHLD handler with our own +- memset(&act, 0, sizeof(act)); +- act.sa_handler = CloseDupRfd; +- if (sigaction(SIGCHLD, &act, &old_act) == 0) { +- struct itimerval timeout; +- +- // install a 100ms timeout that generates SIGALARM on expiration +- memset(&timeout, 0, sizeof(timeout)); +- timeout.it_value.tv_usec = 100 * 1000; // [ms] -> [usec] +- if (setitimer(ITIMER_REAL, &timeout, NULL) == 0) { +- char buf; +- +- // Now try to read() from dup_rfd_. Return values from read(): +- // +- // 1. token read -> 1 +- // 2. pipe closed -> 0 +- // 3. alarm expires -> -1 (EINTR) +- // 4. child exits -> -1 (EINTR) +- // 5. alarm expired before entering read() -> -1 (EBADF) +- // 6. child exited before entering read() -> -1 (EBADF) +- // 7. child exited before handler is installed -> go to 1 - 3 +- ret = read(dup_rfd_, &buf, 1); +- +- // disarm timer +- memset(&timeout, 0, sizeof(timeout)); +- setitimer(ITIMER_REAL, &timeout, NULL); +- } +- +- sigaction(SIGCHLD, &old_act, NULL); +- } +- +- CloseDupRfd(0); +- +- // Case 1 from above list +- if (ret > 0) { +- available_++; +- return true; +- } +- } ++ if (AcquireToken()) { ++ // token acquired ++ available_++; ++ return true; ++ } else { ++ // no token available ++ return false; + } +- +- // read() would block, i.e. no token available, +- // cases 2-6 from above list or +- // select() / poll() / dup() / sigaction() / setitimer() failed +- return false; + } + + void GNUmakeTokenPool::Reserve() { +@@ -239,15 +88,8 @@ void GNUmakeTokenPool::Reserve() { + } + + void GNUmakeTokenPool::Return() { +- const char buf = '+'; +- while (1) { +- int ret = write(wfd_, &buf, 1); +- if (ret > 0) +- available_--; +- if ((ret != -1) || (errno != EINTR)) +- return; +- // write got interrupted - retry +- } ++ if (ReturnToken()) ++ available_--; + } + + void GNUmakeTokenPool::Release() { +@@ -263,18 +105,3 @@ void GNUmakeTokenPool::Clear() { + while (available_ > 1) + Return(); + } +- +-int GNUmakeTokenPool::GetMonitorFd() { +- return(rfd_); +-} +- +-struct TokenPool *TokenPool::Get(bool ignore, +- bool verbose, +- double& max_load_average) { +- GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; +- if (tokenpool->Setup(ignore, verbose, max_load_average)) +- return tokenpool; +- else +- delete tokenpool; +- return NULL; +-} +diff --git a/src/tokenpool-gnu-make.h b/src/tokenpool-gnu-make.h +new file mode 100644 +index 0000000000..d3852088e2 +--- /dev/null ++++ b/src/tokenpool-gnu-make.h +@@ -0,0 +1,40 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++// interface to GNU make token pool ++struct GNUmakeTokenPool : public TokenPool { ++ GNUmakeTokenPool(); ++ virtual ~GNUmakeTokenPool(); ++ ++ // token pool implementation ++ virtual bool Acquire(); ++ virtual void Reserve(); ++ virtual void Release(); ++ virtual void Clear(); ++ virtual bool Setup(bool ignore, bool verbose, double& max_load_average); ++ ++ // platform specific implementation ++ virtual const char *GetEnv(const char *name) = 0; ++ virtual bool ParseAuth(const char *jobserver) = 0; ++ virtual bool AcquireToken() = 0; ++ virtual bool ReturnToken() = 0; ++ ++ private: ++ int available_; ++ int used_; ++ ++ void Return(); ++}; +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +index 4c592875b4..613d16882d 100644 +--- a/src/tokenpool-none.cc ++++ b/src/tokenpool-none.cc +@@ -17,8 +17,6 @@ + #include + + // No-op TokenPool implementation +-struct TokenPool *TokenPool::Get(bool ignore, +- bool verbose, +- double& max_load_average) { ++struct TokenPool *TokenPool::Get() { + return NULL; + } +diff --git a/src/tokenpool.h b/src/tokenpool.h +index 4bf477f20c..1be8e1d5ce 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -1,4 +1,4 @@ +-// Copyright 2016-2017 Google Inc. All Rights Reserved. ++// Copyright 2016-2018 Google Inc. All Rights Reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. +@@ -12,6 +12,10 @@ + // See the License for the specific language governing permissions and + // limitations under the License. + ++#ifdef _WIN32 ++#include ++#endif ++ + // interface to token pool + struct TokenPool { + virtual ~TokenPool() {} +@@ -21,14 +25,18 @@ struct TokenPool { + virtual void Release() = 0; + virtual void Clear() = 0; + ++ // returns false if token pool setup failed ++ virtual bool Setup(bool ignore, bool verbose, double& max_load_average) = 0; ++ + #ifdef _WIN32 +- // @TODO ++ virtual void WaitForTokenAvailability(HANDLE ioport) = 0; ++ // returns true if a token has become available ++ // key is result from GetQueuedCompletionStatus() ++ virtual bool TokenIsAvailable(ULONG_PTR key) = 0; + #else + virtual int GetMonitorFd() = 0; + #endif + + // returns NULL if token pool is not available +- static struct TokenPool *Get(bool ignore, +- bool verbose, +- double& max_load_average); ++ static struct TokenPool *Get(); + }; +diff --git a/src/tokenpool_test.cc b/src/tokenpool_test.cc +index 6c89064ca4..8d4fd7d33a 100644 +--- a/src/tokenpool_test.cc ++++ b/src/tokenpool_test.cc +@@ -16,13 +16,25 @@ + + #include "test.h" + +-#ifndef _WIN32 ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #include + #include +-#include + ++#ifdef _WIN32 ++// should contain all valid characters ++#define SEMAPHORE_NAME "abcdefghijklmnopqrstwxyz01234567890_" ++#define AUTH_FORMAT(tmpl) "foo " tmpl "=%s bar" ++#define ENVIRONMENT_CLEAR() SetEnvironmentVariable("MAKEFLAGS", NULL) ++#define ENVIRONMENT_INIT(v) SetEnvironmentVariable("MAKEFLAGS", v) ++#else ++#define AUTH_FORMAT(tmpl) "foo " tmpl "=%d,%d bar" + #define ENVIRONMENT_CLEAR() unsetenv("MAKEFLAGS") +-#define ENVIRONMENT_INIT(v) setenv("MAKEFLAGS", v, true); ++#define ENVIRONMENT_INIT(v) setenv("MAKEFLAGS", v, true) + #endif + + namespace { +@@ -32,43 +44,60 @@ const double kLoadAverageDefault = -1.23456789; + struct TokenPoolTest : public testing::Test { + double load_avg_; + TokenPool *tokens_; +-#ifndef _WIN32 + char buf_[1024]; ++#ifdef _WIN32 ++ const char *semaphore_name_; ++ HANDLE semaphore_; ++#else + int fds_[2]; + #endif + + virtual void SetUp() { + load_avg_ = kLoadAverageDefault; + tokens_ = NULL; +-#ifndef _WIN32 + ENVIRONMENT_CLEAR(); ++#ifdef _WIN32 ++ semaphore_name_ = SEMAPHORE_NAME; ++ if ((semaphore_ = CreateSemaphore(0, 0, 2, SEMAPHORE_NAME)) == NULL) ++#else + if (pipe(fds_) < 0) +- ASSERT_TRUE(false); + #endif ++ ASSERT_TRUE(false); + } + +- void CreatePool(const char *format, bool ignore_jobserver) { +-#ifndef _WIN32 ++ void CreatePool(const char *format, bool ignore_jobserver = false) { + if (format) { +- sprintf(buf_, format, fds_[0], fds_[1]); ++ sprintf(buf_, format, ++#ifdef _WIN32 ++ semaphore_name_ ++#else ++ fds_[0], fds_[1] ++#endif ++ ); + ENVIRONMENT_INIT(buf_); + } +-#endif +- tokens_ = TokenPool::Get(ignore_jobserver, false, load_avg_); ++ if ((tokens_ = TokenPool::Get()) != NULL) { ++ if (!tokens_->Setup(ignore_jobserver, false, load_avg_)) { ++ delete tokens_; ++ tokens_ = NULL; ++ } ++ } + } + + void CreateDefaultPool() { +- CreatePool("foo --jobserver-auth=%d,%d bar", false); ++ CreatePool(AUTH_FORMAT("--jobserver-auth")); + } + + virtual void TearDown() { + if (tokens_) + delete tokens_; +-#ifndef _WIN32 ++#ifdef _WIN32 ++ CloseHandle(semaphore_); ++#else + close(fds_[0]); + close(fds_[1]); +- ENVIRONMENT_CLEAR(); + #endif ++ ENVIRONMENT_CLEAR(); + } + }; + +@@ -82,10 +111,9 @@ TEST_F(TokenPoolTest, NoTokenPool) { + EXPECT_EQ(kLoadAverageDefault, load_avg_); + } + +-#ifndef _WIN32 + TEST_F(TokenPoolTest, SuccessfulOldSetup) { + // GNUmake <= 4.1 +- CreatePool("foo --jobserver-fds=%d,%d bar", false); ++ CreatePool(AUTH_FORMAT("--jobserver-fds")); + + EXPECT_NE(NULL, tokens_); + EXPECT_EQ(kLoadAverageDefault, load_avg_); +@@ -100,19 +128,37 @@ TEST_F(TokenPoolTest, SuccessfulNewSetup) { + } + + TEST_F(TokenPoolTest, IgnoreWithJN) { +- CreatePool("foo --jobserver-auth=%d,%d bar", true); ++ CreatePool(AUTH_FORMAT("--jobserver-auth"), true); + + EXPECT_EQ(NULL, tokens_); + EXPECT_EQ(kLoadAverageDefault, load_avg_); + } + + TEST_F(TokenPoolTest, HonorLN) { +- CreatePool("foo -l9 --jobserver-auth=%d,%d bar", false); ++ CreatePool(AUTH_FORMAT("-l9 --jobserver-auth")); + + EXPECT_NE(NULL, tokens_); + EXPECT_EQ(9.0, load_avg_); + } + ++#ifdef _WIN32 ++TEST_F(TokenPoolTest, SemaphoreNotFound) { ++ semaphore_name_ = SEMAPHORE_NAME "_foobar"; ++ CreateDefaultPool(); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, TokenIsAvailable) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_TRUE(tokens_->TokenIsAvailable((ULONG_PTR)tokens_)); ++} ++#else + TEST_F(TokenPoolTest, MonitorFD) { + CreateDefaultPool(); + +@@ -121,6 +167,7 @@ TEST_F(TokenPoolTest, MonitorFD) { + + EXPECT_EQ(fds_[0], tokens_->GetMonitorFd()); + } ++#endif + + TEST_F(TokenPoolTest, ImplicitToken) { + CreateDefaultPool(); +@@ -147,7 +194,13 @@ TEST_F(TokenPoolTest, TwoTokens) { + EXPECT_FALSE(tokens_->Acquire()); + + // jobserver offers 2nd token ++#ifdef _WIN32 ++ LONG previous; ++ ASSERT_TRUE(ReleaseSemaphore(semaphore_, 1, &previous)); ++ ASSERT_EQ(0, previous); ++#else + ASSERT_EQ(1u, write(fds_[1], "T", 1)); ++#endif + EXPECT_TRUE(tokens_->Acquire()); + tokens_->Reserve(); + EXPECT_FALSE(tokens_->Acquire()); +@@ -160,8 +213,14 @@ TEST_F(TokenPoolTest, TwoTokens) { + tokens_->Release(); + EXPECT_TRUE(tokens_->Acquire()); + +- // there must be one token in the pipe ++ // there must be one token available ++#ifdef _WIN32 ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_TRUE(ReleaseSemaphore(semaphore_, 1, &previous)); ++ EXPECT_EQ(0, previous); ++#else + EXPECT_EQ(1u, read(fds_[0], buf_, sizeof(buf_))); ++#endif + + // implicit token + EXPECT_TRUE(tokens_->Acquire()); +@@ -179,7 +238,13 @@ TEST_F(TokenPoolTest, Clear) { + EXPECT_FALSE(tokens_->Acquire()); + + // jobserver offers 2nd & 3rd token ++#ifdef _WIN32 ++ LONG previous; ++ ASSERT_TRUE(ReleaseSemaphore(semaphore_, 2, &previous)); ++ ASSERT_EQ(0, previous); ++#else + ASSERT_EQ(2u, write(fds_[1], "TT", 2)); ++#endif + EXPECT_TRUE(tokens_->Acquire()); + tokens_->Reserve(); + EXPECT_TRUE(tokens_->Acquire()); +@@ -189,10 +254,16 @@ TEST_F(TokenPoolTest, Clear) { + tokens_->Clear(); + EXPECT_TRUE(tokens_->Acquire()); + +- // there must be two tokens in the pipe ++ // there must be two tokens available ++#ifdef _WIN32 ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_TRUE(ReleaseSemaphore(semaphore_, 2, &previous)); ++ EXPECT_EQ(0, previous); ++#else + EXPECT_EQ(2u, read(fds_[0], buf_, sizeof(buf_))); ++#endif + + // implicit token + EXPECT_TRUE(tokens_->Acquire()); + } +-#endif + +From 2b9c81c0ec1226d8795e7725529f13be41eaa385 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Fri, 14 Dec 2018 13:27:11 +0200 +Subject: [PATCH 11/11] Prepare PR for merging - part II + +- remove unnecessary "struct" from TokenPool +- add PAPCFUNC cast to QueryUserAPC() +- remove hard-coded MAKEFLAGS string from win32 +- remove useless build test CompleteNoWork +- rename TokenPoolTest to TestTokenPool +- add tokenpool modules to CMake build +- remove unused no-op TokenPool implementation +- fix errors flagged by codespell & clang-tidy +- address review comments from + +https://github.com/ninja-build/ninja/pull/1140#pullrequestreview-195195803 +https://github.com/ninja-build/ninja/pull/1140#pullrequestreview-185089255 +https://github.com/ninja-build/ninja/pull/1140#issuecomment-473898963 +https://github.com/ninja-build/ninja/pull/1140#issuecomment-596624610 +--- + CMakeLists.txt | 8 ++++- + src/build.cc | 2 +- + src/build_test.cc | 12 +------ + src/subprocess-posix.cc | 4 +-- + src/subprocess-win32.cc | 2 +- + src/subprocess.h | 2 +- + src/subprocess_test.cc | 26 +++++++------- + src/tokenpool-gnu-make-posix.cc | 21 +++++------ + src/tokenpool-gnu-make-win32.cc | 36 ++++++++++--------- + src/tokenpool-gnu-make.cc | 63 +++++++++++++++++---------------- + src/tokenpool-gnu-make.h | 6 ++-- + src/tokenpool-none.cc | 22 ------------ + src/tokenpool.h | 2 +- + src/tokenpool_test.cc | 8 ++--- + 14 files changed, 94 insertions(+), 120 deletions(-) + delete mode 100644 src/tokenpool-none.cc + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 57ae548f5b..e2876fe413 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -112,6 +112,7 @@ add_library(libninja OBJECT + src/state.cc + src/status.cc + src/string_piece_util.cc ++ src/tokenpool-gnu-make.cc + src/util.cc + src/version.cc + ) +@@ -123,9 +124,13 @@ if(WIN32) + src/msvc_helper_main-win32.cc + src/getopt.c + src/minidump-win32.cc ++ src/tokenpool-gnu-make-win32.cc + ) + else() +- target_sources(libninja PRIVATE src/subprocess-posix.cc) ++ target_sources(libninja PRIVATE ++ src/subprocess-posix.cc ++ src/tokenpool-gnu-make-posix.cc ++ ) + if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX") + target_sources(libninja PRIVATE src/getopt.c) + endif() +@@ -204,6 +209,7 @@ if(BUILD_TESTING) + src/string_piece_util_test.cc + src/subprocess_test.cc + src/test.cc ++ src/tokenpool_test.cc + src/util_test.cc + ) + if(WIN32) +diff --git a/src/build.cc b/src/build.cc +index 20c3bdc2a0..854df08c2a 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -467,7 +467,7 @@ struct RealCommandRunner : public CommandRunner { + // copy of config_.max_load_average; can be modified by TokenPool setup + double max_load_average_; + SubprocessSet subprocs_; +- TokenPool *tokens_; ++ TokenPool* tokens_; + map subproc_to_edge_; + }; + +diff --git a/src/build_test.cc b/src/build_test.cc +index dd41dfbe1d..8901c9518f 100644 +--- a/src/build_test.cc ++++ b/src/build_test.cc +@@ -4098,7 +4098,7 @@ struct BuildTokenTest : public BuildTest { + void ExpectWaitForCommand(int count, ...); + + private: +- void EnqueueBooleans(vector& booleans, int count, va_list ao); ++ void EnqueueBooleans(vector& booleans, int count, va_list ap); + }; + + void BuildTokenTest::SetUp() { +@@ -4144,16 +4144,6 @@ void BuildTokenTest::EnqueueBooleans(vector& booleans, int count, va_list + } + } + +-TEST_F(BuildTokenTest, CompleteNoWork) { +- // plan should not execute anything +- string err; +- +- EXPECT_TRUE(builder_.Build(&err)); +- EXPECT_EQ("", err); +- +- EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); +-} +- + TEST_F(BuildTokenTest, DoNotAquireToken) { + // plan should execute one command + string err; +diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc +index 74451b0be2..31839276c4 100644 +--- a/src/subprocess-posix.cc ++++ b/src/subprocess-posix.cc +@@ -250,7 +250,7 @@ Subprocess *SubprocessSet::Add(const string& command, bool use_console) { + } + + #ifdef USE_PPOLL +-bool SubprocessSet::DoWork(struct TokenPool* tokens) { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + vector fds; + nfds_t nfds = 0; + +@@ -315,7 +315,7 @@ bool SubprocessSet::DoWork(struct TokenPool* tokens) { + } + + #else // !defined(USE_PPOLL) +-bool SubprocessSet::DoWork(struct TokenPool* tokens) { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + fd_set set; + int nfds = 0; + FD_ZERO(&set); +diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc +index ce3e2c20a4..2926e9a221 100644 +--- a/src/subprocess-win32.cc ++++ b/src/subprocess-win32.cc +@@ -252,7 +252,7 @@ Subprocess *SubprocessSet::Add(const string& command, bool use_console) { + return subprocess; + } + +-bool SubprocessSet::DoWork(struct TokenPool* tokens) { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + DWORD bytes_read; + Subprocess* subproc; + OVERLAPPED* overlapped; +diff --git a/src/subprocess.h b/src/subprocess.h +index 9ea67ea477..1ec78171e8 100644 +--- a/src/subprocess.h ++++ b/src/subprocess.h +@@ -86,7 +86,7 @@ struct SubprocessSet { + ~SubprocessSet(); + + Subprocess* Add(const std::string& command, bool use_console = false); +- bool DoWork(struct TokenPool* tokens); ++ bool DoWork(TokenPool* tokens); + Subprocess* NextFinished(); + void Clear(); + +diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc +index f625963462..7b146f31be 100644 +--- a/src/subprocess_test.cc ++++ b/src/subprocess_test.cc +@@ -35,7 +35,7 @@ const char* kSimpleCommand = "cmd /c dir \\"; + const char* kSimpleCommand = "ls /"; + #endif + +-struct TokenPoolTest : public TokenPool { ++struct TestTokenPool : public TokenPool { + bool Acquire() { return false; } + void Reserve() {} + void Release() {} +@@ -58,7 +58,7 @@ struct TokenPoolTest : public TokenPool { + + struct SubprocessTest : public testing::Test { + SubprocessSet subprocs_; +- TokenPoolTest tokens_; ++ TestTokenPool tokens_; + }; + + } // anonymous namespace +@@ -73,7 +73,7 @@ TEST_F(SubprocessTest, BadCommandStderr) { + // Pretend we discovered that stderr was ready for writing. + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -89,7 +89,7 @@ TEST_F(SubprocessTest, NoSuchCommand) { + // Pretend we discovered that stderr was ready for writing. + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -109,7 +109,7 @@ TEST_F(SubprocessTest, InterruptChild) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -135,7 +135,7 @@ TEST_F(SubprocessTest, InterruptChildWithSigTerm) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -161,7 +161,7 @@ TEST_F(SubprocessTest, InterruptChildWithSigHup) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -190,7 +190,7 @@ TEST_F(SubprocessTest, Console) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitSuccess, subproc->Finish()); + } +@@ -206,7 +206,7 @@ TEST_F(SubprocessTest, SetWithSingle) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_NE("", subproc->GetOutput()); + +@@ -243,7 +243,7 @@ TEST_F(SubprocessTest, SetWithMulti) { + ASSERT_GT(subprocs_.running_.size(), 0u); + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(0u, subprocs_.running_.size()); + ASSERT_EQ(3u, subprocs_.finished_.size()); + +@@ -278,7 +278,7 @@ TEST_F(SubprocessTest, SetWithLots) { + subprocs_.ResetTokenAvailable(); + while (!subprocs_.running_.empty()) + subprocs_.DoWork(NULL); +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + for (size_t i = 0; i < procs.size(); ++i) { + ASSERT_EQ(ExitSuccess, procs[i]->Finish()); + ASSERT_NE("", procs[i]->GetOutput()); +@@ -298,7 +298,7 @@ TEST_F(SubprocessTest, ReadStdin) { + while (!subproc->Done()) { + subprocs_.DoWork(NULL); + } +- ASSERT_EQ(false, subprocs_.IsTokenAvailable()); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_EQ(1u, subprocs_.finished_.size()); + } +@@ -322,7 +322,7 @@ TEST_F(SubprocessTest, TokenAvailable) { + subprocs_.DoWork(&tokens_); + #ifdef _WIN32 + tokens_._token_available = false; +- // we need to loop here as we have no conrol where the token ++ // we need to loop here as we have no control where the token + // I/O completion post ends up in the queue + while (!subproc->Done() && !subprocs_.IsTokenAvailable()) { + subprocs_.DoWork(&tokens_); +diff --git a/src/tokenpool-gnu-make-posix.cc b/src/tokenpool-gnu-make-posix.cc +index 70d84bfff7..353bda226a 100644 +--- a/src/tokenpool-gnu-make-posix.cc ++++ b/src/tokenpool-gnu-make-posix.cc +@@ -32,8 +32,8 @@ struct GNUmakeTokenPoolPosix : public GNUmakeTokenPool { + + virtual int GetMonitorFd(); + +- virtual const char *GetEnv(const char *name) { return getenv(name); }; +- virtual bool ParseAuth(const char *jobserver); ++ virtual const char* GetEnv(const char* name) { return getenv(name); }; ++ virtual bool ParseAuth(const char* jobserver); + virtual bool AcquireToken(); + virtual bool ReturnToken(); + +@@ -64,9 +64,7 @@ bool GNUmakeTokenPoolPosix::CheckFd(int fd) { + if (fd < 0) + return false; + int ret = fcntl(fd, F_GETFD); +- if (ret < 0) +- return false; +- return true; ++ return ret >= 0; + } + + int GNUmakeTokenPoolPosix::dup_rfd_ = -1; +@@ -82,14 +80,13 @@ bool GNUmakeTokenPoolPosix::SetAlarmHandler() { + act.sa_handler = CloseDupRfd; + if (sigaction(SIGALRM, &act, &old_act_) < 0) { + perror("sigaction:"); +- return(false); +- } else { +- restore_ = true; +- return(true); ++ return false; + } ++ restore_ = true; ++ return true; + } + +-bool GNUmakeTokenPoolPosix::ParseAuth(const char *jobserver) { ++bool GNUmakeTokenPoolPosix::ParseAuth(const char* jobserver) { + int rfd = -1; + int wfd = -1; + if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && +@@ -195,9 +192,9 @@ bool GNUmakeTokenPoolPosix::ReturnToken() { + } + + int GNUmakeTokenPoolPosix::GetMonitorFd() { +- return(rfd_); ++ return rfd_; + } + +-struct TokenPool *TokenPool::Get() { ++TokenPool* TokenPool::Get() { + return new GNUmakeTokenPoolPosix; + } +diff --git a/src/tokenpool-gnu-make-win32.cc b/src/tokenpool-gnu-make-win32.cc +index 2719f2c1fc..b2bb52fadb 100644 +--- a/src/tokenpool-gnu-make-win32.cc ++++ b/src/tokenpool-gnu-make-win32.cc +@@ -14,7 +14,8 @@ + + #include "tokenpool-gnu-make.h" + +-// always include first to make sure other headers do the correct thing... ++// Always include this first. ++// Otherwise the other system headers don't work correctly under Win32 + #include + + #include +@@ -32,8 +33,8 @@ struct GNUmakeTokenPoolWin32 : public GNUmakeTokenPool { + virtual void WaitForTokenAvailability(HANDLE ioport); + virtual bool TokenIsAvailable(ULONG_PTR key); + +- virtual const char *GetEnv(const char *name); +- virtual bool ParseAuth(const char *jobserver); ++ virtual const char* GetEnv(const char* name); ++ virtual bool ParseAuth(const char* jobserver); + virtual bool AcquireToken(); + virtual bool ReturnToken(); + +@@ -98,19 +99,19 @@ GNUmakeTokenPoolWin32::~GNUmakeTokenPoolWin32() { + } + } + +-const char *GNUmakeTokenPoolWin32::GetEnv(const char *name) { ++const char* GNUmakeTokenPoolWin32::GetEnv(const char* name) { + // getenv() does not work correctly together with tokenpool_tests.cc + static char buffer[MAX_PATH + 1]; +- if (GetEnvironmentVariable("MAKEFLAGS", buffer, sizeof(buffer)) == 0) ++ if (GetEnvironmentVariable(name, buffer, sizeof(buffer)) == 0) + return NULL; +- return(buffer); ++ return buffer; + } + +-bool GNUmakeTokenPoolWin32::ParseAuth(const char *jobserver) { ++bool GNUmakeTokenPoolWin32::ParseAuth(const char* jobserver) { + // match "--jobserver-auth=gmake_semaphore_..." +- const char *start = strchr(jobserver, '='); ++ const char* start = strchr(jobserver, '='); + if (start) { +- const char *end = start; ++ const char* end = start; + unsigned int len; + char c, *auth; + +@@ -119,14 +120,15 @@ bool GNUmakeTokenPoolWin32::ParseAuth(const char *jobserver) { + break; + len = end - start; // includes string terminator in count + +- if ((len > 1) && ((auth = (char *)malloc(len)) != NULL)) { ++ if ((len > 1) && ((auth = (char*)malloc(len)) != NULL)) { + strncpy(auth, start + 1, len - 1); + auth[len - 1] = '\0'; + +- if ((semaphore_jobserver_ = OpenSemaphore(SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ +- FALSE, /* Child processes DON'T inherit */ +- auth /* Semaphore name */ +- )) != NULL) { ++ if ((semaphore_jobserver_ = ++ OpenSemaphore(SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ ++ FALSE, /* Child processes DON'T inherit */ ++ auth /* Semaphore name */ ++ )) != NULL) { + free(auth); + return true; + } +@@ -171,7 +173,7 @@ DWORD GNUmakeTokenPoolWin32::SemaphoreThread() { + } + + DWORD WINAPI GNUmakeTokenPoolWin32::SemaphoreThreadWrapper(LPVOID param) { +- GNUmakeTokenPoolWin32 *This = (GNUmakeTokenPoolWin32 *) param; ++ GNUmakeTokenPoolWin32* This = (GNUmakeTokenPoolWin32*) param; + return This->SemaphoreThread(); + } + +@@ -216,7 +218,7 @@ void GNUmakeTokenPoolWin32::WaitForTokenAvailability(HANDLE ioport) { + + bool GNUmakeTokenPoolWin32::TokenIsAvailable(ULONG_PTR key) { + // alert child thread to break wait on token semaphore +- QueueUserAPC(&NoopAPCFunc, child_, (ULONG_PTR)NULL); ++ QueueUserAPC((PAPCFUNC)&NoopAPCFunc, child_, (ULONG_PTR)NULL); + + // return true when GetQueuedCompletionStatus() returned our key + return key == (ULONG_PTR) this; +@@ -232,6 +234,6 @@ void GNUmakeTokenPoolWin32::WaitForObject(HANDLE object) { + Win32Fatal("WaitForSingleObject"); + } + +-struct TokenPool *TokenPool::Get() { ++TokenPool* TokenPool::Get() { + return new GNUmakeTokenPoolWin32; + } +diff --git a/src/tokenpool-gnu-make.cc b/src/tokenpool-gnu-make.cc +index 92ff611721..60e0552924 100644 +--- a/src/tokenpool-gnu-make.cc ++++ b/src/tokenpool-gnu-make.cc +@@ -31,36 +31,37 @@ GNUmakeTokenPool::~GNUmakeTokenPool() { + bool GNUmakeTokenPool::Setup(bool ignore, + bool verbose, + double& max_load_average) { +- const char *value = GetEnv("MAKEFLAGS"); +- if (value) { +- // GNU make <= 4.1 +- const char *jobserver = strstr(value, "--jobserver-fds="); ++ const char* value = GetEnv("MAKEFLAGS"); ++ if (!value) ++ return false; ++ ++ // GNU make <= 4.1 ++ const char* jobserver = strstr(value, "--jobserver-fds="); ++ if (!jobserver) + // GNU make => 4.2 +- if (!jobserver) +- jobserver = strstr(value, "--jobserver-auth="); +- if (jobserver) { +- LinePrinter printer; +- +- if (ignore) { +- printer.PrintOnNewLine("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); +- } else { +- if (ParseAuth(jobserver)) { +- const char *l_arg = strstr(value, " -l"); +- int load_limit = -1; +- +- if (verbose) { +- printer.PrintOnNewLine("ninja: using GNU make jobserver.\n"); +- } +- +- // translate GNU make -lN to ninja -lN +- if (l_arg && +- (sscanf(l_arg + 3, "%d ", &load_limit) == 1) && +- (load_limit > 0)) { +- max_load_average = load_limit; +- } +- +- return true; ++ jobserver = strstr(value, "--jobserver-auth="); ++ if (jobserver) { ++ LinePrinter printer; ++ ++ if (ignore) { ++ printer.PrintOnNewLine("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); ++ } else { ++ if (ParseAuth(jobserver)) { ++ const char* l_arg = strstr(value, " -l"); ++ int load_limit = -1; ++ ++ if (verbose) { ++ printer.PrintOnNewLine("ninja: using GNU make jobserver.\n"); ++ } ++ ++ // translate GNU make -lN to ninja -lN ++ if (l_arg && ++ (sscanf(l_arg + 3, "%d ", &load_limit) == 1) && ++ (load_limit > 0)) { ++ max_load_average = load_limit; + } ++ ++ return true; + } + } + } +@@ -76,10 +77,10 @@ bool GNUmakeTokenPool::Acquire() { + // token acquired + available_++; + return true; +- } else { +- // no token available +- return false; + } ++ ++ // no token available ++ return false; + } + + void GNUmakeTokenPool::Reserve() { +diff --git a/src/tokenpool-gnu-make.h b/src/tokenpool-gnu-make.h +index d3852088e2..c94cca5e2d 100644 +--- a/src/tokenpool-gnu-make.h ++++ b/src/tokenpool-gnu-make.h +@@ -17,7 +17,7 @@ + // interface to GNU make token pool + struct GNUmakeTokenPool : public TokenPool { + GNUmakeTokenPool(); +- virtual ~GNUmakeTokenPool(); ++ ~GNUmakeTokenPool(); + + // token pool implementation + virtual bool Acquire(); +@@ -27,8 +27,8 @@ struct GNUmakeTokenPool : public TokenPool { + virtual bool Setup(bool ignore, bool verbose, double& max_load_average); + + // platform specific implementation +- virtual const char *GetEnv(const char *name) = 0; +- virtual bool ParseAuth(const char *jobserver) = 0; ++ virtual const char* GetEnv(const char* name) = 0; ++ virtual bool ParseAuth(const char* jobserver) = 0; + virtual bool AcquireToken() = 0; + virtual bool ReturnToken() = 0; + +diff --git a/src/tokenpool-none.cc b/src/tokenpool-none.cc +deleted file mode 100644 +index 613d16882d..0000000000 +--- a/src/tokenpool-none.cc ++++ /dev/null +@@ -1,22 +0,0 @@ +-// Copyright 2016-2018 Google Inc. All Rights Reserved. +-// +-// Licensed under the Apache License, Version 2.0 (the "License"); +-// you may not use this file except in compliance with the License. +-// You may obtain a copy of the License at +-// +-// http://www.apache.org/licenses/LICENSE-2.0 +-// +-// Unless required by applicable law or agreed to in writing, software +-// distributed under the License is distributed on an "AS IS" BASIS, +-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-// See the License for the specific language governing permissions and +-// limitations under the License. +- +-#include "tokenpool.h" +- +-#include +- +-// No-op TokenPool implementation +-struct TokenPool *TokenPool::Get() { +- return NULL; +-} +diff --git a/src/tokenpool.h b/src/tokenpool.h +index 1be8e1d5ce..931c22754d 100644 +--- a/src/tokenpool.h ++++ b/src/tokenpool.h +@@ -38,5 +38,5 @@ struct TokenPool { + #endif + + // returns NULL if token pool is not available +- static struct TokenPool *Get(); ++ static TokenPool* Get(); + }; +diff --git a/src/tokenpool_test.cc b/src/tokenpool_test.cc +index 8d4fd7d33a..8d3061cb30 100644 +--- a/src/tokenpool_test.cc ++++ b/src/tokenpool_test.cc +@@ -43,10 +43,10 @@ const double kLoadAverageDefault = -1.23456789; + + struct TokenPoolTest : public testing::Test { + double load_avg_; +- TokenPool *tokens_; ++ TokenPool* tokens_; + char buf_[1024]; + #ifdef _WIN32 +- const char *semaphore_name_; ++ const char* semaphore_name_; + HANDLE semaphore_; + #else + int fds_[2]; +@@ -65,7 +65,7 @@ struct TokenPoolTest : public testing::Test { + ASSERT_TRUE(false); + } + +- void CreatePool(const char *format, bool ignore_jobserver = false) { ++ void CreatePool(const char* format, bool ignore_jobserver = false) { + if (format) { + sprintf(buf_, format, + #ifdef _WIN32 +@@ -209,7 +209,7 @@ TEST_F(TokenPoolTest, TwoTokens) { + tokens_->Release(); + EXPECT_TRUE(tokens_->Acquire()); + +- // release implict token - must return 2nd token back to jobserver ++ // release implicit token - must return 2nd token back to jobserver + tokens_->Release(); + EXPECT_TRUE(tokens_->Acquire()); +