diff options
author | Mike Pagano <mpagano@gentoo.org> | 2022-07-07 12:17:19 -0400 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2022-07-07 12:17:19 -0400 |
commit | c98a3a7b4905a9a65a5438e8c3d1d11cc968c721 (patch) | |
tree | a5d4bea850bce1290194577bf0c753cb789331e5 | |
parent | Linux patch 5.10.128 (diff) | |
download | linux-patches-c98a3a7b4905a9a65a5438e8c3d1d11cc968c721.tar.gz linux-patches-c98a3a7b4905a9a65a5438e8c3d1d11cc968c721.tar.bz2 linux-patches-c98a3a7b4905a9a65a5438e8c3d1d11cc968c721.zip |
Linux patch 5.10.1295.10-138
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1128_linux-5.10.129.patch | 5672 |
2 files changed, 5676 insertions, 0 deletions
diff --git a/0000_README b/0000_README index 26bbe9cb..42dc1c5f 100644 --- a/0000_README +++ b/0000_README @@ -555,6 +555,10 @@ Patch: 1127_linux-5.10.128.patch From: http://www.kernel.org Desc: Linux 5.10.128 +Patch: 1128_linux-5.10.129.patch +From: http://www.kernel.org +Desc: Linux 5.10.129 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1128_linux-5.10.129.patch b/1128_linux-5.10.129.patch new file mode 100644 index 00000000..e0d3e800 --- /dev/null +++ b/1128_linux-5.10.129.patch @@ -0,0 +1,5672 @@ +diff --git a/Makefile b/Makefile +index b89ad8a987db8..7d52cee374880 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 10 +-SUBLEVEL = 128 ++SUBLEVEL = 129 + EXTRAVERSION = + NAME = Dare mighty things + +diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c +index acb464547a54f..4a1991a103ea0 100644 +--- a/arch/arm/xen/p2m.c ++++ b/arch/arm/xen/p2m.c +@@ -62,11 +62,12 @@ out: + + unsigned long __pfn_to_mfn(unsigned long pfn) + { +- struct rb_node *n = phys_to_mach.rb_node; ++ struct rb_node *n; + struct xen_p2m_entry *entry; + unsigned long irqflags; + + read_lock_irqsave(&p2m_lock, irqflags); ++ n = phys_to_mach.rb_node; + while (n) { + entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys); + if (entry->pfn <= pfn && +@@ -153,10 +154,11 @@ bool __set_phys_to_machine_multi(unsigned long pfn, + int rc; + unsigned long irqflags; + struct xen_p2m_entry *p2m_entry; +- struct rb_node *n = phys_to_mach.rb_node; ++ struct rb_node *n; + + if (mfn == INVALID_P2M_ENTRY) { + write_lock_irqsave(&p2m_lock, irqflags); ++ n = phys_to_mach.rb_node; + while (n) { + p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys); + if (p2m_entry->pfn <= pfn && +diff --git a/arch/powerpc/include/asm/bpf_perf_event.h b/arch/powerpc/include/asm/bpf_perf_event.h +new file mode 100644 +index 0000000000000..e8a7b4ffb58c2 +--- /dev/null ++++ b/arch/powerpc/include/asm/bpf_perf_event.h +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _ASM_POWERPC_BPF_PERF_EVENT_H ++#define _ASM_POWERPC_BPF_PERF_EVENT_H ++ ++#include <asm/ptrace.h> ++ ++typedef struct user_pt_regs bpf_user_pt_regs_t; ++ ++#endif /* _ASM_POWERPC_BPF_PERF_EVENT_H */ +diff --git a/arch/powerpc/include/uapi/asm/bpf_perf_event.h b/arch/powerpc/include/uapi/asm/bpf_perf_event.h +deleted file mode 100644 +index 5e1e648aeec4c..0000000000000 +--- a/arch/powerpc/include/uapi/asm/bpf_perf_event.h ++++ /dev/null +@@ -1,9 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +-#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__ +-#define _UAPI__ASM_BPF_PERF_EVENT_H__ +- +-#include <asm/ptrace.h> +- +-typedef struct user_pt_regs bpf_user_pt_regs_t; +- +-#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */ +diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh +index b183ab9c5107c..dfa5f729f774d 100644 +--- a/arch/powerpc/kernel/prom_init_check.sh ++++ b/arch/powerpc/kernel/prom_init_check.sh +@@ -13,7 +13,7 @@ + # If you really need to reference something from prom_init.o add + # it to the list below: + +-grep "^CONFIG_KASAN=y$" .config >/dev/null ++grep "^CONFIG_KASAN=y$" ${KCONFIG_CONFIG} >/dev/null + if [ $? -eq 0 ] + then + MEM_FUNCS="__memcpy __memset" +diff --git a/arch/powerpc/mm/nohash/book3e_pgtable.c b/arch/powerpc/mm/nohash/book3e_pgtable.c +index 77884e24281dd..3d845e001c874 100644 +--- a/arch/powerpc/mm/nohash/book3e_pgtable.c ++++ b/arch/powerpc/mm/nohash/book3e_pgtable.c +@@ -95,8 +95,8 @@ int __ref map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) + pgdp = pgd_offset_k(ea); + p4dp = p4d_offset(pgdp, ea); + if (p4d_none(*p4dp)) { +- pmdp = early_alloc_pgtable(PMD_TABLE_SIZE); +- p4d_populate(&init_mm, p4dp, pmdp); ++ pudp = early_alloc_pgtable(PUD_TABLE_SIZE); ++ p4d_populate(&init_mm, p4dp, pudp); + } + pudp = pud_offset(p4dp, ea); + if (pud_none(*pudp)) { +@@ -105,7 +105,7 @@ int __ref map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) + } + pmdp = pmd_offset(pudp, ea); + if (!pmd_present(*pmdp)) { +- ptep = early_alloc_pgtable(PAGE_SIZE); ++ ptep = early_alloc_pgtable(PTE_TABLE_SIZE); + pmd_populate_kernel(&init_mm, pmdp, ptep); + } + ptep = pte_offset_kernel(pmdp, ea); +diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig +index 896b68e541b2e..878993982e39d 100644 +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -507,7 +507,6 @@ config KEXEC + config KEXEC_FILE + bool "kexec file based system call" + select KEXEC_CORE +- select BUILD_BIN2C + depends on CRYPTO + depends on CRYPTO_SHA256 + depends on CRYPTO_SHA256_S390 +diff --git a/arch/s390/crypto/arch_random.c b/arch/s390/crypto/arch_random.c +index 4cbb4b6d85a83..1f2d40993c4d2 100644 +--- a/arch/s390/crypto/arch_random.c ++++ b/arch/s390/crypto/arch_random.c +@@ -2,126 +2,17 @@ + /* + * s390 arch random implementation. + * +- * Copyright IBM Corp. 2017, 2018 ++ * Copyright IBM Corp. 2017, 2020 + * Author(s): Harald Freudenberger +- * +- * The s390_arch_random_generate() function may be called from random.c +- * in interrupt context. So this implementation does the best to be very +- * fast. There is a buffer of random data which is asynchronously checked +- * and filled by a workqueue thread. +- * If there are enough bytes in the buffer the s390_arch_random_generate() +- * just delivers these bytes. Otherwise false is returned until the +- * worker thread refills the buffer. +- * The worker fills the rng buffer by pulling fresh entropy from the +- * high quality (but slow) true hardware random generator. This entropy +- * is then spread over the buffer with an pseudo random generator PRNG. +- * As the arch_get_random_seed_long() fetches 8 bytes and the calling +- * function add_interrupt_randomness() counts this as 1 bit entropy the +- * distribution needs to make sure there is in fact 1 bit entropy contained +- * in 8 bytes of the buffer. The current values pull 32 byte entropy +- * and scatter this into a 2048 byte buffer. So 8 byte in the buffer +- * will contain 1 bit of entropy. +- * The worker thread is rescheduled based on the charge level of the +- * buffer but at least with 500 ms delay to avoid too much CPU consumption. +- * So the max. amount of rng data delivered via arch_get_random_seed is +- * limited to 4k bytes per second. + */ + + #include <linux/kernel.h> + #include <linux/atomic.h> + #include <linux/random.h> +-#include <linux/slab.h> + #include <linux/static_key.h> +-#include <linux/workqueue.h> + #include <asm/cpacf.h> + + DEFINE_STATIC_KEY_FALSE(s390_arch_random_available); + + atomic64_t s390_arch_random_counter = ATOMIC64_INIT(0); + EXPORT_SYMBOL(s390_arch_random_counter); +- +-#define ARCH_REFILL_TICKS (HZ/2) +-#define ARCH_PRNG_SEED_SIZE 32 +-#define ARCH_RNG_BUF_SIZE 2048 +- +-static DEFINE_SPINLOCK(arch_rng_lock); +-static u8 *arch_rng_buf; +-static unsigned int arch_rng_buf_idx; +- +-static void arch_rng_refill_buffer(struct work_struct *); +-static DECLARE_DELAYED_WORK(arch_rng_work, arch_rng_refill_buffer); +- +-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes) +-{ +- /* max hunk is ARCH_RNG_BUF_SIZE */ +- if (nbytes > ARCH_RNG_BUF_SIZE) +- return false; +- +- /* lock rng buffer */ +- if (!spin_trylock(&arch_rng_lock)) +- return false; +- +- /* try to resolve the requested amount of bytes from the buffer */ +- arch_rng_buf_idx -= nbytes; +- if (arch_rng_buf_idx < ARCH_RNG_BUF_SIZE) { +- memcpy(buf, arch_rng_buf + arch_rng_buf_idx, nbytes); +- atomic64_add(nbytes, &s390_arch_random_counter); +- spin_unlock(&arch_rng_lock); +- return true; +- } +- +- /* not enough bytes in rng buffer, refill is done asynchronously */ +- spin_unlock(&arch_rng_lock); +- +- return false; +-} +-EXPORT_SYMBOL(s390_arch_random_generate); +- +-static void arch_rng_refill_buffer(struct work_struct *unused) +-{ +- unsigned int delay = ARCH_REFILL_TICKS; +- +- spin_lock(&arch_rng_lock); +- if (arch_rng_buf_idx > ARCH_RNG_BUF_SIZE) { +- /* buffer is exhausted and needs refill */ +- u8 seed[ARCH_PRNG_SEED_SIZE]; +- u8 prng_wa[240]; +- /* fetch ARCH_PRNG_SEED_SIZE bytes of entropy */ +- cpacf_trng(NULL, 0, seed, sizeof(seed)); +- /* blow this entropy up to ARCH_RNG_BUF_SIZE with PRNG */ +- memset(prng_wa, 0, sizeof(prng_wa)); +- cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, +- &prng_wa, NULL, 0, seed, sizeof(seed)); +- cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, +- &prng_wa, arch_rng_buf, ARCH_RNG_BUF_SIZE, NULL, 0); +- arch_rng_buf_idx = ARCH_RNG_BUF_SIZE; +- } +- delay += (ARCH_REFILL_TICKS * arch_rng_buf_idx) / ARCH_RNG_BUF_SIZE; +- spin_unlock(&arch_rng_lock); +- +- /* kick next check */ +- queue_delayed_work(system_long_wq, &arch_rng_work, delay); +-} +- +-static int __init s390_arch_random_init(void) +-{ +- /* all the needed PRNO subfunctions available ? */ +- if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG) && +- cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) { +- +- /* alloc arch random working buffer */ +- arch_rng_buf = kmalloc(ARCH_RNG_BUF_SIZE, GFP_KERNEL); +- if (!arch_rng_buf) +- return -ENOMEM; +- +- /* kick worker queue job to fill the random buffer */ +- queue_delayed_work(system_long_wq, +- &arch_rng_work, ARCH_REFILL_TICKS); +- +- /* enable arch random to the outside world */ +- static_branch_enable(&s390_arch_random_available); +- } +- +- return 0; +-} +-arch_initcall(s390_arch_random_init); +diff --git a/arch/s390/include/asm/archrandom.h b/arch/s390/include/asm/archrandom.h +index de61ce5620527..2c6e1c6ecbe78 100644 +--- a/arch/s390/include/asm/archrandom.h ++++ b/arch/s390/include/asm/archrandom.h +@@ -2,7 +2,7 @@ + /* + * Kernel interface for the s390 arch_random_* functions + * +- * Copyright IBM Corp. 2017 ++ * Copyright IBM Corp. 2017, 2020 + * + * Author: Harald Freudenberger <freude@de.ibm.com> + * +@@ -15,12 +15,11 @@ + + #include <linux/static_key.h> + #include <linux/atomic.h> ++#include <asm/cpacf.h> + + DECLARE_STATIC_KEY_FALSE(s390_arch_random_available); + extern atomic64_t s390_arch_random_counter; + +-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes); +- + static inline bool __must_check arch_get_random_long(unsigned long *v) + { + return false; +@@ -34,7 +33,9 @@ static inline bool __must_check arch_get_random_int(unsigned int *v) + static inline bool __must_check arch_get_random_seed_long(unsigned long *v) + { + if (static_branch_likely(&s390_arch_random_available)) { +- return s390_arch_random_generate((u8 *)v, sizeof(*v)); ++ cpacf_trng(NULL, 0, (u8 *)v, sizeof(*v)); ++ atomic64_add(sizeof(*v), &s390_arch_random_counter); ++ return true; + } + return false; + } +@@ -42,7 +43,9 @@ static inline bool __must_check arch_get_random_seed_long(unsigned long *v) + static inline bool __must_check arch_get_random_seed_int(unsigned int *v) + { + if (static_branch_likely(&s390_arch_random_available)) { +- return s390_arch_random_generate((u8 *)v, sizeof(*v)); ++ cpacf_trng(NULL, 0, (u8 *)v, sizeof(*v)); ++ atomic64_add(sizeof(*v), &s390_arch_random_counter); ++ return true; + } + return false; + } +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index f9f8721dc5321..520cf5a152cf4 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -1009,6 +1009,11 @@ static void __init setup_randomness(void) + if (stsi(vmms, 3, 2, 2) == 0 && vmms->count) + add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count); + memblock_free((unsigned long) vmms, PAGE_SIZE); ++ ++#ifdef CONFIG_ARCH_RANDOM ++ if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG)) ++ static_branch_enable(&s390_arch_random_available); ++#endif + } + + /* +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index 47d4bb23d6f31..abbb68b6d9bd5 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -151,6 +151,10 @@ static unsigned int xen_blkif_max_ring_order; + module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444); + MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring"); + ++static bool __read_mostly xen_blkif_trusted = true; ++module_param_named(trusted, xen_blkif_trusted, bool, 0644); ++MODULE_PARM_DESC(trusted, "Is the backend trusted"); ++ + #define BLK_RING_SIZE(info) \ + __CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages) + +@@ -208,6 +212,7 @@ struct blkfront_info + unsigned int feature_discard:1; + unsigned int feature_secdiscard:1; + unsigned int feature_persistent:1; ++ unsigned int bounce:1; + unsigned int discard_granularity; + unsigned int discard_alignment; + /* Number of 4KB segments handled */ +@@ -310,8 +315,8 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num) + if (!gnt_list_entry) + goto out_of_memory; + +- if (info->feature_persistent) { +- granted_page = alloc_page(GFP_NOIO); ++ if (info->bounce) { ++ granted_page = alloc_page(GFP_NOIO | __GFP_ZERO); + if (!granted_page) { + kfree(gnt_list_entry); + goto out_of_memory; +@@ -330,7 +335,7 @@ out_of_memory: + list_for_each_entry_safe(gnt_list_entry, n, + &rinfo->grants, node) { + list_del(&gnt_list_entry->node); +- if (info->feature_persistent) ++ if (info->bounce) + __free_page(gnt_list_entry->page); + kfree(gnt_list_entry); + i--; +@@ -376,7 +381,7 @@ static struct grant *get_grant(grant_ref_t *gref_head, + /* Assign a gref to this page */ + gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); + BUG_ON(gnt_list_entry->gref == -ENOSPC); +- if (info->feature_persistent) ++ if (info->bounce) + grant_foreign_access(gnt_list_entry, info); + else { + /* Grant access to the GFN passed by the caller */ +@@ -400,7 +405,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head, + /* Assign a gref to this page */ + gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); + BUG_ON(gnt_list_entry->gref == -ENOSPC); +- if (!info->feature_persistent) { ++ if (!info->bounce) { + struct page *indirect_page; + + /* Fetch a pre-allocated page to use for indirect grefs */ +@@ -715,7 +720,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri + .grant_idx = 0, + .segments = NULL, + .rinfo = rinfo, +- .need_copy = rq_data_dir(req) && info->feature_persistent, ++ .need_copy = rq_data_dir(req) && info->bounce, + }; + + /* +@@ -1035,11 +1040,12 @@ static void xlvbd_flush(struct blkfront_info *info) + { + blk_queue_write_cache(info->rq, info->feature_flush ? true : false, + info->feature_fua ? true : false); +- pr_info("blkfront: %s: %s %s %s %s %s\n", ++ pr_info("blkfront: %s: %s %s %s %s %s %s %s\n", + info->gd->disk_name, flush_info(info), + "persistent grants:", info->feature_persistent ? + "enabled;" : "disabled;", "indirect descriptors:", +- info->max_indirect_segments ? "enabled;" : "disabled;"); ++ info->max_indirect_segments ? "enabled;" : "disabled;", ++ "bounce buffer:", info->bounce ? "enabled" : "disabled;"); + } + + static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) +@@ -1273,7 +1279,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) + if (!list_empty(&rinfo->indirect_pages)) { + struct page *indirect_page, *n; + +- BUG_ON(info->feature_persistent); ++ BUG_ON(info->bounce); + list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) { + list_del(&indirect_page->lru); + __free_page(indirect_page); +@@ -1290,7 +1296,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) + 0, 0UL); + rinfo->persistent_gnts_c--; + } +- if (info->feature_persistent) ++ if (info->bounce) + __free_page(persistent_gnt->page); + kfree(persistent_gnt); + } +@@ -1311,7 +1317,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) + for (j = 0; j < segs; j++) { + persistent_gnt = rinfo->shadow[i].grants_used[j]; + gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); +- if (info->feature_persistent) ++ if (info->bounce) + __free_page(persistent_gnt->page); + kfree(persistent_gnt); + } +@@ -1501,7 +1507,7 @@ static int blkif_completion(unsigned long *id, + data.s = s; + num_sg = s->num_sg; + +- if (bret->operation == BLKIF_OP_READ && info->feature_persistent) { ++ if (bret->operation == BLKIF_OP_READ && info->bounce) { + for_each_sg(s->sg, sg, num_sg, i) { + BUG_ON(sg->offset + sg->length > PAGE_SIZE); + +@@ -1560,7 +1566,7 @@ static int blkif_completion(unsigned long *id, + * Add the used indirect page back to the list of + * available pages for indirect grefs. + */ +- if (!info->feature_persistent) { ++ if (!info->bounce) { + indirect_page = s->indirect_grants[i]->page; + list_add(&indirect_page->lru, &rinfo->indirect_pages); + } +@@ -1753,7 +1759,7 @@ static int setup_blkring(struct xenbus_device *dev, + for (i = 0; i < info->nr_ring_pages; i++) + rinfo->ring_ref[i] = GRANT_INVALID_REF; + +- sring = alloc_pages_exact(ring_size, GFP_NOIO); ++ sring = alloc_pages_exact(ring_size, GFP_NOIO | __GFP_ZERO); + if (!sring) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); + return -ENOMEM; +@@ -1857,6 +1863,10 @@ static int talk_to_blkback(struct xenbus_device *dev, + if (!info) + return -ENODEV; + ++ /* Check if backend is trusted. */ ++ info->bounce = !xen_blkif_trusted || ++ !xenbus_read_unsigned(dev->nodename, "trusted", 1); ++ + max_page_order = xenbus_read_unsigned(info->xbdev->otherend, + "max-ring-page-order", 0); + ring_page_order = min(xen_blkif_max_ring_order, max_page_order); +@@ -2283,17 +2293,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo) + if (err) + goto out_of_memory; + +- if (!info->feature_persistent && info->max_indirect_segments) { ++ if (!info->bounce && info->max_indirect_segments) { + /* +- * We are using indirect descriptors but not persistent +- * grants, we need to allocate a set of pages that can be ++ * We are using indirect descriptors but don't have a bounce ++ * buffer, we need to allocate a set of pages that can be + * used for mapping indirect grefs + */ + int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info); + + BUG_ON(!list_empty(&rinfo->indirect_pages)); + for (i = 0; i < num; i++) { +- struct page *indirect_page = alloc_page(GFP_KERNEL); ++ struct page *indirect_page = alloc_page(GFP_KERNEL | ++ __GFP_ZERO); + if (!indirect_page) + goto out_of_memory; + list_add(&indirect_page->lru, &rinfo->indirect_pages); +@@ -2386,6 +2397,8 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) + info->feature_persistent = + !!xenbus_read_unsigned(info->xbdev->otherend, + "feature-persistent", 0); ++ if (info->feature_persistent) ++ info->bounce = true; + + indirect_segments = xenbus_read_unsigned(info->xbdev->otherend, + "feature-max-indirect-segments", 0); +@@ -2759,6 +2772,13 @@ static void blkfront_delay_work(struct work_struct *work) + struct blkfront_info *info; + bool need_schedule_work = false; + ++ /* ++ * Note that when using bounce buffers but not persistent grants ++ * there's no need to run blkfront_delay_work because grants are ++ * revoked in blkif_completion or else an error is reported and the ++ * connection is closed. ++ */ ++ + mutex_lock(&blkfront_mutex); + + list_for_each_entry(info, &info_list, info_list) { +diff --git a/drivers/clocksource/timer-ixp4xx.c b/drivers/clocksource/timer-ixp4xx.c +index 9396745e1c179..ad904bbbac6fd 100644 +--- a/drivers/clocksource/timer-ixp4xx.c ++++ b/drivers/clocksource/timer-ixp4xx.c +@@ -258,7 +258,6 @@ void __init ixp4xx_timer_setup(resource_size_t timerbase, + } + ixp4xx_timer_register(base, timer_irq, timer_freq); + } +-EXPORT_SYMBOL_GPL(ixp4xx_timer_setup); + + #ifdef CONFIG_OF + static __init int ixp4xx_of_timer_init(struct device_node *np) +diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c +index 6b6b20da2bcfc..573b417e14833 100644 +--- a/drivers/cpufreq/qoriq-cpufreq.c ++++ b/drivers/cpufreq/qoriq-cpufreq.c +@@ -275,6 +275,7 @@ static int qoriq_cpufreq_probe(struct platform_device *pdev) + + np = of_find_matching_node(NULL, qoriq_cpufreq_blacklist); + if (np) { ++ of_node_put(np); + dev_info(&pdev->dev, "Disabling due to erratum A-008083"); + return -ENODEV; + } +diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c +index 17ed980d90998..d6da9c3e31067 100644 +--- a/drivers/devfreq/event/exynos-ppmu.c ++++ b/drivers/devfreq/event/exynos-ppmu.c +@@ -514,15 +514,19 @@ static int of_get_devfreq_events(struct device_node *np, + + count = of_get_child_count(events_np); + desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL); +- if (!desc) ++ if (!desc) { ++ of_node_put(events_np); + return -ENOMEM; ++ } + info->num_events = count; + + of_id = of_match_device(exynos_ppmu_id_match, dev); + if (of_id) + info->ppmu_type = (enum exynos_ppmu_type)of_id->data; +- else ++ else { ++ of_node_put(events_np); + return -EINVAL; ++ } + + j = 0; + for_each_child_of_node(events_np, node) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +index fb6230c62daad..d3a974d105529 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -689,7 +689,8 @@ int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid) + const uint32_t flush_type = 0; + bool all_hub = false; + +- if (adev->family == AMDGPU_FAMILY_AI) ++ if (adev->family == AMDGPU_FAMILY_AI || ++ adev->family == AMDGPU_FAMILY_RV) + all_hub = true; + + return amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, flush_type, all_hub); +diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c +index a4ec85207782d..2e6d6a5cffa16 100644 +--- a/drivers/hwmon/ibmaem.c ++++ b/drivers/hwmon/ibmaem.c +@@ -550,7 +550,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) + + res = platform_device_add(data->pdev); + if (res) +- goto ipmi_err; ++ goto dev_add_err; + + platform_set_drvdata(data->pdev, data); + +@@ -598,7 +598,9 @@ hwmon_reg_err: + ipmi_destroy_user(data->ipmi.user); + ipmi_err: + platform_set_drvdata(data->pdev, NULL); +- platform_device_unregister(data->pdev); ++ platform_device_del(data->pdev); ++dev_add_err: ++ platform_device_put(data->pdev); + dev_err: + ida_simple_remove(&aem_ida, data->id); + id_err: +@@ -690,7 +692,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, + + res = platform_device_add(data->pdev); + if (res) +- goto ipmi_err; ++ goto dev_add_err; + + platform_set_drvdata(data->pdev, data); + +@@ -738,7 +740,9 @@ hwmon_reg_err: + ipmi_destroy_user(data->ipmi.user); + ipmi_err: + platform_set_drvdata(data->pdev, NULL); +- platform_device_unregister(data->pdev); ++ platform_device_del(data->pdev); ++dev_add_err: ++ platform_device_put(data->pdev); + dev_err: + ida_simple_remove(&aem_ida, data->id); + id_err: +diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c +index ee568bdf3c788..3cc7a23fa69fe 100644 +--- a/drivers/infiniband/core/cm.c ++++ b/drivers/infiniband/core/cm.c +@@ -1280,8 +1280,10 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, + return ERR_CAST(cm_id_priv); + + err = cm_init_listen(cm_id_priv, service_id, 0); +- if (err) ++ if (err) { ++ ib_destroy_cm_id(&cm_id_priv->id); + return ERR_PTR(err); ++ } + + spin_lock_irq(&cm_id_priv->lock); + listen_id_priv = cm_insert_listen(cm_id_priv, cm_handler); +diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h +index 9dde70373a553..8ef6eecc42a0a 100644 +--- a/drivers/infiniband/hw/qedr/qedr.h ++++ b/drivers/infiniband/hw/qedr/qedr.h +@@ -418,6 +418,7 @@ struct qedr_qp { + u32 sq_psn; + u32 qkey; + u32 dest_qp_num; ++ u8 timeout; + + /* Relevant to qps created from kernel space only (ULPs) */ + u8 prev_wqe_size; +diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c +index eeb87f31cd252..f7b97b8e81a43 100644 +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -2622,6 +2622,8 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + 1 << max_t(int, attr->timeout - 8, 0); + else + qp_params.ack_timeout = 0; ++ ++ qp->timeout = attr->timeout; + } + + if (attr_mask & IB_QP_RETRY_CNT) { +@@ -2781,7 +2783,7 @@ int qedr_query_qp(struct ib_qp *ibqp, + rdma_ah_set_dgid_raw(&qp_attr->ah_attr, ¶ms.dgid.bytes[0]); + rdma_ah_set_port_num(&qp_attr->ah_attr, 1); + rdma_ah_set_sl(&qp_attr->ah_attr, 0); +- qp_attr->timeout = params.timeout; ++ qp_attr->timeout = qp->timeout; + qp_attr->rnr_retry = params.rnr_retry; + qp_attr->retry_cnt = params.retry_cnt; + qp_attr->min_rnr_timer = params.min_rnr_nak_timer; +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index f5083b4a01958..4e94200e01423 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -1002,12 +1002,13 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) + static int validate_raid_redundancy(struct raid_set *rs) + { + unsigned int i, rebuild_cnt = 0; +- unsigned int rebuilds_per_group = 0, copies; ++ unsigned int rebuilds_per_group = 0, copies, raid_disks; + unsigned int group_size, last_group_start; + +- for (i = 0; i < rs->md.raid_disks; i++) +- if (!test_bit(In_sync, &rs->dev[i].rdev.flags) || +- !rs->dev[i].rdev.sb_page) ++ for (i = 0; i < rs->raid_disks; i++) ++ if (!test_bit(FirstUse, &rs->dev[i].rdev.flags) && ++ ((!test_bit(In_sync, &rs->dev[i].rdev.flags) || ++ !rs->dev[i].rdev.sb_page))) + rebuild_cnt++; + + switch (rs->md.level) { +@@ -1047,8 +1048,9 @@ static int validate_raid_redundancy(struct raid_set *rs) + * A A B B C + * C D D E E + */ ++ raid_disks = min(rs->raid_disks, rs->md.raid_disks); + if (__is_raid10_near(rs->md.new_layout)) { +- for (i = 0; i < rs->md.raid_disks; i++) { ++ for (i = 0; i < raid_disks; i++) { + if (!(i % copies)) + rebuilds_per_group = 0; + if ((!rs->dev[i].rdev.sb_page || +@@ -1071,10 +1073,10 @@ static int validate_raid_redundancy(struct raid_set *rs) + * results in the need to treat the last (potentially larger) + * set differently. + */ +- group_size = (rs->md.raid_disks / copies); +- last_group_start = (rs->md.raid_disks / group_size) - 1; ++ group_size = (raid_disks / copies); ++ last_group_start = (raid_disks / group_size) - 1; + last_group_start *= group_size; +- for (i = 0; i < rs->md.raid_disks; i++) { ++ for (i = 0; i < raid_disks; i++) { + if (!(i % copies) && !(i > last_group_start)) + rebuilds_per_group = 0; + if ((!rs->dev[i].rdev.sb_page || +@@ -1589,7 +1591,7 @@ static sector_t __rdev_sectors(struct raid_set *rs) + { + int i; + +- for (i = 0; i < rs->md.raid_disks; i++) { ++ for (i = 0; i < rs->raid_disks; i++) { + struct md_rdev *rdev = &rs->dev[i].rdev; + + if (!test_bit(Journal, &rdev->flags) && +@@ -3732,13 +3734,13 @@ static int raid_iterate_devices(struct dm_target *ti, + unsigned int i; + int r = 0; + +- for (i = 0; !r && i < rs->md.raid_disks; i++) +- if (rs->dev[i].data_dev) +- r = fn(ti, +- rs->dev[i].data_dev, +- 0, /* No offset on data devs */ +- rs->md.dev_sectors, +- data); ++ for (i = 0; !r && i < rs->raid_disks; i++) { ++ if (rs->dev[i].data_dev) { ++ r = fn(ti, rs->dev[i].data_dev, ++ 0, /* No offset on data devs */ ++ rs->md.dev_sectors, data); ++ } ++ } + + return r; + } +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 02767866b9ff6..c8cafdb094aaa 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -8004,6 +8004,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) + */ + if (rdev->saved_raid_disk >= 0 && + rdev->saved_raid_disk >= first && ++ rdev->saved_raid_disk <= last && + conf->disks[rdev->saved_raid_disk].rdev == NULL) + first = rdev->saved_raid_disk; + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index c2cef7ba26719..325b20729d8ba 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -2209,7 +2209,8 @@ void bond_3ad_unbind_slave(struct slave *slave) + temp_aggregator->num_of_ports--; + if (__agg_active_ports(temp_aggregator) == 0) { + select_new_active_agg = temp_aggregator->is_active; +- ad_clear_agg(temp_aggregator); ++ if (temp_aggregator->num_of_ports == 0) ++ ad_clear_agg(temp_aggregator); + if (select_new_active_agg) { + slave_info(bond->dev, slave->dev, "Removing an active aggregator\n"); + /* select new active aggregator */ +diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c +index 0436aef9c9ef5..152f76f869278 100644 +--- a/drivers/net/bonding/bond_alb.c ++++ b/drivers/net/bonding/bond_alb.c +@@ -1279,12 +1279,12 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled) + return res; + + if (rlb_enabled) { +- bond->alb_info.rlb_enabled = 1; + res = rlb_initialize(bond); + if (res) { + tlb_deinitialize(bond); + return res; + } ++ bond->alb_info.rlb_enabled = 1; + } else { + bond->alb_info.rlb_enabled = 0; + } +diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c +index 47a6d62b75111..a701932f5cc29 100644 +--- a/drivers/net/caif/caif_virtio.c ++++ b/drivers/net/caif/caif_virtio.c +@@ -723,13 +723,21 @@ static int cfv_probe(struct virtio_device *vdev) + /* Carrier is off until netdevice is opened */ + netif_carrier_off(netdev); + ++ /* serialize netdev register + virtio_device_ready() with ndo_open() */ ++ rtnl_lock(); ++ + /* register Netdev */ +- err = register_netdev(netdev); ++ err = register_netdevice(netdev); + if (err) { ++ rtnl_unlock(); + dev_err(&vdev->dev, "Unable to register netdev (%d)\n", err); + goto err; + } + ++ virtio_device_ready(vdev); ++ ++ rtnl_unlock(); ++ + debugfs_init(cfv); + + return 0; +diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c +index b712b4f27efd9..c6563d212476a 100644 +--- a/drivers/net/dsa/bcm_sf2.c ++++ b/drivers/net/dsa/bcm_sf2.c +@@ -774,6 +774,11 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, + if (duplex == DUPLEX_FULL) + reg |= DUPLX_MODE; + ++ if (tx_pause) ++ reg |= TXFLOW_CNTL; ++ if (rx_pause) ++ reg |= RXFLOW_CNTL; ++ + core_writel(priv, reg, offset); + } + +diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c +index 51cd7dca91cda..3a7d2baec6c16 100644 +--- a/drivers/net/ethernet/smsc/epic100.c ++++ b/drivers/net/ethernet/smsc/epic100.c +@@ -1513,14 +1513,14 @@ static void epic_remove_one(struct pci_dev *pdev) + struct net_device *dev = pci_get_drvdata(pdev); + struct epic_private *ep = netdev_priv(dev); + ++ unregister_netdev(dev); + dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, ep->tx_ring, + ep->tx_ring_dma); + dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, ep->rx_ring, + ep->rx_ring_dma); +- unregister_netdev(dev); + pci_iounmap(pdev, ep->ioaddr); +- pci_release_regions(pdev); + free_netdev(dev); ++ pci_release_regions(pdev); + pci_disable_device(pdev); + /* pci_power_off(pdev, -1); */ + } +diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c +index 3d75b98f3051d..3a8849716459a 100644 +--- a/drivers/net/phy/dp83822.c ++++ b/drivers/net/phy/dp83822.c +@@ -243,9 +243,7 @@ static int dp83822_config_intr(struct phy_device *phydev) + if (misr_status < 0) + return misr_status; + +- misr_status |= (DP83822_RX_ERR_HF_INT_EN | +- DP83822_FALSE_CARRIER_HF_INT_EN | +- DP83822_LINK_STAT_INT_EN | ++ misr_status |= (DP83822_LINK_STAT_INT_EN | + DP83822_ENERGY_DET_INT_EN | + DP83822_LINK_QUAL_INT_EN); + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 55ce141c93c75..be9ff6a74ecce 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -279,6 +279,12 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile, + } + } + ++static void tun_napi_enable(struct tun_file *tfile) ++{ ++ if (tfile->napi_enabled) ++ napi_enable(&tfile->napi); ++} ++ + static void tun_napi_disable(struct tun_file *tfile) + { + if (tfile->napi_enabled) +@@ -640,7 +646,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) + tun = rtnl_dereference(tfile->tun); + + if (tun && clean) { +- tun_napi_disable(tfile); ++ if (!tfile->detached) ++ tun_napi_disable(tfile); + tun_napi_del(tfile); + } + +@@ -659,8 +666,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean) + if (clean) { + RCU_INIT_POINTER(tfile->tun, NULL); + sock_put(&tfile->sk); +- } else ++ } else { + tun_disable_queue(tun, tfile); ++ tun_napi_disable(tfile); ++ } + + synchronize_net(); + tun_flow_delete_by_queue(tun, tun->numqueues + 1); +@@ -733,6 +742,7 @@ static void tun_detach_all(struct net_device *dev) + sock_put(&tfile->sk); + } + list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { ++ tun_napi_del(tfile); + tun_enable_queue(tfile); + tun_queue_purge(tfile); + xdp_rxq_info_unreg(&tfile->xdp_rxq); +@@ -813,6 +823,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file, + + if (tfile->detached) { + tun_enable_queue(tfile); ++ tun_napi_enable(tfile); + } else { + sock_hold(&tfile->sk); + tun_napi_init(tun, tfile, napi, napi_frags); +diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c +index 0b0cbcee1920b..79a53fe245e5c 100644 +--- a/drivers/net/usb/ax88179_178a.c ++++ b/drivers/net/usb/ax88179_178a.c +@@ -1471,6 +1471,42 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + * are bundled into this buffer and where we can find an array of + * per-packet metadata (which contains elements encoded into u16). + */ ++ ++ /* SKB contents for current firmware: ++ * <packet 1> <padding> ++ * ... ++ * <packet N> <padding> ++ * <per-packet metadata entry 1> <dummy header> ++ * ... ++ * <per-packet metadata entry N> <dummy header> ++ * <padding2> <rx_hdr> ++ * ++ * where: ++ * <packet N> contains pkt_len bytes: ++ * 2 bytes of IP alignment pseudo header ++ * packet received ++ * <per-packet metadata entry N> contains 4 bytes: ++ * pkt_len and fields AX_RXHDR_* ++ * <padding> 0-7 bytes to terminate at ++ * 8 bytes boundary (64-bit). ++ * <padding2> 4 bytes to make rx_hdr terminate at ++ * 8 bytes boundary (64-bit) ++ * <dummy-header> contains 4 bytes: ++ * pkt_len=0 and AX_RXHDR_DROP_ERR ++ * <rx-hdr> contains 4 bytes: ++ * pkt_cnt and hdr_off (offset of ++ * <per-packet metadata entry 1>) ++ * ++ * pkt_cnt is number of entrys in the per-packet metadata. ++ * In current firmware there is 2 entrys per packet. ++ * The first points to the packet and the ++ * second is a dummy header. ++ * This was done probably to align fields in 64-bit and ++ * maintain compatibility with old firmware. ++ * This code assumes that <dummy header> and <padding2> are ++ * optional. ++ */ ++ + if (skb->len < 4) + return 0; + skb_trim(skb, skb->len - 4); +@@ -1484,51 +1520,66 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + /* Make sure that the bounds of the metadata array are inside the SKB + * (and in front of the counter at the end). + */ +- if (pkt_cnt * 2 + hdr_off > skb->len) ++ if (pkt_cnt * 4 + hdr_off > skb->len) + return 0; + pkt_hdr = (u32 *)(skb->data + hdr_off); + + /* Packets must not overlap the metadata array */ + skb_trim(skb, hdr_off); + +- for (; ; pkt_cnt--, pkt_hdr++) { ++ for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) { ++ u16 pkt_len_plus_padd; + u16 pkt_len; + + le32_to_cpus(pkt_hdr); + pkt_len = (*pkt_hdr >> 16) & 0x1fff; ++ pkt_len_plus_padd = (pkt_len + 7) & 0xfff8; + +- if (pkt_len > skb->len) ++ /* Skip dummy header used for alignment ++ */ ++ if (pkt_len == 0) ++ continue; ++ ++ if (pkt_len_plus_padd > skb->len) + return 0; + + /* Check CRC or runt packet */ +- if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) && +- pkt_len >= 2 + ETH_HLEN) { +- bool last = (pkt_cnt == 0); +- +- if (last) { +- ax_skb = skb; +- } else { +- ax_skb = skb_clone(skb, GFP_ATOMIC); +- if (!ax_skb) +- return 0; +- } +- ax_skb->len = pkt_len; +- /* Skip IP alignment pseudo header */ +- skb_pull(ax_skb, 2); +- skb_set_tail_pointer(ax_skb, ax_skb->len); +- ax_skb->truesize = pkt_len + sizeof(struct sk_buff); +- ax88179_rx_checksum(ax_skb, pkt_hdr); ++ if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) || ++ pkt_len < 2 + ETH_HLEN) { ++ dev->net->stats.rx_errors++; ++ skb_pull(skb, pkt_len_plus_padd); ++ continue; ++ } + +- if (last) +- return 1; ++ /* last packet */ ++ if (pkt_len_plus_padd == skb->len) { ++ skb_trim(skb, pkt_len); + +- usbnet_skb_return(dev, ax_skb); ++ /* Skip IP alignment pseudo header */ ++ skb_pull(skb, 2); ++ ++ skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd); ++ ax88179_rx_checksum(skb, pkt_hdr); ++ return 1; + } + +- /* Trim this packet away from the SKB */ +- if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8)) ++ ax_skb = skb_clone(skb, GFP_ATOMIC); ++ if (!ax_skb) + return 0; ++ skb_trim(ax_skb, pkt_len); ++ ++ /* Skip IP alignment pseudo header */ ++ skb_pull(ax_skb, 2); ++ ++ skb->truesize = pkt_len_plus_padd + ++ SKB_DATA_ALIGN(sizeof(struct sk_buff)); ++ ax88179_rx_checksum(ax_skb, pkt_hdr); ++ usbnet_skb_return(dev, ax_skb); ++ ++ skb_pull(skb, pkt_len_plus_padd); + } ++ ++ return 0; + } + + static struct sk_buff * +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 597766d14563e..48e8b94e4a7c5 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1293,6 +1293,8 @@ static const struct usb_device_id products[] = { + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1060, 2)}, /* Telit LN920 */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1070, 2)}, /* Telit FN990 */ + {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */ + {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */ + {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index 402390b1a66b5..74a833ad7aa99 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -1969,7 +1969,7 @@ static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, + cmd, reqtype, value, index, size); + + if (size) { +- buf = kmalloc(size, GFP_KERNEL); ++ buf = kmalloc(size, GFP_NOIO); + if (!buf) + goto out; + } +@@ -2001,7 +2001,7 @@ static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, + cmd, reqtype, value, index, size); + + if (data) { +- buf = kmemdup(data, size, GFP_KERNEL); ++ buf = kmemdup(data, size, GFP_NOIO); + if (!buf) + goto out; + } else { +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index ad9064df3debb..37178b078ee37 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -3171,14 +3171,20 @@ static int virtnet_probe(struct virtio_device *vdev) + } + } + +- err = register_netdev(dev); ++ /* serialize netdev register + virtio_device_ready() with ndo_open() */ ++ rtnl_lock(); ++ ++ err = register_netdevice(dev); + if (err) { + pr_debug("virtio_net: registering device failed\n"); ++ rtnl_unlock(); + goto free_failover; + } + + virtio_device_ready(vdev); + ++ rtnl_unlock(); ++ + err = virtnet_cpu_notif_add(vi); + if (err) { + pr_debug("virtio_net: registering cpu notifier failed\n"); +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index 1a69b5246133b..569f3c8e7b756 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -66,6 +66,10 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644); + MODULE_PARM_DESC(max_queues, + "Maximum number of queues per virtual interface"); + ++static bool __read_mostly xennet_trusted = true; ++module_param_named(trusted, xennet_trusted, bool, 0644); ++MODULE_PARM_DESC(trusted, "Is the backend trusted"); ++ + #define XENNET_TIMEOUT (5 * HZ) + + static const struct ethtool_ops xennet_ethtool_ops; +@@ -175,6 +179,9 @@ struct netfront_info { + /* Is device behaving sane? */ + bool broken; + ++ /* Should skbs be bounced into a zeroed buffer? */ ++ bool bounce; ++ + atomic_t rx_gso_checksum_fixup; + }; + +@@ -273,7 +280,8 @@ static struct sk_buff *xennet_alloc_one_rx_buffer(struct netfront_queue *queue) + if (unlikely(!skb)) + return NULL; + +- page = page_pool_dev_alloc_pages(queue->page_pool); ++ page = page_pool_alloc_pages(queue->page_pool, ++ GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO); + if (unlikely(!page)) { + kfree_skb(skb); + return NULL; +@@ -669,6 +677,33 @@ static int xennet_xdp_xmit(struct net_device *dev, int n, + return n - drops; + } + ++struct sk_buff *bounce_skb(const struct sk_buff *skb) ++{ ++ unsigned int headerlen = skb_headroom(skb); ++ /* Align size to allocate full pages and avoid contiguous data leaks */ ++ unsigned int size = ALIGN(skb_end_offset(skb) + skb->data_len, ++ XEN_PAGE_SIZE); ++ struct sk_buff *n = alloc_skb(size, GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!n) ++ return NULL; ++ ++ if (!IS_ALIGNED((uintptr_t)n->head, XEN_PAGE_SIZE)) { ++ WARN_ONCE(1, "misaligned skb allocated\n"); ++ kfree_skb(n); ++ return NULL; ++ } ++ ++ /* Set the data pointer */ ++ skb_reserve(n, headerlen); ++ /* Set the tail pointer and length */ ++ skb_put(n, skb->len); ++ ++ BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len)); ++ ++ skb_copy_header(n, skb); ++ return n; ++} + + #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1) + +@@ -722,9 +757,13 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev + + /* The first req should be at least ETH_HLEN size or the packet will be + * dropped by netback. ++ * ++ * If the backend is not trusted bounce all data to zeroed pages to ++ * avoid exposing contiguous data on the granted page not belonging to ++ * the skb. + */ +- if (unlikely(PAGE_SIZE - offset < ETH_HLEN)) { +- nskb = skb_copy(skb, GFP_ATOMIC); ++ if (np->bounce || unlikely(PAGE_SIZE - offset < ETH_HLEN)) { ++ nskb = bounce_skb(skb); + if (!nskb) + goto drop; + dev_consume_skb_any(skb); +@@ -1057,8 +1096,10 @@ static int xennet_get_responses(struct netfront_queue *queue, + } + } + rcu_read_unlock(); +-next: ++ + __skb_queue_tail(list, skb); ++ ++next: + if (!(rx->flags & XEN_NETRXF_more_data)) + break; + +@@ -2248,6 +2289,10 @@ static int talk_to_netback(struct xenbus_device *dev, + + info->netdev->irq = 0; + ++ /* Check if backend is trusted. */ ++ info->bounce = !xennet_trusted || ++ !xenbus_read_unsigned(dev->nodename, "trusted", 1); ++ + /* Check if backend supports multiple queues */ + max_queues = xenbus_read_unsigned(info->xbdev->otherend, + "multi-queue-max-queues", 1); +@@ -2414,6 +2459,9 @@ static int xennet_connect(struct net_device *dev) + return err; + if (np->netback_has_xdp_headroom) + pr_info("backend supports XDP headroom\n"); ++ if (np->bounce) ++ dev_info(&np->xbdev->dev, ++ "bouncing transmitted data to zeroed pages\n"); + + /* talk_to_netback() sets the correct number of queues */ + num_queues = dev->real_num_tx_queues; +diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c +index 18cd96284b77a..f81f1cae93243 100644 +--- a/drivers/nfc/nfcmrvl/i2c.c ++++ b/drivers/nfc/nfcmrvl/i2c.c +@@ -186,9 +186,9 @@ static int nfcmrvl_i2c_parse_dt(struct device_node *node, + pdata->irq_polarity = IRQF_TRIGGER_RISING; + + ret = irq_of_parse_and_map(node, 0); +- if (ret < 0) { +- pr_err("Unable to get irq, error: %d\n", ret); +- return ret; ++ if (!ret) { ++ pr_err("Unable to get irq\n"); ++ return -EINVAL; + } + pdata->irq = ret; + +diff --git a/drivers/nfc/nfcmrvl/spi.c b/drivers/nfc/nfcmrvl/spi.c +index 8e0ddb4347704..1f4120e3314b2 100644 +--- a/drivers/nfc/nfcmrvl/spi.c ++++ b/drivers/nfc/nfcmrvl/spi.c +@@ -129,9 +129,9 @@ static int nfcmrvl_spi_parse_dt(struct device_node *node, + } + + ret = irq_of_parse_and_map(node, 0); +- if (ret < 0) { +- pr_err("Unable to get irq, error: %d\n", ret); +- return ret; ++ if (!ret) { ++ pr_err("Unable to get irq\n"); ++ return -EINVAL; + } + pdata->irq = ret; + +diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c +index 9f60e4dc5a908..3943a30053b3b 100644 +--- a/drivers/nfc/nxp-nci/i2c.c ++++ b/drivers/nfc/nxp-nci/i2c.c +@@ -162,6 +162,9 @@ static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, + + skb_put_data(*skb, (void *)&header, NCI_CTRL_HDR_SIZE); + ++ if (!header.plen) ++ return 0; ++ + r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); + if (r != header.plen) { + nfc_err(&client->dev, +diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c +index 2304c6183822e..9ec59960f2163 100644 +--- a/drivers/nvdimm/bus.c ++++ b/drivers/nvdimm/bus.c +@@ -187,8 +187,8 @@ static int nvdimm_clear_badblocks_region(struct device *dev, void *data) + ndr_end = nd_region->ndr_start + nd_region->ndr_size - 1; + + /* make sure we are in the region */ +- if (ctx->phys < nd_region->ndr_start +- || (ctx->phys + ctx->cleared) > ndr_end) ++ if (ctx->phys < nd_region->ndr_start || ++ (ctx->phys + ctx->cleared - 1) > ndr_end) + return 0; + + sector = (ctx->phys - nd_region->ndr_start) / 512; +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 9e633f4dcec71..3622c5c9515fa 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3245,7 +3245,8 @@ static const struct pci_device_id nvme_id_table[] = { + { PCI_DEVICE(0x1d1d, 0x2601), /* CNEX Granby */ + .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x10ec, 0x5762), /* ADATA SX6000LNP */ +- .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN | ++ NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1cc1, 0x8201), /* ADATA SX8200PNP 512GB */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, +diff --git a/drivers/xen/gntdev-common.h b/drivers/xen/gntdev-common.h +index 20d7d059dadb5..40ef379c28ab0 100644 +--- a/drivers/xen/gntdev-common.h ++++ b/drivers/xen/gntdev-common.h +@@ -16,6 +16,7 @@ + #include <linux/mmu_notifier.h> + #include <linux/types.h> + #include <xen/interface/event_channel.h> ++#include <xen/grant_table.h> + + struct gntdev_dmabuf_priv; + +@@ -56,6 +57,7 @@ struct gntdev_grant_map { + struct gnttab_unmap_grant_ref *unmap_ops; + struct gnttab_map_grant_ref *kmap_ops; + struct gnttab_unmap_grant_ref *kunmap_ops; ++ bool *being_removed; + struct page **pages; + unsigned long pages_vm_start; + +@@ -73,6 +75,11 @@ struct gntdev_grant_map { + /* Needed to avoid allocation in gnttab_dma_free_pages(). */ + xen_pfn_t *frames; + #endif ++ ++ /* Number of live grants */ ++ atomic_t live_grants; ++ /* Needed to avoid allocation in __unmap_grant_pages */ ++ struct gntab_unmap_queue_data unmap_data; + }; + + struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count, +diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c +index 54778aadf618d..f415c056ff8ab 100644 +--- a/drivers/xen/gntdev.c ++++ b/drivers/xen/gntdev.c +@@ -35,6 +35,7 @@ + #include <linux/slab.h> + #include <linux/highmem.h> + #include <linux/refcount.h> ++#include <linux/workqueue.h> + + #include <xen/xen.h> + #include <xen/grant_table.h> +@@ -60,10 +61,11 @@ module_param(limit, uint, 0644); + MODULE_PARM_DESC(limit, + "Maximum number of grants that may be mapped by one mapping request"); + ++/* True in PV mode, false otherwise */ + static int use_ptemod; + +-static int unmap_grant_pages(struct gntdev_grant_map *map, +- int offset, int pages); ++static void unmap_grant_pages(struct gntdev_grant_map *map, ++ int offset, int pages); + + static struct miscdevice gntdev_miscdev; + +@@ -120,6 +122,7 @@ static void gntdev_free_map(struct gntdev_grant_map *map) + kvfree(map->unmap_ops); + kvfree(map->kmap_ops); + kvfree(map->kunmap_ops); ++ kvfree(map->being_removed); + kfree(map); + } + +@@ -140,12 +143,15 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count, + add->kunmap_ops = kvcalloc(count, + sizeof(add->kunmap_ops[0]), GFP_KERNEL); + add->pages = kvcalloc(count, sizeof(add->pages[0]), GFP_KERNEL); ++ add->being_removed = ++ kvcalloc(count, sizeof(add->being_removed[0]), GFP_KERNEL); + if (NULL == add->grants || + NULL == add->map_ops || + NULL == add->unmap_ops || + NULL == add->kmap_ops || + NULL == add->kunmap_ops || +- NULL == add->pages) ++ NULL == add->pages || ++ NULL == add->being_removed) + goto err; + + #ifdef CONFIG_XEN_GRANT_DMA_ALLOC +@@ -240,9 +246,36 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map) + if (!refcount_dec_and_test(&map->users)) + return; + +- if (map->pages && !use_ptemod) ++ if (map->pages && !use_ptemod) { ++ /* ++ * Increment the reference count. This ensures that the ++ * subsequent call to unmap_grant_pages() will not wind up ++ * re-entering itself. It *can* wind up calling ++ * gntdev_put_map() recursively, but such calls will be with a ++ * reference count greater than 1, so they will return before ++ * this code is reached. The recursion depth is thus limited to ++ * 1. Do NOT use refcount_inc() here, as it will detect that ++ * the reference count is zero and WARN(). ++ */ ++ refcount_set(&map->users, 1); ++ ++ /* ++ * Unmap the grants. This may or may not be asynchronous, so it ++ * is possible that the reference count is 1 on return, but it ++ * could also be greater than 1. ++ */ + unmap_grant_pages(map, 0, map->count); + ++ /* Check if the memory now needs to be freed */ ++ if (!refcount_dec_and_test(&map->users)) ++ return; ++ ++ /* ++ * All pages have been returned to the hypervisor, so free the ++ * map. ++ */ ++ } ++ + if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { + notify_remote_via_evtchn(map->notify.event); + evtchn_put(map->notify.event); +@@ -288,6 +321,7 @@ static int set_grant_ptes_as_special(pte_t *pte, unsigned long addr, void *data) + + int gntdev_map_grant_pages(struct gntdev_grant_map *map) + { ++ size_t alloced = 0; + int i, err = 0; + + if (!use_ptemod) { +@@ -336,87 +370,109 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map) + map->pages, map->count); + + for (i = 0; i < map->count; i++) { +- if (map->map_ops[i].status == GNTST_okay) ++ if (map->map_ops[i].status == GNTST_okay) { + map->unmap_ops[i].handle = map->map_ops[i].handle; +- else if (!err) ++ if (!use_ptemod) ++ alloced++; ++ } else if (!err) + err = -EINVAL; + + if (map->flags & GNTMAP_device_map) + map->unmap_ops[i].dev_bus_addr = map->map_ops[i].dev_bus_addr; + + if (use_ptemod) { +- if (map->kmap_ops[i].status == GNTST_okay) ++ if (map->kmap_ops[i].status == GNTST_okay) { ++ if (map->map_ops[i].status == GNTST_okay) ++ alloced++; + map->kunmap_ops[i].handle = map->kmap_ops[i].handle; +- else if (!err) ++ } else if (!err) + err = -EINVAL; + } + } ++ atomic_add(alloced, &map->live_grants); + return err; + } + +-static int __unmap_grant_pages(struct gntdev_grant_map *map, int offset, +- int pages) ++static void __unmap_grant_pages_done(int result, ++ struct gntab_unmap_queue_data *data) + { +- int i, err = 0; +- struct gntab_unmap_queue_data unmap_data; ++ unsigned int i; ++ struct gntdev_grant_map *map = data->data; ++ unsigned int offset = data->unmap_ops - map->unmap_ops; + ++ for (i = 0; i < data->count; i++) { ++ WARN_ON(map->unmap_ops[offset+i].status); ++ pr_debug("unmap handle=%d st=%d\n", ++ map->unmap_ops[offset+i].handle, ++ map->unmap_ops[offset+i].status); ++ map->unmap_ops[offset+i].handle = -1; ++ } ++ /* ++ * Decrease the live-grant counter. This must happen after the loop to ++ * prevent premature reuse of the grants by gnttab_mmap(). ++ */ ++ atomic_sub(data->count, &map->live_grants); ++ ++ /* Release reference taken by __unmap_grant_pages */ ++ gntdev_put_map(NULL, map); ++} ++ ++static void __unmap_grant_pages(struct gntdev_grant_map *map, int offset, ++ int pages) ++{ + if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { + int pgno = (map->notify.addr >> PAGE_SHIFT); ++ + if (pgno >= offset && pgno < offset + pages) { + /* No need for kmap, pages are in lowmem */ + uint8_t *tmp = pfn_to_kaddr(page_to_pfn(map->pages[pgno])); ++ + tmp[map->notify.addr & (PAGE_SIZE-1)] = 0; + map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; + } + } + +- unmap_data.unmap_ops = map->unmap_ops + offset; +- unmap_data.kunmap_ops = use_ptemod ? map->kunmap_ops + offset : NULL; +- unmap_data.pages = map->pages + offset; +- unmap_data.count = pages; ++ map->unmap_data.unmap_ops = map->unmap_ops + offset; ++ map->unmap_data.kunmap_ops = use_ptemod ? map->kunmap_ops + offset : NULL; ++ map->unmap_data.pages = map->pages + offset; ++ map->unmap_data.count = pages; ++ map->unmap_data.done = __unmap_grant_pages_done; ++ map->unmap_data.data = map; ++ refcount_inc(&map->users); /* to keep map alive during async call below */ + +- err = gnttab_unmap_refs_sync(&unmap_data); +- if (err) +- return err; +- +- for (i = 0; i < pages; i++) { +- if (map->unmap_ops[offset+i].status) +- err = -EINVAL; +- pr_debug("unmap handle=%d st=%d\n", +- map->unmap_ops[offset+i].handle, +- map->unmap_ops[offset+i].status); +- map->unmap_ops[offset+i].handle = -1; +- } +- return err; ++ gnttab_unmap_refs_async(&map->unmap_data); + } + +-static int unmap_grant_pages(struct gntdev_grant_map *map, int offset, +- int pages) ++static void unmap_grant_pages(struct gntdev_grant_map *map, int offset, ++ int pages) + { +- int range, err = 0; ++ int range; ++ ++ if (atomic_read(&map->live_grants) == 0) ++ return; /* Nothing to do */ + + pr_debug("unmap %d+%d [%d+%d]\n", map->index, map->count, offset, pages); + + /* It is possible the requested range will have a "hole" where we + * already unmapped some of the grants. Only unmap valid ranges. + */ +- while (pages && !err) { +- while (pages && map->unmap_ops[offset].handle == -1) { ++ while (pages) { ++ while (pages && map->being_removed[offset]) { + offset++; + pages--; + } + range = 0; + while (range < pages) { +- if (map->unmap_ops[offset+range].handle == -1) ++ if (map->being_removed[offset + range]) + break; ++ map->being_removed[offset + range] = true; + range++; + } +- err = __unmap_grant_pages(map, offset, range); ++ if (range) ++ __unmap_grant_pages(map, offset, range); + offset += range; + pages -= range; + } +- +- return err; + } + + /* ------------------------------------------------------------------ */ +@@ -468,7 +524,6 @@ static bool gntdev_invalidate(struct mmu_interval_notifier *mn, + struct gntdev_grant_map *map = + container_of(mn, struct gntdev_grant_map, notifier); + unsigned long mstart, mend; +- int err; + + if (!mmu_notifier_range_blockable(range)) + return false; +@@ -489,10 +544,9 @@ static bool gntdev_invalidate(struct mmu_interval_notifier *mn, + map->index, map->count, + map->vma->vm_start, map->vma->vm_end, + range->start, range->end, mstart, mend); +- err = unmap_grant_pages(map, ++ unmap_grant_pages(map, + (mstart - map->vma->vm_start) >> PAGE_SHIFT, + (mend - mstart) >> PAGE_SHIFT); +- WARN_ON(err); + + return true; + } +@@ -980,6 +1034,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) + goto unlock_out; + if (use_ptemod && map->vma) + goto unlock_out; ++ if (atomic_read(&map->live_grants)) { ++ err = -EAGAIN; ++ goto unlock_out; ++ } + refcount_inc(&map->users); + + vma->vm_ops = &gntdev_vmops; +diff --git a/fs/io_uring.c b/fs/io_uring.c +index 2e12dcbc7b0fd..023c3eb34dcca 100644 +--- a/fs/io_uring.c ++++ b/fs/io_uring.c +@@ -4366,6 +4366,8 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + + if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL)) + return -EINVAL; ++ if (unlikely(sqe->addr2 || sqe->splice_fd_in || sqe->ioprio)) ++ return -EINVAL; + + sr->msg_flags = READ_ONCE(sqe->msg_flags); + sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr)); +@@ -4601,6 +4603,8 @@ static int io_recvmsg_prep(struct io_kiocb *req, + + if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL)) + return -EINVAL; ++ if (unlikely(sqe->addr2 || sqe->splice_fd_in || sqe->ioprio)) ++ return -EINVAL; + + sr->msg_flags = READ_ONCE(sqe->msg_flags); + sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr)); +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index dd33b31b0a826..86297f59b43e2 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -1460,13 +1460,6 @@ iomap_do_writepage(struct page *page, struct writeback_control *wbc, void *data) + PF_MEMALLOC)) + goto redirty; + +- /* +- * Given that we do not allow direct reclaim to call us, we should +- * never be called in a recursive filesystem reclaim context. +- */ +- if (WARN_ON_ONCE(current->flags & PF_MEMALLOC_NOFS)) +- goto redirty; +- + /* + * Is this page beyond the end of the file? + * +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 548ebc913f920..c852bb5ff2121 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1156,6 +1156,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + nfsd_net_id)); + err2 = filemap_check_wb_err(nf->nf_file->f_mapping, + since); ++ err = nfserrno(err2); + break; + case -EINVAL: + err = nfserr_notsupp; +@@ -1163,8 +1164,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + default: + nfsd_reset_boot_verifier(net_generic(nf->nf_net, + nfsd_net_id)); ++ err = nfserrno(err2); + } +- err = nfserrno(err2); + } else + nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, + nfsd_net_id)); +diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c +index 98c82f4935e1e..24c7d30e41dfe 100644 +--- a/fs/xfs/libxfs/xfs_btree.c ++++ b/fs/xfs/libxfs/xfs_btree.c +@@ -2811,7 +2811,7 @@ xfs_btree_split_worker( + struct xfs_btree_split_args *args = container_of(work, + struct xfs_btree_split_args, work); + unsigned long pflags; +- unsigned long new_pflags = PF_MEMALLOC_NOFS; ++ unsigned long new_pflags = 0; + + /* + * we are in a transaction context here, but may also be doing work +@@ -2823,12 +2823,20 @@ xfs_btree_split_worker( + new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; + + current_set_flags_nested(&pflags, new_pflags); ++ xfs_trans_set_context(args->cur->bc_tp); + + args->result = __xfs_btree_split(args->cur, args->level, args->ptrp, + args->key, args->curp, args->stat); +- complete(args->done); + ++ xfs_trans_clear_context(args->cur->bc_tp); + current_restore_flags_nested(&pflags, new_pflags); ++ ++ /* ++ * Do not access args after complete() has run here. We don't own args ++ * and the owner may run and free args before we return here. ++ */ ++ complete(args->done); ++ + } + + /* +diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c +index 5aeafa59ed276..66e8353da2f3c 100644 +--- a/fs/xfs/libxfs/xfs_sb.c ++++ b/fs/xfs/libxfs/xfs_sb.c +@@ -956,9 +956,19 @@ xfs_log_sb( + struct xfs_mount *mp = tp->t_mountp; + struct xfs_buf *bp = xfs_trans_getsb(tp); + +- mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); +- mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree); +- mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); ++ /* ++ * Lazy sb counters don't update the in-core superblock so do that now. ++ * If this is at unmount, the counters will be exactly correct, but at ++ * any other time they will only be ballpark correct because of ++ * reservations that have been taken out percpu counters. If we have an ++ * unclean shutdown, this will be corrected by log recovery rebuilding ++ * the counters from the AGF block counts. ++ */ ++ if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { ++ mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); ++ mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree); ++ mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); ++ } + + xfs_sb_to_disk(bp->b_addr, &mp->m_sb); + xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); +diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c +index 4b76a32d2f16d..953de843d9c38 100644 +--- a/fs/xfs/xfs_aops.c ++++ b/fs/xfs/xfs_aops.c +@@ -62,7 +62,7 @@ xfs_setfilesize_trans_alloc( + * We hand off the transaction to the completion thread now, so + * clear the flag here. + */ +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); ++ xfs_trans_clear_context(tp); + return 0; + } + +@@ -125,7 +125,7 @@ xfs_setfilesize_ioend( + * thus we need to mark ourselves as being in a transaction manually. + * Similarly for freeze protection. + */ +- current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); ++ xfs_trans_set_context(tp); + __sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS); + + /* we abort the update if there was an IO error */ +@@ -577,6 +577,12 @@ xfs_vm_writepage( + { + struct xfs_writepage_ctx wpc = { }; + ++ if (WARN_ON_ONCE(current->journal_info)) { ++ redirty_page_for_writepage(wbc, page); ++ unlock_page(page); ++ return 0; ++ } ++ + return iomap_writepage(page, wbc, &wpc.ctx, &xfs_writeback_ops); + } + +@@ -587,6 +593,13 @@ xfs_vm_writepages( + { + struct xfs_writepage_ctx wpc = { }; + ++ /* ++ * Writing back data in a transaction context can result in recursive ++ * transactions. This is bad, so issue a warning and get out of here. ++ */ ++ if (WARN_ON_ONCE(current->journal_info)) ++ return 0; ++ + xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); + return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops); + } +diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c +index 7f6e208994730..f9e2f606b5b8c 100644 +--- a/fs/xfs/xfs_error.c ++++ b/fs/xfs/xfs_error.c +@@ -293,6 +293,8 @@ xfs_errortag_add( + struct xfs_mount *mp, + unsigned int error_tag) + { ++ BUILD_BUG_ON(ARRAY_SIZE(xfs_errortag_random_default) != XFS_ERRTAG_MAX); ++ + if (error_tag >= XFS_ERRTAG_MAX) + return -EINVAL; + +diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c +index 6fa05fb78189b..aa46b75d75af5 100644 +--- a/fs/xfs/xfs_reflink.c ++++ b/fs/xfs/xfs_reflink.c +@@ -1503,7 +1503,8 @@ xfs_reflink_unshare( + if (error) + goto out; + +- error = filemap_write_and_wait_range(inode->i_mapping, offset, len); ++ error = filemap_write_and_wait_range(inode->i_mapping, offset, ++ offset + len - 1); + if (error) + goto out; + +diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c +index 05cea7788d494..6323974d6b3e6 100644 +--- a/fs/xfs/xfs_super.c ++++ b/fs/xfs/xfs_super.c +@@ -1155,6 +1155,22 @@ suffix_kstrtoint( + return ret; + } + ++static inline void ++xfs_fs_warn_deprecated( ++ struct fs_context *fc, ++ struct fs_parameter *param, ++ uint64_t flag, ++ bool value) ++{ ++ /* Don't print the warning if reconfiguring and current mount point ++ * already had the flag set ++ */ ++ if ((fc->purpose & FS_CONTEXT_FOR_RECONFIGURE) && ++ !!(XFS_M(fc->root->d_sb)->m_flags & flag) == value) ++ return; ++ xfs_warn(fc->s_fs_info, "%s mount option is deprecated.", param->key); ++} ++ + /* + * Set mount state from a mount option. + * +@@ -1165,7 +1181,7 @@ xfs_fc_parse_param( + struct fs_context *fc, + struct fs_parameter *param) + { +- struct xfs_mount *mp = fc->s_fs_info; ++ struct xfs_mount *parsing_mp = fc->s_fs_info; + struct fs_parse_result result; + int size = 0; + int opt; +@@ -1176,142 +1192,142 @@ xfs_fc_parse_param( + + switch (opt) { + case Opt_logbufs: +- mp->m_logbufs = result.uint_32; ++ parsing_mp->m_logbufs = result.uint_32; + return 0; + case Opt_logbsize: +- if (suffix_kstrtoint(param->string, 10, &mp->m_logbsize)) ++ if (suffix_kstrtoint(param->string, 10, &parsing_mp->m_logbsize)) + return -EINVAL; + return 0; + case Opt_logdev: +- kfree(mp->m_logname); +- mp->m_logname = kstrdup(param->string, GFP_KERNEL); +- if (!mp->m_logname) ++ kfree(parsing_mp->m_logname); ++ parsing_mp->m_logname = kstrdup(param->string, GFP_KERNEL); ++ if (!parsing_mp->m_logname) + return -ENOMEM; + return 0; + case Opt_rtdev: +- kfree(mp->m_rtname); +- mp->m_rtname = kstrdup(param->string, GFP_KERNEL); +- if (!mp->m_rtname) ++ kfree(parsing_mp->m_rtname); ++ parsing_mp->m_rtname = kstrdup(param->string, GFP_KERNEL); ++ if (!parsing_mp->m_rtname) + return -ENOMEM; + return 0; + case Opt_allocsize: + if (suffix_kstrtoint(param->string, 10, &size)) + return -EINVAL; +- mp->m_allocsize_log = ffs(size) - 1; +- mp->m_flags |= XFS_MOUNT_ALLOCSIZE; ++ parsing_mp->m_allocsize_log = ffs(size) - 1; ++ parsing_mp->m_flags |= XFS_MOUNT_ALLOCSIZE; + return 0; + case Opt_grpid: + case Opt_bsdgroups: +- mp->m_flags |= XFS_MOUNT_GRPID; ++ parsing_mp->m_flags |= XFS_MOUNT_GRPID; + return 0; + case Opt_nogrpid: + case Opt_sysvgroups: +- mp->m_flags &= ~XFS_MOUNT_GRPID; ++ parsing_mp->m_flags &= ~XFS_MOUNT_GRPID; + return 0; + case Opt_wsync: +- mp->m_flags |= XFS_MOUNT_WSYNC; ++ parsing_mp->m_flags |= XFS_MOUNT_WSYNC; + return 0; + case Opt_norecovery: +- mp->m_flags |= XFS_MOUNT_NORECOVERY; ++ parsing_mp->m_flags |= XFS_MOUNT_NORECOVERY; + return 0; + case Opt_noalign: +- mp->m_flags |= XFS_MOUNT_NOALIGN; ++ parsing_mp->m_flags |= XFS_MOUNT_NOALIGN; + return 0; + case Opt_swalloc: +- mp->m_flags |= XFS_MOUNT_SWALLOC; ++ parsing_mp->m_flags |= XFS_MOUNT_SWALLOC; + return 0; + case Opt_sunit: +- mp->m_dalign = result.uint_32; ++ parsing_mp->m_dalign = result.uint_32; + return 0; + case Opt_swidth: +- mp->m_swidth = result.uint_32; ++ parsing_mp->m_swidth = result.uint_32; + return 0; + case Opt_inode32: +- mp->m_flags |= XFS_MOUNT_SMALL_INUMS; ++ parsing_mp->m_flags |= XFS_MOUNT_SMALL_INUMS; + return 0; + case Opt_inode64: +- mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; ++ parsing_mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; + return 0; + case Opt_nouuid: +- mp->m_flags |= XFS_MOUNT_NOUUID; ++ parsing_mp->m_flags |= XFS_MOUNT_NOUUID; + return 0; + case Opt_largeio: +- mp->m_flags |= XFS_MOUNT_LARGEIO; ++ parsing_mp->m_flags |= XFS_MOUNT_LARGEIO; + return 0; + case Opt_nolargeio: +- mp->m_flags &= ~XFS_MOUNT_LARGEIO; ++ parsing_mp->m_flags &= ~XFS_MOUNT_LARGEIO; + return 0; + case Opt_filestreams: +- mp->m_flags |= XFS_MOUNT_FILESTREAMS; ++ parsing_mp->m_flags |= XFS_MOUNT_FILESTREAMS; + return 0; + case Opt_noquota: +- mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; +- mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; +- mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE; ++ parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; ++ parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; ++ parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE; + return 0; + case Opt_quota: + case Opt_uquota: + case Opt_usrquota: +- mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE | ++ parsing_mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE | + XFS_UQUOTA_ENFD); + return 0; + case Opt_qnoenforce: + case Opt_uqnoenforce: +- mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); +- mp->m_qflags &= ~XFS_UQUOTA_ENFD; ++ parsing_mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); ++ parsing_mp->m_qflags &= ~XFS_UQUOTA_ENFD; + return 0; + case Opt_pquota: + case Opt_prjquota: +- mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE | ++ parsing_mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE | + XFS_PQUOTA_ENFD); + return 0; + case Opt_pqnoenforce: +- mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); +- mp->m_qflags &= ~XFS_PQUOTA_ENFD; ++ parsing_mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); ++ parsing_mp->m_qflags &= ~XFS_PQUOTA_ENFD; + return 0; + case Opt_gquota: + case Opt_grpquota: +- mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE | ++ parsing_mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE | + XFS_GQUOTA_ENFD); + return 0; + case Opt_gqnoenforce: +- mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); +- mp->m_qflags &= ~XFS_GQUOTA_ENFD; ++ parsing_mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); ++ parsing_mp->m_qflags &= ~XFS_GQUOTA_ENFD; + return 0; + case Opt_discard: +- mp->m_flags |= XFS_MOUNT_DISCARD; ++ parsing_mp->m_flags |= XFS_MOUNT_DISCARD; + return 0; + case Opt_nodiscard: +- mp->m_flags &= ~XFS_MOUNT_DISCARD; ++ parsing_mp->m_flags &= ~XFS_MOUNT_DISCARD; + return 0; + #ifdef CONFIG_FS_DAX + case Opt_dax: +- xfs_mount_set_dax_mode(mp, XFS_DAX_ALWAYS); ++ xfs_mount_set_dax_mode(parsing_mp, XFS_DAX_ALWAYS); + return 0; + case Opt_dax_enum: +- xfs_mount_set_dax_mode(mp, result.uint_32); ++ xfs_mount_set_dax_mode(parsing_mp, result.uint_32); + return 0; + #endif + /* Following mount options will be removed in September 2025 */ + case Opt_ikeep: +- xfs_warn(mp, "%s mount option is deprecated.", param->key); +- mp->m_flags |= XFS_MOUNT_IKEEP; ++ xfs_fs_warn_deprecated(fc, param, XFS_MOUNT_IKEEP, true); ++ parsing_mp->m_flags |= XFS_MOUNT_IKEEP; + return 0; + case Opt_noikeep: +- xfs_warn(mp, "%s mount option is deprecated.", param->key); +- mp->m_flags &= ~XFS_MOUNT_IKEEP; ++ xfs_fs_warn_deprecated(fc, param, XFS_MOUNT_IKEEP, false); ++ parsing_mp->m_flags &= ~XFS_MOUNT_IKEEP; + return 0; + case Opt_attr2: +- xfs_warn(mp, "%s mount option is deprecated.", param->key); +- mp->m_flags |= XFS_MOUNT_ATTR2; ++ xfs_fs_warn_deprecated(fc, param, XFS_MOUNT_ATTR2, true); ++ parsing_mp->m_flags |= XFS_MOUNT_ATTR2; + return 0; + case Opt_noattr2: +- xfs_warn(mp, "%s mount option is deprecated.", param->key); +- mp->m_flags &= ~XFS_MOUNT_ATTR2; +- mp->m_flags |= XFS_MOUNT_NOATTR2; ++ xfs_fs_warn_deprecated(fc, param, XFS_MOUNT_NOATTR2, true); ++ parsing_mp->m_flags &= ~XFS_MOUNT_ATTR2; ++ parsing_mp->m_flags |= XFS_MOUNT_NOATTR2; + return 0; + default: +- xfs_warn(mp, "unknown mount option [%s].", param->key); ++ xfs_warn(parsing_mp, "unknown mount option [%s].", param->key); + return -EINVAL; + } + +@@ -1918,7 +1934,7 @@ xfs_init_zones(void) + if (!xfs_ifork_zone) + goto out_destroy_da_state_zone; + +- xfs_trans_zone = kmem_cache_create("xf_trans", ++ xfs_trans_zone = kmem_cache_create("xfs_trans", + sizeof(struct xfs_trans), + 0, 0, NULL); + if (!xfs_trans_zone) +diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c +index c94e71f741b67..36166bae24a6f 100644 +--- a/fs/xfs/xfs_trans.c ++++ b/fs/xfs/xfs_trans.c +@@ -68,6 +68,7 @@ xfs_trans_free( + xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false); + + trace_xfs_trans_free(tp, _RET_IP_); ++ xfs_trans_clear_context(tp); + if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT)) + sb_end_intwrite(tp->t_mountp->m_super); + xfs_trans_free_dqinfo(tp); +@@ -119,7 +120,8 @@ xfs_trans_dup( + + ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; + tp->t_rtx_res = tp->t_rtx_res_used; +- ntp->t_pflags = tp->t_pflags; ++ ++ xfs_trans_switch_context(tp, ntp); + + /* move deferred ops over to the new tp */ + xfs_defer_move(ntp, tp); +@@ -153,9 +155,6 @@ xfs_trans_reserve( + int error = 0; + bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; + +- /* Mark this thread as being in a transaction */ +- current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); +- + /* + * Attempt to reserve the needed disk blocks by decrementing + * the number needed from the number available. This will +@@ -163,10 +162,8 @@ xfs_trans_reserve( + */ + if (blocks > 0) { + error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd); +- if (error != 0) { +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); ++ if (error != 0) + return -ENOSPC; +- } + tp->t_blk_res += blocks; + } + +@@ -240,9 +237,6 @@ undo_blocks: + xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd); + tp->t_blk_res = 0; + } +- +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); +- + return error; + } + +@@ -266,6 +260,7 @@ xfs_trans_alloc( + tp = kmem_cache_zalloc(xfs_trans_zone, GFP_KERNEL | __GFP_NOFAIL); + if (!(flags & XFS_TRANS_NO_WRITECOUNT)) + sb_start_intwrite(mp->m_super); ++ xfs_trans_set_context(tp); + + /* + * Zero-reservation ("empty") transactions can't modify anything, so +@@ -620,6 +615,9 @@ xfs_trans_unreserve_and_mod_sb( + + /* apply remaining deltas */ + spin_lock(&mp->m_sb_lock); ++ mp->m_sb.sb_fdblocks += tp->t_fdblocks_delta + tp->t_res_fdblocks_delta; ++ mp->m_sb.sb_icount += idelta; ++ mp->m_sb.sb_ifree += ifreedelta; + mp->m_sb.sb_frextents += rtxdelta; + mp->m_sb.sb_dblocks += tp->t_dblocks_delta; + mp->m_sb.sb_agcount += tp->t_agcount_delta; +@@ -878,7 +876,6 @@ __xfs_trans_commit( + + xfs_log_commit_cil(mp, tp, &commit_lsn, regrant); + +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); + xfs_trans_free(tp); + + /* +@@ -910,7 +907,6 @@ out_unreserve: + xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket); + tp->t_ticket = NULL; + } +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); + xfs_trans_free_items(tp, !!error); + xfs_trans_free(tp); + +@@ -970,9 +966,6 @@ xfs_trans_cancel( + tp->t_ticket = NULL; + } + +- /* mark this thread as no longer being in a transaction */ +- current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); +- + xfs_trans_free_items(tp, dirty); + xfs_trans_free(tp); + } +diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h +index 084658946cc89..075eeade4f7d5 100644 +--- a/fs/xfs/xfs_trans.h ++++ b/fs/xfs/xfs_trans.h +@@ -268,4 +268,34 @@ xfs_trans_item_relog( + return lip->li_ops->iop_relog(lip, tp); + } + ++static inline void ++xfs_trans_set_context( ++ struct xfs_trans *tp) ++{ ++ ASSERT(current->journal_info == NULL); ++ tp->t_pflags = memalloc_nofs_save(); ++ current->journal_info = tp; ++} ++ ++static inline void ++xfs_trans_clear_context( ++ struct xfs_trans *tp) ++{ ++ if (current->journal_info == tp) { ++ memalloc_nofs_restore(tp->t_pflags); ++ current->journal_info = NULL; ++ } ++} ++ ++static inline void ++xfs_trans_switch_context( ++ struct xfs_trans *old_tp, ++ struct xfs_trans *new_tp) ++{ ++ ASSERT(current->journal_info == old_tp); ++ new_tp->t_pflags = old_tp->t_pflags; ++ old_tp->t_pflags = 0; ++ current->journal_info = new_tp; ++} ++ + #endif /* __XFS_TRANS_H__ */ +diff --git a/include/linux/dim.h b/include/linux/dim.h +index b698266d00356..6c5733981563e 100644 +--- a/include/linux/dim.h ++++ b/include/linux/dim.h +@@ -21,7 +21,7 @@ + * We consider 10% difference as significant. + */ + #define IS_SIGNIFICANT_DIFF(val, ref) \ +- (((100UL * abs((val) - (ref))) / (ref)) > 10) ++ ((ref) && (((100UL * abs((val) - (ref))) / (ref)) > 10)) + + /* + * Calculate the gap between two values. +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index e25be2d01a7ac..4b74c67f13c9d 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -410,7 +410,7 @@ int skb_tunnel_check_pmtu(struct sk_buff *skb, struct dst_entry *encap_dst, + u32 mtu = dst_mtu(encap_dst) - headroom; + + if ((skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) || +- (!skb_is_gso(skb) && (skb->len - skb_mac_header_len(skb)) <= mtu)) ++ (!skb_is_gso(skb) && (skb->len - skb_network_offset(skb)) <= mtu)) + return 0; + + skb_dst_update_pmtu_no_confirm(skb, mtu); +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index 017cd666387f3..32c60122db9c8 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1980,7 +1980,8 @@ process: + struct sock *nsk; + + sk = req->rsk_listener; +- if (unlikely(tcp_v4_inbound_md5_hash(sk, skb, dif, sdif))) { ++ if (unlikely(!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb) || ++ tcp_v4_inbound_md5_hash(sk, skb, dif, sdif))) { + sk_drops_add(sk, skb); + reqsk_put(req); + goto discard_it; +@@ -2019,6 +2020,7 @@ process: + } + goto discard_and_relse; + } ++ nf_reset_ct(skb); + if (nsk == sk) { + reqsk_put(req); + tcp_v4_restore_cb(skb); +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 0562fb321959e..05317e6f48f8a 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1102,10 +1102,6 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg, + goto out; + } + +- if (net->ipv6.devconf_all->disable_policy || +- idev->cnf.disable_policy) +- f6i->dst_nopolicy = true; +- + neigh_parms_data_state_setall(idev->nd_parms); + + ifa->addr = *cfg->pfx; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 6ace9f0ac22f3..e67505c6d8562 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -4479,8 +4479,15 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net, + } + + f6i = ip6_route_info_create(&cfg, gfp_flags, NULL); +- if (!IS_ERR(f6i)) ++ if (!IS_ERR(f6i)) { + f6i->dst_nocount = true; ++ ++ if (!anycast && ++ (net->ipv6.devconf_all->disable_policy || ++ idev->cnf.disable_policy)) ++ f6i->dst_nopolicy = true; ++ } ++ + return f6i; + } + +diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c +index b9179708e3c1a..552bce1fdfb94 100644 +--- a/net/ipv6/seg6_hmac.c ++++ b/net/ipv6/seg6_hmac.c +@@ -409,7 +409,6 @@ int __net_init seg6_hmac_net_init(struct net *net) + + return 0; + } +-EXPORT_SYMBOL(seg6_hmac_net_init); + + void seg6_hmac_exit(void) + { +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index bab0e99f6e356..3c92e8cacbbab 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -321,9 +321,7 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ifreq *ifr) + kcalloc(cmax, sizeof(*kp), GFP_KERNEL | __GFP_NOWARN) : + NULL; + +- rcu_read_lock(); +- +- ca = t->prl_count < cmax ? t->prl_count : cmax; ++ ca = min(t->prl_count, cmax); + + if (!kp) { + /* We don't try hard to allocate much memory for +@@ -338,7 +336,7 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ifreq *ifr) + } + } + +- c = 0; ++ rcu_read_lock(); + for_each_prl_rcu(t->prl) { + if (c >= cmax) + break; +@@ -350,7 +348,7 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ifreq *ifr) + if (kprl.addr != htonl(INADDR_ANY)) + break; + } +-out: ++ + rcu_read_unlock(); + + len = sizeof(*kp) * c; +@@ -359,7 +357,7 @@ out: + ret = -EFAULT; + + kfree(kp); +- ++out: + return ret; + } + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index 858c8d4d659a8..a5cfb321ae23a 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -142,6 +142,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key, + /* Another cpu may race to insert the element with the same key */ + if (prev) { + nft_set_elem_destroy(set, he, true); ++ atomic_dec(&set->nelems); + he = prev; + } + +@@ -151,6 +152,7 @@ out: + + err2: + nft_set_elem_destroy(set, he, true); ++ atomic_dec(&set->nelems); + err1: + return false; + } +diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c +index b3138fc2e552e..f06ddbed3fed6 100644 +--- a/net/rose/rose_timer.c ++++ b/net/rose/rose_timer.c +@@ -31,89 +31,89 @@ static void rose_idletimer_expiry(struct timer_list *); + + void rose_start_heartbeat(struct sock *sk) + { +- del_timer(&sk->sk_timer); ++ sk_stop_timer(sk, &sk->sk_timer); + + sk->sk_timer.function = rose_heartbeat_expiry; + sk->sk_timer.expires = jiffies + 5 * HZ; + +- add_timer(&sk->sk_timer); ++ sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires); + } + + void rose_start_t1timer(struct sock *sk) + { + struct rose_sock *rose = rose_sk(sk); + +- del_timer(&rose->timer); ++ sk_stop_timer(sk, &rose->timer); + + rose->timer.function = rose_timer_expiry; + rose->timer.expires = jiffies + rose->t1; + +- add_timer(&rose->timer); ++ sk_reset_timer(sk, &rose->timer, rose->timer.expires); + } + + void rose_start_t2timer(struct sock *sk) + { + struct rose_sock *rose = rose_sk(sk); + +- del_timer(&rose->timer); ++ sk_stop_timer(sk, &rose->timer); + + rose->timer.function = rose_timer_expiry; + rose->timer.expires = jiffies + rose->t2; + +- add_timer(&rose->timer); ++ sk_reset_timer(sk, &rose->timer, rose->timer.expires); + } + + void rose_start_t3timer(struct sock *sk) + { + struct rose_sock *rose = rose_sk(sk); + +- del_timer(&rose->timer); ++ sk_stop_timer(sk, &rose->timer); + + rose->timer.function = rose_timer_expiry; + rose->timer.expires = jiffies + rose->t3; + +- add_timer(&rose->timer); ++ sk_reset_timer(sk, &rose->timer, rose->timer.expires); + } + + void rose_start_hbtimer(struct sock *sk) + { + struct rose_sock *rose = rose_sk(sk); + +- del_timer(&rose->timer); ++ sk_stop_timer(sk, &rose->timer); + + rose->timer.function = rose_timer_expiry; + rose->timer.expires = jiffies + rose->hb; + +- add_timer(&rose->timer); ++ sk_reset_timer(sk, &rose->timer, rose->timer.expires); + } + + void rose_start_idletimer(struct sock *sk) + { + struct rose_sock *rose = rose_sk(sk); + +- del_timer(&rose->idletimer); ++ sk_stop_timer(sk, &rose->idletimer); + + if (rose->idle > 0) { + rose->idletimer.function = rose_idletimer_expiry; + rose->idletimer.expires = jiffies + rose->idle; + +- add_timer(&rose->idletimer); ++ sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires); + } + } + + void rose_stop_heartbeat(struct sock *sk) + { +- del_timer(&sk->sk_timer); ++ sk_stop_timer(sk, &sk->sk_timer); + } + + void rose_stop_timer(struct sock *sk) + { +- del_timer(&rose_sk(sk)->timer); ++ sk_stop_timer(sk, &rose_sk(sk)->timer); + } + + void rose_stop_idletimer(struct sock *sk) + { +- del_timer(&rose_sk(sk)->idletimer); ++ sk_stop_timer(sk, &rose_sk(sk)->idletimer); + } + + static void rose_heartbeat_expiry(struct timer_list *t) +@@ -130,6 +130,7 @@ static void rose_heartbeat_expiry(struct timer_list *t) + (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { + bh_unlock_sock(sk); + rose_destroy_socket(sk); ++ sock_put(sk); + return; + } + break; +@@ -152,6 +153,7 @@ static void rose_heartbeat_expiry(struct timer_list *t) + + rose_start_heartbeat(sk); + bh_unlock_sock(sk); ++ sock_put(sk); + } + + static void rose_timer_expiry(struct timer_list *t) +@@ -181,6 +183,7 @@ static void rose_timer_expiry(struct timer_list *t) + break; + } + bh_unlock_sock(sk); ++ sock_put(sk); + } + + static void rose_idletimer_expiry(struct timer_list *t) +@@ -205,4 +208,5 @@ static void rose_idletimer_expiry(struct timer_list *t) + sock_set_flag(sk, SOCK_DEAD); + } + bh_unlock_sock(sk); ++ sock_put(sk); + } +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index 7b29aa1a3ce9a..4ab9c2a6f6501 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -302,7 +302,8 @@ static int tcf_idr_release_unsafe(struct tc_action *p) + } + + static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, +- const struct tc_action_ops *ops) ++ const struct tc_action_ops *ops, ++ struct netlink_ext_ack *extack) + { + struct nlattr *nest; + int n_i = 0; +@@ -318,20 +319,25 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, + if (nla_put_string(skb, TCA_KIND, ops->kind)) + goto nla_put_failure; + ++ ret = 0; + mutex_lock(&idrinfo->lock); + idr_for_each_entry_ul(idr, p, tmp, id) { + if (IS_ERR(p)) + continue; + ret = tcf_idr_release_unsafe(p); +- if (ret == ACT_P_DELETED) { ++ if (ret == ACT_P_DELETED) + module_put(ops->owner); +- n_i++; +- } else if (ret < 0) { +- mutex_unlock(&idrinfo->lock); +- goto nla_put_failure; +- } ++ else if (ret < 0) ++ break; ++ n_i++; + } + mutex_unlock(&idrinfo->lock); ++ if (ret < 0) { ++ if (n_i) ++ NL_SET_ERR_MSG(extack, "Unable to flush all TC actions"); ++ else ++ goto nla_put_failure; ++ } + + ret = nla_put_u32(skb, TCA_FCNT, n_i); + if (ret) +@@ -352,7 +358,7 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, + struct tcf_idrinfo *idrinfo = tn->idrinfo; + + if (type == RTM_DELACTION) { +- return tcf_del_walker(idrinfo, skb, ops); ++ return tcf_del_walker(idrinfo, skb, ops, extack); + } else if (type == RTM_GETACTION) { + return tcf_dump_walker(idrinfo, skb, cb); + } else { +diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c +index c8ed6d3d5762e..d84bb5037bb5b 100644 +--- a/net/sunrpc/xdr.c ++++ b/net/sunrpc/xdr.c +@@ -752,7 +752,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, + */ + xdr->p = (void *)p + frag2bytes; + space_left = xdr->buf->buflen - xdr->buf->len; +- if (space_left - nbytes >= PAGE_SIZE) ++ if (space_left - frag1bytes >= PAGE_SIZE) + xdr->end = (void *)p + PAGE_SIZE; + else + xdr->end = (void *)p + space_left - frag1bytes; +diff --git a/net/tipc/node.c b/net/tipc/node.c +index e4452d55851f9..60059827563ae 100644 +--- a/net/tipc/node.c ++++ b/net/tipc/node.c +@@ -456,8 +456,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id, + bool preliminary) + { + struct tipc_net *tn = net_generic(net, tipc_net_id); ++ struct tipc_link *l, *snd_l = tipc_bc_sndlink(net); + struct tipc_node *n, *temp_node; +- struct tipc_link *l; + unsigned long intv; + int bearer_id; + int i; +@@ -472,6 +472,16 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id, + goto exit; + /* A preliminary node becomes "real" now, refresh its data */ + tipc_node_write_lock(n); ++ if (!tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX, ++ tipc_link_min_win(snd_l), tipc_link_max_win(snd_l), ++ n->capabilities, &n->bc_entry.inputq1, ++ &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) { ++ pr_warn("Broadcast rcv link refresh failed, no memory\n"); ++ tipc_node_write_unlock_fast(n); ++ tipc_node_put(n); ++ n = NULL; ++ goto exit; ++ } + n->preliminary = false; + n->addr = addr; + hlist_del_rcu(&n->hash); +@@ -551,7 +561,16 @@ update: + n->signature = INVALID_NODE_SIG; + n->active_links[0] = INVALID_BEARER_ID; + n->active_links[1] = INVALID_BEARER_ID; +- n->bc_entry.link = NULL; ++ if (!preliminary && ++ !tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX, ++ tipc_link_min_win(snd_l), tipc_link_max_win(snd_l), ++ n->capabilities, &n->bc_entry.inputq1, ++ &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) { ++ pr_warn("Broadcast rcv link creation failed, no memory\n"); ++ kfree(n); ++ n = NULL; ++ goto exit; ++ } + tipc_node_get(n); + timer_setup(&n->timer, tipc_node_timeout, 0); + /* Start a slow timer anyway, crypto needs it */ +@@ -1128,7 +1147,7 @@ void tipc_node_check_dest(struct net *net, u32 addr, + bool *respond, bool *dupl_addr) + { + struct tipc_node *n; +- struct tipc_link *l, *snd_l; ++ struct tipc_link *l; + struct tipc_link_entry *le; + bool addr_match = false; + bool sign_match = false; +@@ -1148,22 +1167,6 @@ void tipc_node_check_dest(struct net *net, u32 addr, + return; + + tipc_node_write_lock(n); +- if (unlikely(!n->bc_entry.link)) { +- snd_l = tipc_bc_sndlink(net); +- if (!tipc_link_bc_create(net, tipc_own_addr(net), +- addr, peer_id, U16_MAX, +- tipc_link_min_win(snd_l), +- tipc_link_max_win(snd_l), +- n->capabilities, +- &n->bc_entry.inputq1, +- &n->bc_entry.namedq, snd_l, +- &n->bc_entry.link)) { +- pr_warn("Broadcast rcv link creation failed, no mem\n"); +- tipc_node_write_unlock_fast(n); +- tipc_node_put(n); +- return; +- } +- } + + le = &n->links[b->identity]; + +diff --git a/tools/testing/selftests/net/udpgso_bench.sh b/tools/testing/selftests/net/udpgso_bench.sh +index 80b5d352702e5..dc932fd653634 100755 +--- a/tools/testing/selftests/net/udpgso_bench.sh ++++ b/tools/testing/selftests/net/udpgso_bench.sh +@@ -120,7 +120,7 @@ run_all() { + run_udp "${ipv4_args}" + + echo "ipv6" +- run_tcp "${ipv4_args}" ++ run_tcp "${ipv6_args}" + run_udp "${ipv6_args}" + } + +diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile +index 2af9d39a97168..215e1067f0376 100644 +--- a/tools/testing/selftests/rseq/Makefile ++++ b/tools/testing/selftests/rseq/Makefile +@@ -6,7 +6,7 @@ endif + + CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L$(OUTPUT) -Wl,-rpath=./ \ + $(CLANG_FLAGS) +-LDLIBS += -lpthread ++LDLIBS += -lpthread -ldl + + # Own dependencies because we only want to build against 1st prerequisite, but + # still track changes to header files and depend on shared object. +diff --git a/tools/testing/selftests/rseq/basic_percpu_ops_test.c b/tools/testing/selftests/rseq/basic_percpu_ops_test.c +index eb3f6db36d369..517756afc2a4e 100644 +--- a/tools/testing/selftests/rseq/basic_percpu_ops_test.c ++++ b/tools/testing/selftests/rseq/basic_percpu_ops_test.c +@@ -9,10 +9,9 @@ + #include <string.h> + #include <stddef.h> + ++#include "../kselftest.h" + #include "rseq.h" + +-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +- + struct percpu_lock_entry { + intptr_t v; + } __attribute__((aligned(128))); +@@ -168,7 +167,7 @@ struct percpu_list_node *this_cpu_list_pop(struct percpu_list *list, + for (;;) { + struct percpu_list_node *head; + intptr_t *targetptr, expectnot, *load; +- off_t offset; ++ long offset; + int ret, cpu; + + cpu = rseq_cpu_start(); +diff --git a/tools/testing/selftests/rseq/compiler.h b/tools/testing/selftests/rseq/compiler.h +new file mode 100644 +index 0000000000000..876eb6a7f75be +--- /dev/null ++++ b/tools/testing/selftests/rseq/compiler.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */ ++/* ++ * rseq/compiler.h ++ * ++ * Work-around asm goto compiler bugs. ++ * ++ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#ifndef RSEQ_COMPILER_H ++#define RSEQ_COMPILER_H ++ ++/* ++ * gcc prior to 4.8.2 miscompiles asm goto. ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 ++ * ++ * gcc prior to 8.1.0 miscompiles asm goto at O1. ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103908 ++ * ++ * clang prior to version 13.0.1 miscompiles asm goto at O2. ++ * https://github.com/llvm/llvm-project/issues/52735 ++ * ++ * Work around these issues by adding a volatile inline asm with ++ * memory clobber in the fallthrough after the asm goto and at each ++ * label target. Emit this for all compilers in case other similar ++ * issues are found in the future. ++ */ ++#define rseq_after_asm_goto() asm volatile ("" : : : "memory") ++ ++#endif /* RSEQ_COMPILER_H_ */ +diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c +index 384589095864d..e29ecc7158e8b 100644 +--- a/tools/testing/selftests/rseq/param_test.c ++++ b/tools/testing/selftests/rseq/param_test.c +@@ -161,7 +161,7 @@ unsigned int yield_mod_cnt, nr_abort; + " cbnz " INJECT_ASM_REG ", 222b\n" \ + "333:\n" + +-#elif __PPC__ ++#elif defined(__PPC__) + + #define RSEQ_INJECT_INPUT \ + , [loop_cnt_1]"m"(loop_cnt[1]) \ +@@ -368,9 +368,7 @@ void *test_percpu_spinlock_thread(void *arg) + abort(); + reps = thread_data->reps; + for (i = 0; i < reps; i++) { +- int cpu = rseq_cpu_start(); +- +- cpu = rseq_this_cpu_lock(&data->lock); ++ int cpu = rseq_this_cpu_lock(&data->lock); + data->c[cpu].count++; + rseq_percpu_unlock(&data->lock, cpu); + #ifndef BENCHMARK +@@ -551,7 +549,7 @@ struct percpu_list_node *this_cpu_list_pop(struct percpu_list *list, + for (;;) { + struct percpu_list_node *head; + intptr_t *targetptr, expectnot, *load; +- off_t offset; ++ long offset; + int ret; + + cpu = rseq_cpu_start(); +diff --git a/tools/testing/selftests/rseq/rseq-abi.h b/tools/testing/selftests/rseq/rseq-abi.h +new file mode 100644 +index 0000000000000..a8c44d9af71fb +--- /dev/null ++++ b/tools/testing/selftests/rseq/rseq-abi.h +@@ -0,0 +1,151 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++#ifndef _RSEQ_ABI_H ++#define _RSEQ_ABI_H ++ ++/* ++ * rseq-abi.h ++ * ++ * Restartable sequences system call API ++ * ++ * Copyright (c) 2015-2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#include <linux/types.h> ++#include <asm/byteorder.h> ++ ++enum rseq_abi_cpu_id_state { ++ RSEQ_ABI_CPU_ID_UNINITIALIZED = -1, ++ RSEQ_ABI_CPU_ID_REGISTRATION_FAILED = -2, ++}; ++ ++enum rseq_abi_flags { ++ RSEQ_ABI_FLAG_UNREGISTER = (1 << 0), ++}; ++ ++enum rseq_abi_cs_flags_bit { ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, ++}; ++ ++enum rseq_abi_cs_flags { ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_PREEMPT = ++ (1U << RSEQ_ABI_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT), ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_SIGNAL = ++ (1U << RSEQ_ABI_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT), ++ RSEQ_ABI_CS_FLAG_NO_RESTART_ON_MIGRATE = ++ (1U << RSEQ_ABI_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT), ++}; ++ ++/* ++ * struct rseq_abi_cs is aligned on 4 * 8 bytes to ensure it is always ++ * contained within a single cache-line. It is usually declared as ++ * link-time constant data. ++ */ ++struct rseq_abi_cs { ++ /* Version of this structure. */ ++ __u32 version; ++ /* enum rseq_abi_cs_flags */ ++ __u32 flags; ++ __u64 start_ip; ++ /* Offset from start_ip. */ ++ __u64 post_commit_offset; ++ __u64 abort_ip; ++} __attribute__((aligned(4 * sizeof(__u64)))); ++ ++/* ++ * struct rseq_abi is aligned on 4 * 8 bytes to ensure it is always ++ * contained within a single cache-line. ++ * ++ * A single struct rseq_abi per thread is allowed. ++ */ ++struct rseq_abi { ++ /* ++ * Restartable sequences cpu_id_start field. Updated by the ++ * kernel. Read by user-space with single-copy atomicity ++ * semantics. This field should only be read by the thread which ++ * registered this data structure. Aligned on 32-bit. Always ++ * contains a value in the range of possible CPUs, although the ++ * value may not be the actual current CPU (e.g. if rseq is not ++ * initialized). This CPU number value should always be compared ++ * against the value of the cpu_id field before performing a rseq ++ * commit or returning a value read from a data structure indexed ++ * using the cpu_id_start value. ++ */ ++ __u32 cpu_id_start; ++ /* ++ * Restartable sequences cpu_id field. Updated by the kernel. ++ * Read by user-space with single-copy atomicity semantics. This ++ * field should only be read by the thread which registered this ++ * data structure. Aligned on 32-bit. Values ++ * RSEQ_CPU_ID_UNINITIALIZED and RSEQ_CPU_ID_REGISTRATION_FAILED ++ * have a special semantic: the former means "rseq uninitialized", ++ * and latter means "rseq initialization failed". This value is ++ * meant to be read within rseq critical sections and compared ++ * with the cpu_id_start value previously read, before performing ++ * the commit instruction, or read and compared with the ++ * cpu_id_start value before returning a value loaded from a data ++ * structure indexed using the cpu_id_start value. ++ */ ++ __u32 cpu_id; ++ /* ++ * Restartable sequences rseq_cs field. ++ * ++ * Contains NULL when no critical section is active for the current ++ * thread, or holds a pointer to the currently active struct rseq_cs. ++ * ++ * Updated by user-space, which sets the address of the currently ++ * active rseq_cs at the beginning of assembly instruction sequence ++ * block, and set to NULL by the kernel when it restarts an assembly ++ * instruction sequence block, as well as when the kernel detects that ++ * it is preempting or delivering a signal outside of the range ++ * targeted by the rseq_cs. Also needs to be set to NULL by user-space ++ * before reclaiming memory that contains the targeted struct rseq_cs. ++ * ++ * Read and set by the kernel. Set by user-space with single-copy ++ * atomicity semantics. This field should only be updated by the ++ * thread which registered this data structure. Aligned on 64-bit. ++ */ ++ union { ++ __u64 ptr64; ++ ++ /* ++ * The "arch" field provides architecture accessor for ++ * the ptr field based on architecture pointer size and ++ * endianness. ++ */ ++ struct { ++#ifdef __LP64__ ++ __u64 ptr; ++#elif defined(__BYTE_ORDER) ? (__BYTE_ORDER == __BIG_ENDIAN) : defined(__BIG_ENDIAN) ++ __u32 padding; /* Initialized to zero. */ ++ __u32 ptr; ++#else ++ __u32 ptr; ++ __u32 padding; /* Initialized to zero. */ ++#endif ++ } arch; ++ } rseq_cs; ++ ++ /* ++ * Restartable sequences flags field. ++ * ++ * This field should only be updated by the thread which ++ * registered this data structure. Read by the kernel. ++ * Mainly used for single-stepping through rseq critical sections ++ * with debuggers. ++ * ++ * - RSEQ_ABI_CS_FLAG_NO_RESTART_ON_PREEMPT ++ * Inhibit instruction sequence block restart on preemption ++ * for this thread. ++ * - RSEQ_ABI_CS_FLAG_NO_RESTART_ON_SIGNAL ++ * Inhibit instruction sequence block restart on signal ++ * delivery for this thread. ++ * - RSEQ_ABI_CS_FLAG_NO_RESTART_ON_MIGRATE ++ * Inhibit instruction sequence block restart on migration for ++ * this thread. ++ */ ++ __u32 flags; ++} __attribute__((aligned(4 * sizeof(__u64)))); ++ ++#endif /* _RSEQ_ABI_H */ +diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h +index 5943c816c07ce..893a11eca9d51 100644 +--- a/tools/testing/selftests/rseq/rseq-arm.h ++++ b/tools/testing/selftests/rseq/rseq-arm.h +@@ -147,14 +147,11 @@ do { \ + teardown \ + "b %l[" __rseq_str(cmpfail_label) "]\n\t" + +-#define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("") +- + static inline __attribute__((always_inline)) + int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -185,8 +182,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -198,30 +195,31 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } + + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -255,8 +253,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -270,19 +268,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -292,7 +292,6 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + #ifdef RSEQ_COMPARE_TWICE +@@ -316,8 +315,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [count] "Ir" (count) + RSEQ_INJECT_INPUT +@@ -328,14 +327,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -347,7 +347,6 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -381,8 +380,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -398,19 +397,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -422,7 +423,6 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -457,8 +457,8 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -474,19 +474,21 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -498,7 +500,6 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -537,8 +538,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -554,21 +555,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("1st expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -582,7 +586,6 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -657,8 +660,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -678,21 +681,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -706,7 +709,6 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -782,8 +784,8 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -803,21 +805,21 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: +- rseq_workaround_gcc_asm_size_guess(); ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +diff --git a/tools/testing/selftests/rseq/rseq-arm64.h b/tools/testing/selftests/rseq/rseq-arm64.h +index 200dae9e4208c..cbe190a4d0056 100644 +--- a/tools/testing/selftests/rseq/rseq-arm64.h ++++ b/tools/testing/selftests/rseq/rseq-arm64.h +@@ -230,8 +230,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "Qo" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -242,24 +242,28 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } + + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -287,8 +291,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "Qo" (*v), + [expectnot] "r" (expectnot), + [load] "Qo" (*load), +@@ -300,16 +304,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -337,8 +346,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "Qo" (*v), + [count] "r" (count) + RSEQ_INJECT_INPUT +@@ -348,12 +357,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -388,8 +400,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), +@@ -402,17 +414,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -447,8 +463,8 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), +@@ -461,17 +477,21 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -508,8 +528,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "Qo" (*v), + [expect] "r" (expect), + [v2] "Qo" (*v2), +@@ -522,19 +542,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -569,8 +594,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), +@@ -584,17 +609,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -629,8 +658,8 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "Qo" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), +@@ -644,17 +673,21 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +diff --git a/tools/testing/selftests/rseq/rseq-generic-thread-pointer.h b/tools/testing/selftests/rseq/rseq-generic-thread-pointer.h +new file mode 100644 +index 0000000000000..38c5846615714 +--- /dev/null ++++ b/tools/testing/selftests/rseq/rseq-generic-thread-pointer.h +@@ -0,0 +1,25 @@ ++/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */ ++/* ++ * rseq-generic-thread-pointer.h ++ * ++ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#ifndef _RSEQ_GENERIC_THREAD_POINTER ++#define _RSEQ_GENERIC_THREAD_POINTER ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Use gcc builtin thread pointer. */ ++static inline void *rseq_thread_pointer(void) ++{ ++ return __builtin_thread_pointer(); ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/tools/testing/selftests/rseq/rseq-mips.h b/tools/testing/selftests/rseq/rseq-mips.h +index e989e7c14b097..878739fae2fde 100644 +--- a/tools/testing/selftests/rseq/rseq-mips.h ++++ b/tools/testing/selftests/rseq/rseq-mips.h +@@ -154,14 +154,11 @@ do { \ + teardown \ + "b %l[" __rseq_str(cmpfail_label) "]\n\t" + +-#define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("") +- + static inline __attribute__((always_inline)) + int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -190,8 +187,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -203,14 +200,11 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +@@ -222,11 +216,10 @@ error2: + + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -258,8 +251,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -273,14 +266,11 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +@@ -295,7 +285,6 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + #ifdef RSEQ_COMPARE_TWICE +@@ -319,8 +308,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [count] "Ir" (count) + RSEQ_INJECT_INPUT +@@ -331,10 +320,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE +@@ -350,7 +337,6 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -382,8 +368,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -399,14 +385,11 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +@@ -423,7 +406,6 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -456,8 +438,8 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -473,14 +455,11 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +@@ -497,7 +476,6 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + { + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -532,8 +510,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -549,14 +527,11 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +@@ -577,7 +552,6 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -649,8 +623,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -670,21 +644,16 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +- rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); + error2: +- rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -698,7 +667,6 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + + RSEQ_INJECT_C(9) + +- rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) +@@ -771,8 +739,8 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -792,21 +760,16 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); +- rseq_workaround_gcc_asm_size_guess(); + return 0; + abort: +- rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: +- rseq_workaround_gcc_asm_size_guess(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: +- rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); + error2: +- rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); + #endif + } +diff --git a/tools/testing/selftests/rseq/rseq-ppc-thread-pointer.h b/tools/testing/selftests/rseq/rseq-ppc-thread-pointer.h +new file mode 100644 +index 0000000000000..263eee84fb760 +--- /dev/null ++++ b/tools/testing/selftests/rseq/rseq-ppc-thread-pointer.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */ ++/* ++ * rseq-ppc-thread-pointer.h ++ * ++ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#ifndef _RSEQ_PPC_THREAD_POINTER ++#define _RSEQ_PPC_THREAD_POINTER ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++static inline void *rseq_thread_pointer(void) ++{ ++#ifdef __powerpc64__ ++ register void *__result asm ("r13"); ++#else ++ register void *__result asm ("r2"); ++#endif ++ asm ("" : "=r" (__result)); ++ return __result; ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/tools/testing/selftests/rseq/rseq-ppc.h b/tools/testing/selftests/rseq/rseq-ppc.h +index 76be90196fe4f..bab8e0b9fb115 100644 +--- a/tools/testing/selftests/rseq/rseq-ppc.h ++++ b/tools/testing/selftests/rseq/rseq-ppc.h +@@ -47,10 +47,13 @@ do { \ + + #ifdef __PPC64__ + +-#define STORE_WORD "std " +-#define LOAD_WORD "ld " +-#define LOADX_WORD "ldx " +-#define CMP_WORD "cmpd " ++#define RSEQ_STORE_LONG(arg) "std%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ ++#define RSEQ_STORE_INT(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ ++#define RSEQ_LOAD_LONG(arg) "ld%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ ++#define RSEQ_LOAD_INT(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ ++#define RSEQ_LOADX_LONG "ldx " /* From base register ("b" constraint) */ ++#define RSEQ_CMP_LONG "cmpd " ++#define RSEQ_CMP_LONG_INT "cmpdi " + + #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ +@@ -89,10 +92,13 @@ do { \ + + #else /* #ifdef __PPC64__ */ + +-#define STORE_WORD "stw " +-#define LOAD_WORD "lwz " +-#define LOADX_WORD "lwzx " +-#define CMP_WORD "cmpw " ++#define RSEQ_STORE_LONG(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ ++#define RSEQ_STORE_INT(arg) RSEQ_STORE_LONG(arg) /* To memory ("m" constraint) */ ++#define RSEQ_LOAD_LONG(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ ++#define RSEQ_LOAD_INT(arg) RSEQ_LOAD_LONG(arg) /* From memory ("m" constraint) */ ++#define RSEQ_LOADX_LONG "lwzx " /* From base register ("b" constraint) */ ++#define RSEQ_CMP_LONG "cmpw " ++#define RSEQ_CMP_LONG_INT "cmpwi " + + #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ +@@ -125,7 +131,7 @@ do { \ + RSEQ_INJECT_ASM(1) \ + "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \ + "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ +- "stw %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ ++ RSEQ_STORE_INT(rseq_cs) "%%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + + #endif /* #ifdef __PPC64__ */ +@@ -136,7 +142,7 @@ do { \ + + #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ +- "lwz %%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \ ++ RSEQ_LOAD_INT(current_cpu_id) "%%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \ + "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \ + "bne- cr7, " __rseq_str(label) "\n\t" + +@@ -153,25 +159,25 @@ do { \ + * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7) + */ + #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \ +- LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ +- CMP_WORD "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \ ++ RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ ++ RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \ + "bne- cr7, " __rseq_str(label) "\n\t" + + #define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \ +- LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ +- CMP_WORD "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \ ++ RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ ++ RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \ + "beq- cr7, " __rseq_str(label) "\n\t" + + #define RSEQ_ASM_OP_STORE(value, var) \ +- STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" ++ RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" + + /* Load @var to r17 */ + #define RSEQ_ASM_OP_R_LOAD(var) \ +- LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" ++ RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" + + /* Store r17 to @var */ + #define RSEQ_ASM_OP_R_STORE(var) \ +- STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" ++ RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" + + /* Add @count to r17 */ + #define RSEQ_ASM_OP_R_ADD(count) \ +@@ -179,11 +185,11 @@ do { \ + + /* Load (r17 + voffp) to r17 */ + #define RSEQ_ASM_OP_R_LOADX(voffp) \ +- LOADX_WORD "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t" ++ RSEQ_LOADX_LONG "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t" + + /* TODO: implement a faster memcpy. */ + #define RSEQ_ASM_OP_R_MEMCPY() \ +- "cmpdi %%r19, 0\n\t" \ ++ RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \ + "beq 333f\n\t" \ + "addi %%r20, %%r20, -1\n\t" \ + "addi %%r21, %%r21, -1\n\t" \ +@@ -191,16 +197,16 @@ do { \ + "lbzu %%r18, 1(%%r20)\n\t" \ + "stbu %%r18, 1(%%r21)\n\t" \ + "addi %%r19, %%r19, -1\n\t" \ +- "cmpdi %%r19, 0\n\t" \ ++ RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" \ + + #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \ +- STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ ++ RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ + __rseq_str(post_commit_label) ":\n\t" + + #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \ +- STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \ ++ RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \ + __rseq_str(post_commit_label) ":\n\t" + + static inline __attribute__((always_inline)) +@@ -235,8 +241,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -248,23 +254,28 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } + + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -301,8 +312,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -316,16 +327,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -359,8 +375,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [count] "r" (count) +@@ -372,12 +388,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -419,8 +438,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -436,16 +455,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -489,8 +513,8 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -506,16 +530,21 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -560,8 +589,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -577,18 +606,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("1st expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -635,8 +670,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -653,16 +688,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -711,8 +751,8 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -729,23 +769,23 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } + +-#undef STORE_WORD +-#undef LOAD_WORD +-#undef LOADX_WORD +-#undef CMP_WORD +- + #endif /* !RSEQ_SKIP_FASTPATH */ +diff --git a/tools/testing/selftests/rseq/rseq-s390.h b/tools/testing/selftests/rseq/rseq-s390.h +index 8ef94ad1cbb45..4e6dc5f0cb429 100644 +--- a/tools/testing/selftests/rseq/rseq-s390.h ++++ b/tools/testing/selftests/rseq/rseq-s390.h +@@ -165,8 +165,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -178,16 +178,21 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -198,7 +203,7 @@ error2: + */ + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -233,8 +238,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -248,16 +253,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -288,8 +298,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [count] "r" (count) +@@ -301,12 +311,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -347,8 +360,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -364,16 +377,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -426,8 +444,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -443,18 +461,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("1st expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -534,8 +558,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + #endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [current_cpu_id] "m" (__rseq_abi.cpu_id), +- [rseq_cs] "m" (__rseq_abi.rseq_cs), ++ [current_cpu_id] "m" (rseq_get_abi()->cpu_id), ++ [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -555,16 +579,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +diff --git a/tools/testing/selftests/rseq/rseq-skip.h b/tools/testing/selftests/rseq/rseq-skip.h +index 72750b5905a96..7b53dac1fcdd9 100644 +--- a/tools/testing/selftests/rseq/rseq-skip.h ++++ b/tools/testing/selftests/rseq/rseq-skip.h +@@ -13,7 +13,7 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + return -1; + } +diff --git a/tools/testing/selftests/rseq/rseq-thread-pointer.h b/tools/testing/selftests/rseq/rseq-thread-pointer.h +new file mode 100644 +index 0000000000000..977c25d758b2a +--- /dev/null ++++ b/tools/testing/selftests/rseq/rseq-thread-pointer.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */ ++/* ++ * rseq-thread-pointer.h ++ * ++ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#ifndef _RSEQ_THREAD_POINTER ++#define _RSEQ_THREAD_POINTER ++ ++#if defined(__x86_64__) || defined(__i386__) ++#include "rseq-x86-thread-pointer.h" ++#elif defined(__PPC__) ++#include "rseq-ppc-thread-pointer.h" ++#else ++#include "rseq-generic-thread-pointer.h" ++#endif ++ ++#endif +diff --git a/tools/testing/selftests/rseq/rseq-x86-thread-pointer.h b/tools/testing/selftests/rseq/rseq-x86-thread-pointer.h +new file mode 100644 +index 0000000000000..d3133587d9968 +--- /dev/null ++++ b/tools/testing/selftests/rseq/rseq-x86-thread-pointer.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */ ++/* ++ * rseq-x86-thread-pointer.h ++ * ++ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> ++ */ ++ ++#ifndef _RSEQ_X86_THREAD_POINTER ++#define _RSEQ_X86_THREAD_POINTER ++ ++#include <features.h> ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#if __GNUC_PREREQ (11, 1) ++static inline void *rseq_thread_pointer(void) ++{ ++ return __builtin_thread_pointer(); ++} ++#else ++static inline void *rseq_thread_pointer(void) ++{ ++ void *__result; ++ ++# ifdef __x86_64__ ++ __asm__ ("mov %%fs:0, %0" : "=r" (__result)); ++# else ++ __asm__ ("mov %%gs:0, %0" : "=r" (__result)); ++# endif ++ return __result; ++} ++#endif /* !GCC 11 */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/tools/testing/selftests/rseq/rseq-x86.h b/tools/testing/selftests/rseq/rseq-x86.h +index 640411518e466..bd01dc41ca130 100644 +--- a/tools/testing/selftests/rseq/rseq-x86.h ++++ b/tools/testing/selftests/rseq/rseq-x86.h +@@ -28,6 +28,8 @@ + + #ifdef __x86_64__ + ++#define RSEQ_ASM_TP_SEGMENT %%fs ++ + #define rseq_smp_mb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc") + #define rseq_smp_rmb() rseq_barrier() +@@ -123,14 +125,14 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + #endif +@@ -141,7 +143,7 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -152,16 +154,21 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -172,7 +179,7 @@ error2: + */ + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -184,15 +191,15 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "movq %[v], %%rbx\n\t" + "cmpq %%rbx, %[expectnot]\n\t" + "je %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "movq %[v], %%rbx\n\t" + "cmpq %%rbx, %[expectnot]\n\t" + "je %l[error2]\n\t" +@@ -207,7 +214,7 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -220,16 +227,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -245,11 +257,11 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + #endif + /* final store */ + "addq %[count], %[v]\n\t" +@@ -258,7 +270,7 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [count] "er" (count) +@@ -269,12 +281,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -286,7 +301,7 @@ error1: + * *pval += inc; + */ + static inline __attribute__((always_inline)) +-int rseq_offset_deref_addv(intptr_t *ptr, off_t off, intptr_t inc, int cpu) ++int rseq_offset_deref_addv(intptr_t *ptr, long off, intptr_t inc, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -296,11 +311,11 @@ int rseq_offset_deref_addv(intptr_t *ptr, off_t off, intptr_t inc, int cpu) + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + #endif + /* get p+v */ + "movq %[ptr], %%rbx\n\t" +@@ -314,7 +329,7 @@ int rseq_offset_deref_addv(intptr_t *ptr, off_t off, intptr_t inc, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [ptr] "m" (*ptr), + [off] "er" (off), +@@ -351,14 +366,14 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + #endif +@@ -372,7 +387,7 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -387,16 +402,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -426,8 +446,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" +@@ -436,7 +456,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + "cmpq %[v2], %[expect2]\n\t" +@@ -449,7 +469,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -464,18 +484,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("1st expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -500,14 +526,14 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + "movq %[dst], %[rseq_scratch1]\n\t" + "movq %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f) + "cmpq %[v], %[expect]\n\t" + "jnz 7f\n\t" + #endif +@@ -555,7 +581,7 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + #endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), +@@ -574,16 +600,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -600,7 +631,9 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + + #endif /* !RSEQ_SKIP_FASTPATH */ + +-#elif __i386__ ++#elif defined(__i386__) ++ ++#define RSEQ_ASM_TP_SEGMENT %%gs + + #define rseq_smp_mb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc") +@@ -701,14 +734,14 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + #endif +@@ -719,7 +752,7 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) +@@ -730,16 +763,21 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -750,7 +788,7 @@ error2: + */ + static inline __attribute__((always_inline)) + int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, +- off_t voffp, intptr_t *load, int cpu) ++ long voffp, intptr_t *load, int cpu) + { + RSEQ_INJECT_C(9) + +@@ -762,15 +800,15 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "movl %[v], %%ebx\n\t" + "cmpl %%ebx, %[expectnot]\n\t" + "je %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "movl %[v], %%ebx\n\t" + "cmpl %%ebx, %[expectnot]\n\t" + "je %l[error2]\n\t" +@@ -785,7 +823,7 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), +@@ -798,16 +836,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -823,11 +866,11 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + #endif + /* final store */ + "addl %[count], %[v]\n\t" +@@ -836,7 +879,7 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [count] "ir" (count) +@@ -847,12 +890,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu) + , error1 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + #endif + } +@@ -872,14 +918,14 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + #endif +@@ -894,7 +940,7 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* try store input */ + [v2] "m" (*v2), + [newv2] "m" (newv2), +@@ -909,16 +955,21 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -938,15 +989,15 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %[v], %%eax\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "movl %[expect], %%eax\n\t" + "cmpl %[v], %%eax\n\t" + "jnz %l[error2]\n\t" +@@ -962,7 +1013,7 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), +@@ -977,16 +1028,21 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + +@@ -1008,8 +1064,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3]) + #endif + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" +@@ -1018,7 +1074,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1]) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + "cmpl %[expect2], %[v2]\n\t" +@@ -1032,7 +1088,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), +@@ -1047,18 +1103,24 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + , error1, error2, error3 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("1st expected value comparison failed"); + error3: ++ rseq_after_asm_goto(); + rseq_bug("2nd expected value comparison failed"); + #endif + } +@@ -1084,15 +1146,15 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + "movl %[dst], %[rseq_scratch1]\n\t" + "movl %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 7f\n\t" +@@ -1142,7 +1204,7 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + #endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [expect] "m" (expect), +@@ -1161,16 +1223,21 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +@@ -1196,15 +1263,15 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + "movl %[dst], %[rseq_scratch1]\n\t" + "movl %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ +- RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi])) +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f) ++ RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset])) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) + #ifdef RSEQ_COMPARE_TWICE +- RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f) ++ RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 7f\n\t" +@@ -1255,7 +1322,7 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + #endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), +- [rseq_abi] "r" (&__rseq_abi), ++ [rseq_offset] "r" (rseq_offset), + /* final store input */ + [v] "m" (*v), + [expect] "m" (expect), +@@ -1274,16 +1341,21 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + , error1, error2 + #endif + ); ++ rseq_after_asm_goto(); + return 0; + abort: ++ rseq_after_asm_goto(); + RSEQ_INJECT_FAILED + return -1; + cmpfail: ++ rseq_after_asm_goto(); + return 1; + #ifdef RSEQ_COMPARE_TWICE + error1: ++ rseq_after_asm_goto(); + rseq_bug("cpu_id comparison failed"); + error2: ++ rseq_after_asm_goto(); + rseq_bug("expected value comparison failed"); + #endif + } +diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/rseq/rseq.c +index 7159eb777fd34..986b9458efb26 100644 +--- a/tools/testing/selftests/rseq/rseq.c ++++ b/tools/testing/selftests/rseq/rseq.c +@@ -26,131 +26,124 @@ + #include <assert.h> + #include <signal.h> + #include <limits.h> ++#include <dlfcn.h> ++#include <stddef.h> + ++#include "../kselftest.h" + #include "rseq.h" + +-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) ++static const ptrdiff_t *libc_rseq_offset_p; ++static const unsigned int *libc_rseq_size_p; ++static const unsigned int *libc_rseq_flags_p; + +-__thread volatile struct rseq __rseq_abi = { +- .cpu_id = RSEQ_CPU_ID_UNINITIALIZED, +-}; ++/* Offset from the thread pointer to the rseq area. */ ++ptrdiff_t rseq_offset; + +-/* +- * Shared with other libraries. This library may take rseq ownership if it is +- * still 0 when executing the library constructor. Set to 1 by library +- * constructor when handling rseq. Set to 0 in destructor if handling rseq. +- */ +-int __rseq_handled; ++/* Size of the registered rseq area. 0 if the registration was ++ unsuccessful. */ ++unsigned int rseq_size = -1U; ++ ++/* Flags used during rseq registration. */ ++unsigned int rseq_flags; + +-/* Whether this library have ownership of rseq registration. */ + static int rseq_ownership; + +-static __thread volatile uint32_t __rseq_refcount; ++static ++__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = { ++ .cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED, ++}; + +-static void signal_off_save(sigset_t *oldset) ++static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len, ++ int flags, uint32_t sig) + { +- sigset_t set; +- int ret; +- +- sigfillset(&set); +- ret = pthread_sigmask(SIG_BLOCK, &set, oldset); +- if (ret) +- abort(); ++ return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); + } + +-static void signal_restore(sigset_t oldset) ++int rseq_available(void) + { +- int ret; ++ int rc; + +- ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL); +- if (ret) ++ rc = sys_rseq(NULL, 0, 0, 0); ++ if (rc != -1) + abort(); +-} +- +-static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, +- int flags, uint32_t sig) +-{ +- return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); ++ switch (errno) { ++ case ENOSYS: ++ return 0; ++ case EINVAL: ++ return 1; ++ default: ++ abort(); ++ } + } + + int rseq_register_current_thread(void) + { +- int rc, ret = 0; +- sigset_t oldset; ++ int rc; + +- if (!rseq_ownership) ++ if (!rseq_ownership) { ++ /* Treat libc's ownership as a successful registration. */ + return 0; +- signal_off_save(&oldset); +- if (__rseq_refcount == UINT_MAX) { +- ret = -1; +- goto end; +- } +- if (__rseq_refcount++) +- goto end; +- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG); +- if (!rc) { +- assert(rseq_current_cpu_raw() >= 0); +- goto end; + } +- if (errno != EBUSY) +- __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED; +- ret = -1; +- __rseq_refcount--; +-end: +- signal_restore(oldset); +- return ret; ++ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG); ++ if (rc) ++ return -1; ++ assert(rseq_current_cpu_raw() >= 0); ++ return 0; + } + + int rseq_unregister_current_thread(void) + { +- int rc, ret = 0; +- sigset_t oldset; ++ int rc; + +- if (!rseq_ownership) ++ if (!rseq_ownership) { ++ /* Treat libc's ownership as a successful unregistration. */ + return 0; +- signal_off_save(&oldset); +- if (!__rseq_refcount) { +- ret = -1; +- goto end; + } +- if (--__rseq_refcount) +- goto end; +- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), +- RSEQ_FLAG_UNREGISTER, RSEQ_SIG); +- if (!rc) +- goto end; +- __rseq_refcount = 1; +- ret = -1; +-end: +- signal_restore(oldset); +- return ret; ++ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG); ++ if (rc) ++ return -1; ++ return 0; + } + +-int32_t rseq_fallback_current_cpu(void) ++static __attribute__((constructor)) ++void rseq_init(void) + { +- int32_t cpu; +- +- cpu = sched_getcpu(); +- if (cpu < 0) { +- perror("sched_getcpu()"); +- abort(); ++ libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset"); ++ libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size"); ++ libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags"); ++ if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p) { ++ /* rseq registration owned by glibc */ ++ rseq_offset = *libc_rseq_offset_p; ++ rseq_size = *libc_rseq_size_p; ++ rseq_flags = *libc_rseq_flags_p; ++ return; + } +- return cpu; +-} +- +-void __attribute__((constructor)) rseq_init(void) +-{ +- /* Check whether rseq is handled by another library. */ +- if (__rseq_handled) ++ if (!rseq_available()) + return; +- __rseq_handled = 1; + rseq_ownership = 1; ++ rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer(); ++ rseq_size = sizeof(struct rseq_abi); ++ rseq_flags = 0; + } + +-void __attribute__((destructor)) rseq_fini(void) ++static __attribute__((destructor)) ++void rseq_exit(void) + { + if (!rseq_ownership) + return; +- __rseq_handled = 0; ++ rseq_offset = 0; ++ rseq_size = -1U; + rseq_ownership = 0; + } ++ ++int32_t rseq_fallback_current_cpu(void) ++{ ++ int32_t cpu; ++ ++ cpu = sched_getcpu(); ++ if (cpu < 0) { ++ perror("sched_getcpu()"); ++ abort(); ++ } ++ return cpu; ++} +diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/rseq/rseq.h +index 3f63eb362b92f..9d850b290c2e6 100644 +--- a/tools/testing/selftests/rseq/rseq.h ++++ b/tools/testing/selftests/rseq/rseq.h +@@ -16,7 +16,9 @@ + #include <errno.h> + #include <stdio.h> + #include <stdlib.h> +-#include <linux/rseq.h> ++#include <stddef.h> ++#include "rseq-abi.h" ++#include "compiler.h" + + /* + * Empty code injection macros, override when testing. +@@ -43,8 +45,20 @@ + #define RSEQ_INJECT_FAILED + #endif + +-extern __thread volatile struct rseq __rseq_abi; +-extern int __rseq_handled; ++#include "rseq-thread-pointer.h" ++ ++/* Offset from the thread pointer to the rseq area. */ ++extern ptrdiff_t rseq_offset; ++/* Size of the registered rseq area. 0 if the registration was ++ unsuccessful. */ ++extern unsigned int rseq_size; ++/* Flags used during rseq registration. */ ++extern unsigned int rseq_flags; ++ ++static inline struct rseq_abi *rseq_get_abi(void) ++{ ++ return (struct rseq_abi *) ((uintptr_t) rseq_thread_pointer() + rseq_offset); ++} + + #define rseq_likely(x) __builtin_expect(!!(x), 1) + #define rseq_unlikely(x) __builtin_expect(!!(x), 0) +@@ -108,7 +122,7 @@ int32_t rseq_fallback_current_cpu(void); + */ + static inline int32_t rseq_current_cpu_raw(void) + { +- return RSEQ_ACCESS_ONCE(__rseq_abi.cpu_id); ++ return RSEQ_ACCESS_ONCE(rseq_get_abi()->cpu_id); + } + + /* +@@ -124,7 +138,7 @@ static inline int32_t rseq_current_cpu_raw(void) + */ + static inline uint32_t rseq_cpu_start(void) + { +- return RSEQ_ACCESS_ONCE(__rseq_abi.cpu_id_start); ++ return RSEQ_ACCESS_ONCE(rseq_get_abi()->cpu_id_start); + } + + static inline uint32_t rseq_current_cpu(void) +@@ -139,11 +153,7 @@ static inline uint32_t rseq_current_cpu(void) + + static inline void rseq_clear_rseq_cs(void) + { +-#ifdef __LP64__ +- __rseq_abi.rseq_cs.ptr = 0; +-#else +- __rseq_abi.rseq_cs.ptr.ptr32 = 0; +-#endif ++ RSEQ_WRITE_ONCE(rseq_get_abi()->rseq_cs.arch.ptr, 0); + } + + /* |