diff --git a/Makefile b/Makefile index bb4d0d6fa9b43..7970efc804ae6 100644 --- a/Makefile +++ b/Makefile @@ -549,9 +549,6 @@ LINUXINCLUDE := \ -I$(objtree)/include \ $(USERINCLUDE) -# UBUNTU: Include our third party driver stuff too -LINUXINCLUDE += -I$(srctree)/ubuntu/include - KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE KBUILD_CFLAGS := @@ -738,8 +735,11 @@ endif ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit -core-y := -drivers-y := +core-y := init/ usr/ arch/$(SRCARCH)/ +drivers-y := drivers/ sound/ +drivers-$(CONFIG_SAMPLES) += samples/ +drivers-$(CONFIG_NET) += net/ +drivers-y += virt/ libs-y := lib/ endif # KBUILD_EXTMOD @@ -1297,7 +1297,6 @@ headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts $(if $(filter um, $(SRCARCH)), $(error Headers not exportable for UML)) $(Q)$(MAKE) $(hdr-inst)=include/uapi $(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi - $(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders= ifdef CONFIG_HEADERS_INSTALL prepare: headers diff --git a/debian.master/changelog b/debian.master/changelog index 2dd1a5f053b4d..ffb1956524406 100644 --- a/debian.master/changelog +++ b/debian.master/changelog @@ -1,3 +1,12 @@ +linux (6.8.0-47.47) noble; urgency=medium + + * noble/linux: 6.8.0-47.47 -proposed tracker (LP: #2082118) + + * CVE-2024-45016 + - netem: fix return value if duplicate enqueue fails + + -- Manuel Diewald Fri, 27 Sep 2024 19:21:30 +0200 + linux (6.8.0-45.45) noble; urgency=medium * noble/linux: 6.8.0-45.45 -proposed tracker (LP: #2078100) diff --git a/debian.master/config/annotations b/debian.master/config/annotations index a6af35a9299a2..401fdaec8d8fb 100644 --- a/debian.master/config/annotations +++ b/debian.master/config/annotations @@ -1,7 +1,7 @@ # Menu: HEADER # FORMAT: 4 -# ARCH: amd64 arm64 armhf ppc64el riscv64 s390x -# FLAVOUR: amd64-generic arm64-generic arm64-generic-64k armhf-generic ppc64el-generic riscv64-generic s390x-generic +# ARCH: amd64 +# FLAVOUR: amd64-generic CONFIG_ACCESSIBILITY policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 'riscv64': 'y', 's390x': 'n'}> CONFIG_ACCESSIBILITY note<'LP: #1967702'> @@ -3806,7 +3806,7 @@ CONFIG_DEBUG_CGROUP_REF policy<{'amd64': 'n', 'arm64': ' CONFIG_DEBUG_CLOSURES policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 'riscv64': 'n', 's390x': 'n'}> CONFIG_DEBUG_DEVRES policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 'riscv64': 'n', 's390x': 'n'}> CONFIG_DEBUG_DRIVER policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 'riscv64': 'n', 's390x': 'n'}> -CONFIG_DEBUG_EFI policy<{'arm64': 'n'}> +CONFIG_DEBUG_EFI policy<{'amd64': 'y', 'arm64': 'n'}> CONFIG_DEBUG_ENTRY policy<{'amd64': 'n', 's390x': 'n'}> CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B policy<{'amd64': 'n', 'arm64': 'n', 'ppc64el': 'n', 'riscv64': 'n', 's390x': 'n'}> CONFIG_DEBUG_FORCE_WEAK_PER_CPU policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 'riscv64': 'n', 's390x': 'n'}> @@ -4758,7 +4758,7 @@ CONFIG_EFI_SECRET policy<{'amd64': 'm'}> CONFIG_EFI_SOFT_RESERVE policy<{'amd64': 'y', 'arm64': 'y'}> CONFIG_EFI_STUB policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'riscv64': 'y'}> CONFIG_EFI_TEST policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'riscv64': 'm'}> -CONFIG_EFI_VARS_PSTORE policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'riscv64': 'm'}> +CONFIG_EFI_VARS_PSTORE policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'riscv64': 'm'}> CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'riscv64': 'n'}> CONFIG_EFS_FS policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm', 'riscv64': 'm', 's390x': 'n'}> CONFIG_EINT_MTK policy<{'arm64': 'y', 'armhf': 'y'}> diff --git a/debian.master/dkms-versions b/debian.master/dkms-versions index 82c3d68c356fa..378cbd0c13480 100644 --- a/debian.master/dkms-versions +++ b/debian.master/dkms-versions @@ -1,5 +1 @@ zfs-linux 2.2.2-0ubuntu9 modulename=zfs debpath=pool/universe/z/%package%/zfs-dkms_%version%_all.deb arch=amd64 arch=arm64 arch=ppc64el arch=s390x rprovides=spl-modules rprovides=spl-dkms rprovides=zfs-modules rprovides=zfs-dkms -ipu6-drivers 0~git202406240945.aecec2aa-0ubuntu2~24.04.1 modulename=ipu6 debpath=pool/universe/i/%package%/intel-ipu6-dkms_%version%_amd64.deb arch=amd64 rprovides=ipu6-modules rprovides=intel-ipu6-dkms type=standalone -backport-iwlwifi-dkms 11510-0ubuntu1 modulename=iwlwifi debpath=pool/universe/b/%package%/backport-iwlwifi-dkms_%version%_all.deb arch=amd64 rprovides=iwlwifi-modules rprovides=backport-iwlwifi-dkms type=standalone -v4l2loopback 0.12.7-2ubuntu5 modulename=v4l2loopback debpath=pool/universe/v/%package%/v4l2loopback-dkms_%version%_all.deb arch=amd64 rprovides=v4l2loopback-modules rprovides=v4l2loopback-dkms -usbio-drivers 0~git202312141918.78ffb706-0ubuntu2.1 modulename=usbio debpath=pool/universe/u/%package%/intel-usbio-dkms_%version%_amd64.deb arch=amd64 rprovides=usbio-modules rprovides=intel-usbio-dkms type=standalone diff --git a/debian.master/tracking-bug b/debian.master/tracking-bug index b254652d45ed0..f574657584485 100644 --- a/debian.master/tracking-bug +++ b/debian.master/tracking-bug @@ -1 +1 @@ -2078100 s2024.08.05-1 +2082118 s2024.09.02-1 diff --git a/debian/rules.d/0-common-vars.mk b/debian/rules.d/0-common-vars.mk index 5cd38f6f1b6c9..98347b798c5f1 100644 --- a/debian/rules.d/0-common-vars.mk +++ b/debian/rules.d/0-common-vars.mk @@ -201,7 +201,7 @@ kmake = make ARCH=$(build_arch) \ KERNELRELEASE=$(abi_release)-$(target_flavour) \ CONFIG_DEBUG_SECTION_MISMATCH=y \ KBUILD_BUILD_VERSION="$(uploadnum)" \ - CFLAGS_MODULE="-DPKG_ABI=$(abinum)" \ + CFLAGS_MODULE='-DPKG_ABI=\"$(abinum)\"' \ PYTHON=$(PYTHON) ifneq ($(LOCAL_ENV_CC),) kmake += CC="$(LOCAL_ENV_CC)" DISTCC_HOSTS="$(LOCAL_ENV_DISTCC_HOSTS)" diff --git a/debian/rules.d/2-binary-arch.mk b/debian/rules.d/2-binary-arch.mk index 89d1eb769ed90..7d1af53379f05 100644 --- a/debian/rules.d/2-binary-arch.mk +++ b/debian/rules.d/2-binary-arch.mk @@ -7,7 +7,7 @@ shlibdeps_opts = $(if $(CROSS_COMPILE),-- -l$(CROSS_COMPILE:%-=/usr/%)/lib) debian/scripts/fix-filenames: debian/scripts/fix-filenames.c $(HOSTCC) $^ -o $@ -$(stampdir)/stamp-prepare-%: config-prepare-check-% +$(stampdir)/stamp-prepare-%: $(stampdir)/stamp-prepare-tree-% @echo Debug: $@ $(stamp) diff --git a/delphix b/delphix new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 1d25e64b068a0..f1eed1d49c8a0 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3922,6 +3922,7 @@ int iscsi_target_tx_thread(void *arg) * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); + complete(&conn->kthr_start_comp); while (!kthread_should_stop()) { /* @@ -4170,6 +4171,7 @@ int iscsi_target_rx_thread(void *arg) * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); + complete(&conn->kthr_start_comp); /* * Wait for iscsi_post_login_handler() to complete before allowing * incoming iscsi/tcp socket I/O, and/or failing the connection. diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 6797200211836..26f3ecd25c28d 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1102,6 +1102,18 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) iscsit_inc_conn_usage_count(conn); + /* + * If the command was aborted, for instance following a LUN RESET, + * a dataout timeout might be normal. + */ + if (target_cmd_interrupted(&cmd->se_cmd)) { + pr_debug("DataOut timeout on interrupted cmd with" + " ITT[0x%08llx]\n", cmd->se_cmd.tag); + cmd->dataout_timer_flags &= ~ISCSI_TF_RUNNING; + iscsit_dec_conn_usage_count(conn); + return; + } + spin_lock_bh(&cmd->dataout_timeout_lock); if (cmd->dataout_timer_flags & ISCSI_TF_STOP) { spin_unlock_bh(&cmd->dataout_timeout_lock); @@ -1115,19 +1127,22 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) if (!sess->sess_ops->ErrorRecoveryLevel) { pr_err("Unable to recover from DataOut timeout while" " in ERL=0, closing iSCSI connection for I_T Nexus" - " %s,i,0x%6phN,%s,t,0x%02x\n", + " %s,i,0x%6phN,%s,t,0x%02x, cmd ITT[0x%08llx]\n", sess->sess_ops->InitiatorName, sess->isid, - sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt, + cmd->se_cmd.tag); goto failure; } if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) { pr_err("Command ITT: 0x%08x exceeded max retries" " for DataOUT timeout %u, closing iSCSI connection for" - " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", + " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x," + " cmd ITT[0x%08llx]\n", cmd->init_task_tag, na->dataout_timeout_retries, sess->sess_ops->InitiatorName, sess->isid, - sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt, + cmd->se_cmd.tag); goto failure; } diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 90b870f234f03..d564f9ae4db97 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -660,6 +660,7 @@ int iscsit_start_kthreads(struct iscsit_conn *conn) ret = PTR_ERR(conn->tx_thread); goto out_bitmap; } + wait_for_completion(&conn->kthr_start_comp); conn->tx_thread_active = true; conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, @@ -669,6 +670,7 @@ int iscsit_start_kthreads(struct iscsit_conn *conn) ret = PTR_ERR(conn->rx_thread); goto out_tx; } + wait_for_completion(&conn->kthr_start_comp); conn->rx_thread_active = true; return 0; @@ -1064,6 +1066,7 @@ static struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np) init_completion(&conn->rx_half_close_comp); init_completion(&conn->tx_half_close_comp); init_completion(&conn->rx_login_comp); + init_completion(&conn->kthr_start_comp); spin_lock_init(&conn->cmd_lock); spin_lock_init(&conn->conn_usage_lock); spin_lock_init(&conn->immed_queue_lock); @@ -1132,7 +1135,7 @@ void iscsi_target_login_sess_out(struct iscsit_conn *conn, if (!new_sess) goto old_sess_out; - pr_err("iSCSI Login negotiation failed.\n"); + pr_debug("iSCSI Login negotiation failed.\n"); iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, ISCSI_LOGIN_STATUS_INIT_ERR); if (!zero_tsih || !conn->sess) diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index fa3fb5f4e6bc4..5cddf8e60b3e6 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -1234,7 +1234,7 @@ int iscsi_target_locate_portal( */ tiqn = iscsit_get_tiqn_for_login(t_buf); if (!tiqn) { - pr_err("Unable to locate Target IQN: %s in" + pr_debug("Unable to locate Target IQN: %s in" " Storage Node\n", t_buf); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 73d0d6133ac8f..d37b2641bfe50 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -882,7 +882,7 @@ static void target_abort_work(struct work_struct *work) target_handle_abort(cmd); } -static bool target_cmd_interrupted(struct se_cmd *cmd) +bool target_cmd_interrupted(struct se_cmd *cmd) { int post_ret; @@ -901,6 +901,7 @@ static bool target_cmd_interrupted(struct se_cmd *cmd) return false; } +EXPORT_SYMBOL(target_cmd_interrupted); /* May be called from interrupt context so must not sleep. */ void target_complete_cmd_with_sense(struct se_cmd *cmd, u8 scsi_status, diff --git a/fs/namespace.c b/fs/namespace.c index 5a51315c66781..c8110a5ac85a5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -169,7 +169,7 @@ void mnt_release_group_id(struct mount *mnt) /* * vfsmount lock must be held for read */ -static inline void mnt_add_count(struct mount *mnt, int n) +static noinline __noclone void mnt_add_count(struct mount *mnt, int n) { #ifdef CONFIG_SMP this_cpu_add(mnt->mnt_pcp->mnt_count, n); @@ -1704,7 +1704,8 @@ static int do_umount_root(struct super_block *sb) return ret; } -static int do_umount(struct mount *mnt, int flags) +/* force a bpftrace dynamic function probe here */ +static noinline __noclone int do_umount(struct mount *mnt, int flags) { struct super_block *sb = mnt->mnt.mnt_sb; int retval; diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index 1cfc69cb7efbe..ee759c8245f64 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -18,6 +18,7 @@ #ifndef _ASM_GENERIC_MSHYPERV_H #define _ASM_GENERIC_MSHYPERV_H +#include #include #include #include @@ -120,7 +121,7 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, * Preserve the ability to 'make deb-pkg' since PKG_ABI is provided * by the Ubuntu build rules. */ -#define PKG_ABI 0 +#define PKG_ABI "0" #endif /* Generate the guest OS identifier as described in the Hyper-V TLFS */ @@ -130,7 +131,15 @@ static inline u64 hv_generate_guest_id(u64 kernel_version) guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48); guest_id |= (kernel_version << 16); - guest_id |= PKG_ABI; + /* + * Delphix mutates the ABI number by appending a date and the commit hash. Strip it. + */ + char *token; + char *pkg_abi_str = PKG_ABI; + token = strsep(&pkg_abi_str, "-"); + unsigned long abi_number = simple_strtoul(token, NULL, 10); + guest_id |= (abi_number << 8); + return guest_id; } diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 60af7c63b34e6..002f37b6366f5 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -550,6 +550,7 @@ struct iscsit_conn { struct completion conn_logout_comp; struct completion tx_half_close_comp; struct completion rx_half_close_comp; + struct completion kthr_start_comp; /* socket used by this connection */ struct socket *sock; void (*orig_data_ready)(struct sock *); diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 3378ff9ee271c..4f136a98df63e 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -191,6 +191,7 @@ sense_reason_t transport_generic_new_cmd(struct se_cmd *); void target_put_cmd_and_wait(struct se_cmd *cmd); void target_execute_cmd(struct se_cmd *cmd); +bool target_cmd_interrupted(struct se_cmd *cmd); int transport_generic_free_cmd(struct se_cmd *, int); diff --git a/include/uapi/linux/netfilter/xt_connmark.h b/include/uapi/linux/netfilter/xt_connmark.h index 41b578ccd03b8..36cc956ead1ae 100644 --- a/include/uapi/linux/netfilter/xt_connmark.h +++ b/include/uapi/linux/netfilter/xt_connmark.h @@ -1,37 +1,7 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* Copyright (C) 2002,2004 MARA Systems AB - * by Henrik Nordstrom - */ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _XT_CONNMARK_H_target +#define _XT_CONNMARK_H_target -#ifndef _XT_CONNMARK_H -#define _XT_CONNMARK_H +#include -#include - -enum { - XT_CONNMARK_SET = 0, - XT_CONNMARK_SAVE, - XT_CONNMARK_RESTORE -}; - -enum { - D_SHIFT_LEFT = 0, - D_SHIFT_RIGHT, -}; - -struct xt_connmark_tginfo1 { - __u32 ctmark, ctmask, nfmask; - __u8 mode; -}; - -struct xt_connmark_tginfo2 { - __u32 ctmark, ctmask, nfmask; - __u8 shift_dir, shift_bits, mode; -}; - -struct xt_connmark_mtinfo1 { - __u32 mark, mask; - __u8 invert; -}; - -#endif /*_XT_CONNMARK_H*/ +#endif /*_XT_CONNMARK_H_target*/ diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c index fb0169a8f9bbd..cfa44515ab72d 100644 --- a/net/netfilter/xt_dscp.c +++ b/net/netfilter/xt_dscp.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only -/* IP tables module for matching the value of the IPv4/IPv6 DSCP field +/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8 * * (C) 2002 by Harald Welte - */ + * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh + * + * See RFC2474 for a description of the DSCP field within the IP Header. +*/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -11,100 +14,148 @@ #include #include -#include +#include MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("Xtables: DSCP/TOS field match"); +MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("ipt_dscp"); -MODULE_ALIAS("ip6t_dscp"); -MODULE_ALIAS("ipt_tos"); -MODULE_ALIAS("ip6t_tos"); +MODULE_ALIAS("ipt_DSCP"); +MODULE_ALIAS("ip6t_DSCP"); +MODULE_ALIAS("ipt_TOS"); +MODULE_ALIAS("ip6t_TOS"); + +#define XT_DSCP_ECN_MASK 3u -static bool -dscp_mt(const struct sk_buff *skb, struct xt_action_param *par) +static unsigned int +dscp_tg(struct sk_buff *skb, const struct xt_action_param *par) { - const struct xt_dscp_info *info = par->matchinfo; + const struct xt_DSCP_info *dinfo = par->targinfo; u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; - return (dscp == info->dscp) ^ !!info->invert; + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct iphdr))) + return NF_DROP; + + ipv4_change_dsfield(ip_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); + + } + return XT_CONTINUE; } -static bool -dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par) +static unsigned int +dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par) { - const struct xt_dscp_info *info = par->matchinfo; + const struct xt_DSCP_info *dinfo = par->targinfo; u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; - return (dscp == info->dscp) ^ !!info->invert; + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct ipv6hdr))) + return NF_DROP; + + ipv6_change_dsfield(ipv6_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); + } + return XT_CONTINUE; } -static int dscp_mt_check(const struct xt_mtchk_param *par) +static int dscp_tg_check(const struct xt_tgchk_param *par) { - const struct xt_dscp_info *info = par->matchinfo; + const struct xt_DSCP_info *info = par->targinfo; if (info->dscp > XT_DSCP_MAX) return -EDOM; - return 0; } -static bool tos_mt(const struct sk_buff *skb, struct xt_action_param *par) +static unsigned int +tos_tg(struct sk_buff *skb, const struct xt_action_param *par) { - const struct xt_tos_match_info *info = par->matchinfo; - - if (xt_family(par) == NFPROTO_IPV4) - return ((ip_hdr(skb)->tos & info->tos_mask) == - info->tos_value) ^ !!info->invert; - else - return ((ipv6_get_dsfield(ipv6_hdr(skb)) & info->tos_mask) == - info->tos_value) ^ !!info->invert; + const struct xt_tos_target_info *info = par->targinfo; + struct iphdr *iph = ip_hdr(skb); + u_int8_t orig, nv; + + orig = ipv4_get_dsfield(iph); + nv = (orig & ~info->tos_mask) ^ info->tos_value; + + if (orig != nv) { + if (skb_ensure_writable(skb, sizeof(struct iphdr))) + return NF_DROP; + iph = ip_hdr(skb); + ipv4_change_dsfield(iph, 0, nv); + } + + return XT_CONTINUE; +} + +static unsigned int +tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_tos_target_info *info = par->targinfo; + struct ipv6hdr *iph = ipv6_hdr(skb); + u_int8_t orig, nv; + + orig = ipv6_get_dsfield(iph); + nv = (orig & ~info->tos_mask) ^ info->tos_value; + + if (orig != nv) { + if (skb_ensure_writable(skb, sizeof(struct iphdr))) + return NF_DROP; + iph = ipv6_hdr(skb); + ipv6_change_dsfield(iph, 0, nv); + } + + return XT_CONTINUE; } -static struct xt_match dscp_mt_reg[] __read_mostly = { +static struct xt_target dscp_tg_reg[] __read_mostly = { { - .name = "dscp", + .name = "DSCP", .family = NFPROTO_IPV4, - .checkentry = dscp_mt_check, - .match = dscp_mt, - .matchsize = sizeof(struct xt_dscp_info), + .checkentry = dscp_tg_check, + .target = dscp_tg, + .targetsize = sizeof(struct xt_DSCP_info), + .table = "mangle", .me = THIS_MODULE, }, { - .name = "dscp", + .name = "DSCP", .family = NFPROTO_IPV6, - .checkentry = dscp_mt_check, - .match = dscp_mt6, - .matchsize = sizeof(struct xt_dscp_info), + .checkentry = dscp_tg_check, + .target = dscp_tg6, + .targetsize = sizeof(struct xt_DSCP_info), + .table = "mangle", .me = THIS_MODULE, }, { - .name = "tos", + .name = "TOS", .revision = 1, .family = NFPROTO_IPV4, - .match = tos_mt, - .matchsize = sizeof(struct xt_tos_match_info), + .table = "mangle", + .target = tos_tg, + .targetsize = sizeof(struct xt_tos_target_info), .me = THIS_MODULE, }, { - .name = "tos", + .name = "TOS", .revision = 1, .family = NFPROTO_IPV6, - .match = tos_mt, - .matchsize = sizeof(struct xt_tos_match_info), + .table = "mangle", + .target = tos_tg6, + .targetsize = sizeof(struct xt_tos_target_info), .me = THIS_MODULE, }, }; -static int __init dscp_mt_init(void) +static int __init dscp_tg_init(void) { - return xt_register_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); + return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); } -static void __exit dscp_mt_exit(void) +static void __exit dscp_tg_exit(void) { - xt_unregister_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); + xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); } -module_init(dscp_mt_init); -module_exit(dscp_mt_exit); +module_init(dscp_tg_init); +module_exit(dscp_tg_exit); diff --git a/net/netfilter/xt_hl.c b/net/netfilter/xt_hl.c index c1a70f8f04417..7873b834c3004 100644 --- a/net/netfilter/xt_hl.c +++ b/net/netfilter/xt_hl.c @@ -1,93 +1,159 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * IP tables module for matching the value of the TTL - * (C) 2000,2001 by Harald Welte + * TTL modification target for IP tables + * (C) 2000,2005 by Harald Welte * - * Hop Limit matching module - * (C) 2001-2002 Maciej Soltysiak + * Hop Limit modification target for ip6tables + * Maciej Soltysiak */ - -#include -#include +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include +#include +#include +#include #include -#include -#include +#include +#include +MODULE_AUTHOR("Harald Welte "); MODULE_AUTHOR("Maciej Soltysiak "); -MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match"); +MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("ipt_ttl"); -MODULE_ALIAS("ip6t_hl"); -static bool ttl_mt(const struct sk_buff *skb, struct xt_action_param *par) +static unsigned int +ttl_tg(struct sk_buff *skb, const struct xt_action_param *par) { - const struct ipt_ttl_info *info = par->matchinfo; - const u8 ttl = ip_hdr(skb)->ttl; + struct iphdr *iph; + const struct ipt_TTL_info *info = par->targinfo; + int new_ttl; + + if (skb_ensure_writable(skb, sizeof(*iph))) + return NF_DROP; + + iph = ip_hdr(skb); switch (info->mode) { - case IPT_TTL_EQ: - return ttl == info->ttl; - case IPT_TTL_NE: - return ttl != info->ttl; - case IPT_TTL_LT: - return ttl < info->ttl; - case IPT_TTL_GT: - return ttl > info->ttl; + case IPT_TTL_SET: + new_ttl = info->ttl; + break; + case IPT_TTL_INC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl > 255) + new_ttl = 255; + break; + case IPT_TTL_DEC: + new_ttl = iph->ttl - info->ttl; + if (new_ttl < 0) + new_ttl = 0; + break; + default: + new_ttl = iph->ttl; + break; } - return false; + if (new_ttl != iph->ttl) { + csum_replace2(&iph->check, htons(iph->ttl << 8), + htons(new_ttl << 8)); + iph->ttl = new_ttl; + } + + return XT_CONTINUE; } -static bool hl_mt6(const struct sk_buff *skb, struct xt_action_param *par) +static unsigned int +hl_tg6(struct sk_buff *skb, const struct xt_action_param *par) { - const struct ip6t_hl_info *info = par->matchinfo; - const struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct ipv6hdr *ip6h; + const struct ip6t_HL_info *info = par->targinfo; + int new_hl; + + if (skb_ensure_writable(skb, sizeof(*ip6h))) + return NF_DROP; + + ip6h = ipv6_hdr(skb); switch (info->mode) { - case IP6T_HL_EQ: - return ip6h->hop_limit == info->hop_limit; - case IP6T_HL_NE: - return ip6h->hop_limit != info->hop_limit; - case IP6T_HL_LT: - return ip6h->hop_limit < info->hop_limit; - case IP6T_HL_GT: - return ip6h->hop_limit > info->hop_limit; + case IP6T_HL_SET: + new_hl = info->hop_limit; + break; + case IP6T_HL_INC: + new_hl = ip6h->hop_limit + info->hop_limit; + if (new_hl > 255) + new_hl = 255; + break; + case IP6T_HL_DEC: + new_hl = ip6h->hop_limit - info->hop_limit; + if (new_hl < 0) + new_hl = 0; + break; + default: + new_hl = ip6h->hop_limit; + break; } - return false; + ip6h->hop_limit = new_hl; + + return XT_CONTINUE; +} + +static int ttl_tg_check(const struct xt_tgchk_param *par) +{ + const struct ipt_TTL_info *info = par->targinfo; + + if (info->mode > IPT_TTL_MAXMODE) + return -EINVAL; + if (info->mode != IPT_TTL_SET && info->ttl == 0) + return -EINVAL; + return 0; +} + +static int hl_tg6_check(const struct xt_tgchk_param *par) +{ + const struct ip6t_HL_info *info = par->targinfo; + + if (info->mode > IP6T_HL_MAXMODE) + return -EINVAL; + if (info->mode != IP6T_HL_SET && info->hop_limit == 0) + return -EINVAL; + return 0; } -static struct xt_match hl_mt_reg[] __read_mostly = { +static struct xt_target hl_tg_reg[] __read_mostly = { { - .name = "ttl", + .name = "TTL", .revision = 0, .family = NFPROTO_IPV4, - .match = ttl_mt, - .matchsize = sizeof(struct ipt_ttl_info), + .target = ttl_tg, + .targetsize = sizeof(struct ipt_TTL_info), + .table = "mangle", + .checkentry = ttl_tg_check, .me = THIS_MODULE, }, { - .name = "hl", + .name = "HL", .revision = 0, .family = NFPROTO_IPV6, - .match = hl_mt6, - .matchsize = sizeof(struct ip6t_hl_info), + .target = hl_tg6, + .targetsize = sizeof(struct ip6t_HL_info), + .table = "mangle", + .checkentry = hl_tg6_check, .me = THIS_MODULE, }, }; -static int __init hl_mt_init(void) +static int __init hl_tg_init(void) { - return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); + return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); } -static void __exit hl_mt_exit(void) +static void __exit hl_tg_exit(void) { - xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); + xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); } -module_init(hl_mt_init); -module_exit(hl_mt_exit); +module_init(hl_tg_init); +module_exit(hl_tg_exit); +MODULE_ALIAS("ipt_TTL"); +MODULE_ALIAS("ip6t_HL"); diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index 72324bd976af8..80f6624e23554 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c @@ -5,149 +5,229 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include +#define RATEEST_HSIZE 16 -static bool -xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) +struct xt_rateest_net { + struct mutex hash_lock; + struct hlist_head hash[RATEEST_HSIZE]; +}; + +static unsigned int xt_rateest_id; + +static unsigned int jhash_rnd __read_mostly; + +static unsigned int xt_rateest_hash(const char *name) { - const struct xt_rateest_match_info *info = par->matchinfo; - struct gnet_stats_rate_est64 sample = {0}; - u_int32_t bps1, bps2, pps1, pps2; - bool ret = true; - - gen_estimator_read(&info->est1->rate_est, &sample); - - if (info->flags & XT_RATEEST_MATCH_DELTA) { - bps1 = info->bps1 >= sample.bps ? info->bps1 - sample.bps : 0; - pps1 = info->pps1 >= sample.pps ? info->pps1 - sample.pps : 0; - } else { - bps1 = sample.bps; - pps1 = sample.pps; - } + return jhash(name, sizeof_field(struct xt_rateest, name), jhash_rnd) & + (RATEEST_HSIZE - 1); +} + +static void xt_rateest_hash_insert(struct xt_rateest_net *xn, + struct xt_rateest *est) +{ + unsigned int h; + + h = xt_rateest_hash(est->name); + hlist_add_head(&est->list, &xn->hash[h]); +} - if (info->flags & XT_RATEEST_MATCH_ABS) { - bps2 = info->bps2; - pps2 = info->pps2; - } else { - gen_estimator_read(&info->est2->rate_est, &sample); - - if (info->flags & XT_RATEEST_MATCH_DELTA) { - bps2 = info->bps2 >= sample.bps ? info->bps2 - sample.bps : 0; - pps2 = info->pps2 >= sample.pps ? info->pps2 - sample.pps : 0; - } else { - bps2 = sample.bps; - pps2 = sample.pps; +static struct xt_rateest *__xt_rateest_lookup(struct xt_rateest_net *xn, + const char *name) +{ + struct xt_rateest *est; + unsigned int h; + + h = xt_rateest_hash(name); + hlist_for_each_entry(est, &xn->hash[h], list) { + if (strcmp(est->name, name) == 0) { + est->refcnt++; + return est; } } - switch (info->mode) { - case XT_RATEEST_MATCH_LT: - if (info->flags & XT_RATEEST_MATCH_BPS) - ret &= bps1 < bps2; - if (info->flags & XT_RATEEST_MATCH_PPS) - ret &= pps1 < pps2; - break; - case XT_RATEEST_MATCH_GT: - if (info->flags & XT_RATEEST_MATCH_BPS) - ret &= bps1 > bps2; - if (info->flags & XT_RATEEST_MATCH_PPS) - ret &= pps1 > pps2; - break; - case XT_RATEEST_MATCH_EQ: - if (info->flags & XT_RATEEST_MATCH_BPS) - ret &= bps1 == bps2; - if (info->flags & XT_RATEEST_MATCH_PPS) - ret &= pps1 == pps2; - break; - } + return NULL; +} - ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false; - return ret; +struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name) +{ + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + struct xt_rateest *est; + + mutex_lock(&xn->hash_lock); + est = __xt_rateest_lookup(xn, name); + mutex_unlock(&xn->hash_lock); + return est; } +EXPORT_SYMBOL_GPL(xt_rateest_lookup); -static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) +void xt_rateest_put(struct net *net, struct xt_rateest *est) { - struct xt_rateest_match_info *info = par->matchinfo; - struct xt_rateest *est1, *est2; - int ret = -EINVAL; + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + + mutex_lock(&xn->hash_lock); + if (--est->refcnt == 0) { + hlist_del(&est->list); + gen_kill_estimator(&est->rate_est); + /* + * gen_estimator est_timer() might access est->lock or bstats, + * wait a RCU grace period before freeing 'est' + */ + kfree_rcu(est, rcu); + } + mutex_unlock(&xn->hash_lock); +} +EXPORT_SYMBOL_GPL(xt_rateest_put); - if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | - XT_RATEEST_MATCH_REL)) != 1) - goto err1; +static unsigned int +xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_rateest_target_info *info = par->targinfo; + struct gnet_stats_basic_sync *stats = &info->est->bstats; - if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS))) - goto err1; + spin_lock_bh(&info->est->lock); + u64_stats_add(&stats->bytes, skb->len); + u64_stats_inc(&stats->packets); + spin_unlock_bh(&info->est->lock); - switch (info->mode) { - case XT_RATEEST_MATCH_EQ: - case XT_RATEEST_MATCH_LT: - case XT_RATEEST_MATCH_GT: - break; - default: - goto err1; + return XT_CONTINUE; +} + +static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) +{ + struct xt_rateest_net *xn = net_generic(par->net, xt_rateest_id); + struct xt_rateest_target_info *info = par->targinfo; + struct xt_rateest *est; + struct { + struct nlattr opt; + struct gnet_estimator est; + } cfg; + int ret; + + if (strnlen(info->name, sizeof(est->name)) >= sizeof(est->name)) + return -ENAMETOOLONG; + + net_get_random_once(&jhash_rnd, sizeof(jhash_rnd)); + + mutex_lock(&xn->hash_lock); + est = __xt_rateest_lookup(xn, info->name); + if (est) { + mutex_unlock(&xn->hash_lock); + /* + * If estimator parameters are specified, they must match the + * existing estimator. + */ + if ((!info->interval && !info->ewma_log) || + (info->interval != est->params.interval || + info->ewma_log != est->params.ewma_log)) { + xt_rateest_put(par->net, est); + return -EINVAL; + } + info->est = est; + return 0; } - ret = -ENOENT; - est1 = xt_rateest_lookup(par->net, info->name1); - if (!est1) + ret = -ENOMEM; + est = kzalloc(sizeof(*est), GFP_KERNEL); + if (!est) goto err1; - est2 = NULL; - if (info->flags & XT_RATEEST_MATCH_REL) { - est2 = xt_rateest_lookup(par->net, info->name2); - if (!est2) - goto err2; - } - - info->est1 = est1; - info->est2 = est2; + gnet_stats_basic_sync_init(&est->bstats); + strscpy(est->name, info->name, sizeof(est->name)); + spin_lock_init(&est->lock); + est->refcnt = 1; + est->params.interval = info->interval; + est->params.ewma_log = info->ewma_log; + + cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est)); + cfg.opt.nla_type = TCA_STATS_RATE_EST; + cfg.est.interval = info->interval; + cfg.est.ewma_log = info->ewma_log; + + ret = gen_new_estimator(&est->bstats, NULL, &est->rate_est, + &est->lock, NULL, &cfg.opt); + if (ret < 0) + goto err2; + + info->est = est; + xt_rateest_hash_insert(xn, est); + mutex_unlock(&xn->hash_lock); return 0; err2: - xt_rateest_put(par->net, est1); + kfree(est); err1: + mutex_unlock(&xn->hash_lock); return ret; } -static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) +static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) { - struct xt_rateest_match_info *info = par->matchinfo; + struct xt_rateest_target_info *info = par->targinfo; - xt_rateest_put(par->net, info->est1); - if (info->est2) - xt_rateest_put(par->net, info->est2); + xt_rateest_put(par->net, info->est); } -static struct xt_match xt_rateest_mt_reg __read_mostly = { - .name = "rateest", +static struct xt_target xt_rateest_tg_reg __read_mostly = { + .name = "RATEEST", .revision = 0, .family = NFPROTO_UNSPEC, - .match = xt_rateest_mt, - .checkentry = xt_rateest_mt_checkentry, - .destroy = xt_rateest_mt_destroy, - .matchsize = sizeof(struct xt_rateest_match_info), - .usersize = offsetof(struct xt_rateest_match_info, est1), + .target = xt_rateest_tg, + .checkentry = xt_rateest_tg_checkentry, + .destroy = xt_rateest_tg_destroy, + .targetsize = sizeof(struct xt_rateest_target_info), + .usersize = offsetof(struct xt_rateest_target_info, est), .me = THIS_MODULE, }; -static int __init xt_rateest_mt_init(void) +static __net_init int xt_rateest_net_init(struct net *net) { - return xt_register_match(&xt_rateest_mt_reg); + struct xt_rateest_net *xn = net_generic(net, xt_rateest_id); + int i; + + mutex_init(&xn->hash_lock); + for (i = 0; i < ARRAY_SIZE(xn->hash); i++) + INIT_HLIST_HEAD(&xn->hash[i]); + return 0; } -static void __exit xt_rateest_mt_fini(void) +static struct pernet_operations xt_rateest_net_ops = { + .init = xt_rateest_net_init, + .id = &xt_rateest_id, + .size = sizeof(struct xt_rateest_net), +}; + +static int __init xt_rateest_tg_init(void) { - xt_unregister_match(&xt_rateest_mt_reg); + int err = register_pernet_subsys(&xt_rateest_net_ops); + + if (err) + return err; + return xt_register_target(&xt_rateest_tg_reg); } +static void __exit xt_rateest_tg_fini(void) +{ + xt_unregister_target(&xt_rateest_tg_reg); + unregister_pernet_subsys(&xt_rateest_net_ops); +} + + MODULE_AUTHOR("Patrick McHardy "); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("xtables rate estimator match"); -MODULE_ALIAS("ipt_rateest"); -MODULE_ALIAS("ip6t_rateest"); -module_init(xt_rateest_mt_init); -module_exit(xt_rateest_mt_fini); +MODULE_DESCRIPTION("Xtables: packet rate estimator"); +MODULE_ALIAS("ipt_RATEEST"); +MODULE_ALIAS("ip6t_RATEEST"); +module_init(xt_rateest_tg_init); +module_exit(xt_rateest_tg_fini); diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index fa678eb885284..0d29d0ccf8cb2 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -446,12 +446,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct netem_sched_data *q = qdisc_priv(sch); /* We don't fill cb now as skb_unshare() may invalidate it */ struct netem_skb_cb *cb; - struct sk_buff *skb2; + struct sk_buff *skb2 = NULL; struct sk_buff *segs = NULL; unsigned int prev_len = qdisc_pkt_len(skb); int count = 1; - int rc = NET_XMIT_SUCCESS; - int rc_drop = NET_XMIT_DROP; /* Do not fool qdisc_drop_all() */ skb->prev = NULL; @@ -480,19 +478,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, skb_orphan_partial(skb); /* - * If we need to duplicate packet, then re-insert at top of the - * qdisc tree, since parent queuer expects that only one - * skb will be queued. + * If we need to duplicate packet, then clone it before + * original is modified. */ - if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { - struct Qdisc *rootq = qdisc_root_bh(sch); - u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ - - q->duplicate = 0; - rootq->enqueue(skb2, rootq, to_free); - q->duplicate = dupsave; - rc_drop = NET_XMIT_SUCCESS; - } + if (count > 1) + skb2 = skb_clone(skb, GFP_ATOMIC); /* * Randomized packet corruption. @@ -504,7 +494,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (skb_is_gso(skb)) { skb = netem_segment(skb, sch, to_free); if (!skb) - return rc_drop; + goto finish_segs; + segs = skb->next; skb_mark_not_on_list(skb); qdisc_skb_cb(skb)->pkt_len = skb->len; @@ -530,7 +521,24 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* re-link segs, so that qdisc_drop_all() frees them all */ skb->next = segs; qdisc_drop_all(skb, sch, to_free); - return rc_drop; + if (skb2) + __qdisc_drop(skb2, to_free); + return NET_XMIT_DROP; + } + + /* + * If doing duplication then re-insert at top of the + * qdisc tree, since parent queuer expects that only one + * skb will be queued. + */ + if (skb2) { + struct Qdisc *rootq = qdisc_root_bh(sch); + u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ + + q->duplicate = 0; + rootq->enqueue(skb2, rootq, to_free); + q->duplicate = dupsave; + skb2 = NULL; } qdisc_qstats_backlog_inc(sch, skb); @@ -601,9 +609,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } finish_segs: + if (skb2) + __qdisc_drop(skb2, to_free); + if (segs) { unsigned int len, last_len; - int nb; + int rc, nb; len = skb ? skb->len : 0; nb = skb ? 1 : 0; diff --git a/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus b/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus index 10a2aa04cd078..415248fb66990 100644 --- a/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus +++ b/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus @@ -1,11 +1,12 @@ -C Z6.0+pooncelock+pooncelock+pombonce +C Z6.0+pooncelock+poonceLock+pombonce (* - * Result: Sometimes + * Result: Never * - * This example demonstrates that a pair of accesses made by different - * processes each while holding a given lock will not necessarily be - * seen as ordered by a third process not holding that lock. + * This litmus test demonstrates how smp_mb__after_spinlock() may be + * used to ensure that accesses in different critical sections for a + * given lock running on different CPUs are nevertheless seen in order + * by CPUs not holding that lock. *) {} @@ -23,6 +24,7 @@ P1(int *y, int *z, spinlock_t *mylock) int r0; spin_lock(mylock); + smp_mb__after_spinlock(); r0 = READ_ONCE(*y); WRITE_ONCE(*z, 1); spin_unlock(mylock);