]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Feb 2026 12:20:45 +0000 (13:20 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Feb 2026 12:20:45 +0000 (13:20 +0100)
added patches:
mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch
net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch
netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch
netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch
nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch
selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch
spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch
vsock-test-verify-socket-options-after-setting-them.patch

queue-6.6/mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch [new file with mode: 0644]
queue-6.6/net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch [new file with mode: 0644]
queue-6.6/netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch [new file with mode: 0644]
queue-6.6/netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch [new file with mode: 0644]
queue-6.6/nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch [new file with mode: 0644]
queue-6.6/selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch [new file with mode: 0644]
queue-6.6/vsock-test-verify-socket-options-after-setting-them.patch [new file with mode: 0644]

diff --git a/queue-6.6/mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch b/queue-6.6/mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch
new file mode 100644 (file)
index 0000000..7d696a6
--- /dev/null
@@ -0,0 +1,79 @@
+From e2a9eeb69f7d4ca4cf4c70463af77664fdb6ab1d Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Sat, 24 Jan 2026 11:59:18 +0100
+Subject: mptcp: fix race in mptcp_pm_nl_flush_addrs_doit()
+
+From: Eric Dumazet <edumazet@google.com>
+
+commit e2a9eeb69f7d4ca4cf4c70463af77664fdb6ab1d upstream.
+
+syzbot and Eulgyu Kim reported crashes in mptcp_pm_nl_get_local_id()
+and/or mptcp_pm_nl_is_backup()
+
+Root cause is list_splice_init() in mptcp_pm_nl_flush_addrs_doit()
+which is not RCU ready.
+
+list_splice_init_rcu() can not be called here while holding pernet->lock
+spinlock.
+
+Many thanks to Eulgyu Kim for providing a repro and testing our patches.
+
+Fixes: 141694df6573 ("mptcp: remove address when netlink flushes addrs")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: syzbot+5498a510ff9de39d37da@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/6970a46d.a00a0220.3ad28e.5cf0.GAE@google.com/T/
+Reported-by: Eulgyu Kim <eulgyukim@snu.ac.kr>
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/611
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260124-net-mptcp-race_nl_flush_addrs-v3-1-b2dc1b613e9d@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Conflicts because the code has been moved from pm_netlink.c to
+  pm_kernel.c later on in commit 8617e85e04bd ("mptcp: pm: split
+  in-kernel PM specific code"). The same modifications can be applied
+  in pm_netlink.c with one exception, because 'pernet->local_addr_list'
+  has been renamed to 'pernet->endp_list' in commit 35e71e43a56d
+  ("mptcp: pm: in-kernel: rename 'local_addr_list' to 'endp_list'"). The
+  previous name is then still being used in this version.
+  Also, another conflict is caused by commit 7bcf4d8022f9 ("mptcp: pm:
+  rename helpers linked to 'flush'") which is not in this version:
+  mptcp_nl_remove_addrs_list() has been renamed to
+  mptcp_nl_flush_addrs_list(). The previous name has then been kept. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c |   16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -1859,16 +1859,26 @@ static void __reset_counters(struct pm_n
+ static int mptcp_nl_cmd_flush_addrs(struct sk_buff *skb, struct genl_info *info)
+ {
+       struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
+-      LIST_HEAD(free_list);
++      struct list_head free_list;
+       spin_lock_bh(&pernet->lock);
+-      list_splice_init(&pernet->local_addr_list, &free_list);
++      free_list = pernet->local_addr_list;
++      INIT_LIST_HEAD_RCU(&pernet->local_addr_list);
+       __reset_counters(pernet);
+       pernet->next_id = 1;
+       bitmap_zero(pernet->id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
+       spin_unlock_bh(&pernet->lock);
+-      mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
++
++      if (free_list.next == &pernet->local_addr_list)
++              return 0;
++
+       synchronize_rcu();
++
++      /* Adjust the pointers to free_list instead of pernet->local_addr_list */
++      free_list.prev->next = &free_list;
++      free_list.next->prev = &free_list;
++
++      mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
+       __flush_addrs(&free_list);
+       return 0;
+ }
diff --git a/queue-6.6/net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch b/queue-6.6/net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch
new file mode 100644 (file)
index 0000000..1c3895f
--- /dev/null
@@ -0,0 +1,50 @@
+From adcbadfd8e05d3558c9cfaa783f17c645181165f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+Date: Thu, 29 Jan 2026 09:22:27 +0100
+Subject: net: sfp: Fix quirk for Ubiquiti U-Fiber Instant SFP module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marek BehĂșn <kabel@kernel.org>
+
+commit adcbadfd8e05d3558c9cfaa783f17c645181165f upstream.
+
+Commit fd580c9830316eda ("net: sfp: augment SFP parsing with
+phy_interface_t bitmap") did not add augumentation for the interface
+bitmap in the quirk for Ubiquiti U-Fiber Instant.
+
+The subsequent commit f81fa96d8a6c7a77 ("net: phylink: use
+phy_interface_t bitmaps for optical modules") then changed phylink code
+for selection of SFP interface: instead of using link mode bitmap, the
+interface bitmap is used, and the fastest interface mode supported by
+both SFP module and MAC is chosen.
+
+Since the interface bitmap contains also modes faster than 1000base-x,
+this caused a regression wherein this module stopped working
+out-of-the-box.
+
+Fix this.
+
+Fixes: fd580c9830316eda ("net: sfp: augment SFP parsing with phy_interface_t bitmap")
+Signed-off-by: Marek BehĂșn <kabel@kernel.org>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/20260129082227.17443-1-kabel@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/phy/sfp.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -431,6 +431,8 @@ static void sfp_quirk_ubnt_uf_instant(co
+        */
+       linkmode_zero(modes);
+       linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes);
++      phy_interface_zero(interfaces);
++      __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+ }
+ #define SFP_QUIRK(_v, _p, _m, _f) \
diff --git a/queue-6.6/netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch b/queue-6.6/netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch
new file mode 100644 (file)
index 0000000..cde42f2
--- /dev/null
@@ -0,0 +1,174 @@
+From 69e687cea79fc99a17dfb0116c8644b9391b915e Mon Sep 17 00:00:00 2001
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed, 18 Sep 2024 14:19:45 +0200
+Subject: netfilter: nf_tables: missing objects with no memcg accounting
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 69e687cea79fc99a17dfb0116c8644b9391b915e upstream.
+
+Several ruleset objects are still not using GFP_KERNEL_ACCOUNT for
+memory accounting, update them. This includes:
+
+- catchall elements
+- compat match large info area
+- log prefix
+- meta secctx
+- numgen counters
+- pipapo set backend datastructure
+- tunnel private objects
+
+Fixes: 33758c891479 ("memcg: enable accounting for nft objects")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+[ Adjust context ]
+Signed-off-by: Bin Lan <lanbincn@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c  |    2 +-
+ net/netfilter/nft_compat.c     |    6 +++---
+ net/netfilter/nft_log.c        |    2 +-
+ net/netfilter/nft_meta.c       |    2 +-
+ net/netfilter/nft_numgen.c     |    2 +-
+ net/netfilter/nft_set_pipapo.c |   10 +++++-----
+ net/netfilter/nft_tunnel.c     |    5 +++--
+ 7 files changed, 15 insertions(+), 14 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -6615,7 +6615,7 @@ static int nft_setelem_catchall_insert(c
+               }
+       }
+-      catchall = kmalloc(sizeof(*catchall), GFP_KERNEL);
++      catchall = kmalloc(sizeof(*catchall), GFP_KERNEL_ACCOUNT);
+       if (!catchall)
+               return -ENOMEM;
+--- a/net/netfilter/nft_compat.c
++++ b/net/netfilter/nft_compat.c
+@@ -535,7 +535,7 @@ nft_match_large_init(const struct nft_ct
+       struct xt_match *m = expr->ops->data;
+       int ret;
+-      priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL);
++      priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL_ACCOUNT);
+       if (!priv->info)
+               return -ENOMEM;
+@@ -808,7 +808,7 @@ nft_match_select_ops(const struct nft_ct
+               goto err;
+       }
+-      ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL);
++      ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL_ACCOUNT);
+       if (!ops) {
+               err = -ENOMEM;
+               goto err;
+@@ -898,7 +898,7 @@ nft_target_select_ops(const struct nft_c
+               goto err;
+       }
+-      ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL);
++      ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL_ACCOUNT);
+       if (!ops) {
+               err = -ENOMEM;
+               goto err;
+--- a/net/netfilter/nft_log.c
++++ b/net/netfilter/nft_log.c
+@@ -163,7 +163,7 @@ static int nft_log_init(const struct nft
+       nla = tb[NFTA_LOG_PREFIX];
+       if (nla != NULL) {
+-              priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
++              priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL_ACCOUNT);
+               if (priv->prefix == NULL)
+                       return -ENOMEM;
+               nla_strscpy(priv->prefix, nla, nla_len(nla) + 1);
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -952,7 +952,7 @@ static int nft_secmark_obj_init(const st
+       if (tb[NFTA_SECMARK_CTX] == NULL)
+               return -EINVAL;
+-      priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL);
++      priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL_ACCOUNT);
+       if (!priv->ctx)
+               return -ENOMEM;
+--- a/net/netfilter/nft_numgen.c
++++ b/net/netfilter/nft_numgen.c
+@@ -66,7 +66,7 @@ static int nft_ng_inc_init(const struct
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+-      priv->counter = kmalloc(sizeof(*priv->counter), GFP_KERNEL);
++      priv->counter = kmalloc(sizeof(*priv->counter), GFP_KERNEL_ACCOUNT);
+       if (!priv->counter)
+               return -ENOMEM;
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -874,7 +874,7 @@ static void pipapo_lt_bits_adjust(struct
+               return;
+       }
+-      new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL);
++      new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL_ACCOUNT);
+       if (!new_lt)
+               return;
+@@ -1150,7 +1150,7 @@ static int pipapo_realloc_scratch(struct
+               scratch = kzalloc_node(struct_size(scratch, map,
+                                                  bsize_max * 2) +
+                                      NFT_PIPAPO_ALIGN_HEADROOM,
+-                                     GFP_KERNEL, cpu_to_node(i));
++                                     GFP_KERNEL_ACCOUNT, cpu_to_node(i));
+               if (!scratch) {
+                       /* On failure, there's no need to undo previous
+                        * allocations: this means that some scratch maps have
+@@ -1323,7 +1323,7 @@ static struct nft_pipapo_match *pipapo_c
+       struct nft_pipapo_match *new;
+       int i;
+-      new = kmalloc(struct_size(new, f, old->field_count), GFP_KERNEL);
++      new = kmalloc(struct_size(new, f, old->field_count), GFP_KERNEL_ACCOUNT);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+@@ -1353,7 +1353,7 @@ static struct nft_pipapo_match *pipapo_c
+               new_lt = kvzalloc(src->groups * NFT_PIPAPO_BUCKETS(src->bb) *
+                                 src->bsize * sizeof(*dst->lt) +
+                                 NFT_PIPAPO_ALIGN_HEADROOM,
+-                                GFP_KERNEL);
++                                GFP_KERNEL_ACCOUNT);
+               if (!new_lt)
+                       goto out_lt;
+@@ -1367,7 +1367,7 @@ static struct nft_pipapo_match *pipapo_c
+               if (src->rules > (INT_MAX / sizeof(*src->mt)))
+                       goto out_mt;
+-              dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL);
++              dst->mt = kvmalloc(src->rules * sizeof(*src->mt), GFP_KERNEL_ACCOUNT);
+               if (!dst->mt)
+                       goto out_mt;
+--- a/net/netfilter/nft_tunnel.c
++++ b/net/netfilter/nft_tunnel.c
+@@ -503,13 +503,14 @@ static int nft_tunnel_obj_init(const str
+                       return err;
+       }
+-      md = metadata_dst_alloc(priv->opts.len, METADATA_IP_TUNNEL, GFP_KERNEL);
++      md = metadata_dst_alloc(priv->opts.len, METADATA_IP_TUNNEL,
++                              GFP_KERNEL_ACCOUNT);
+       if (!md)
+               return -ENOMEM;
+       memcpy(&md->u.tun_info, &info, sizeof(info));
+ #ifdef CONFIG_DST_CACHE
+-      err = dst_cache_init(&md->u.tun_info.dst_cache, GFP_KERNEL);
++      err = dst_cache_init(&md->u.tun_info.dst_cache, GFP_KERNEL_ACCOUNT);
+       if (err < 0) {
+               metadata_dst_free(md);
+               return err;
diff --git a/queue-6.6/netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch b/queue-6.6/netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch
new file mode 100644 (file)
index 0000000..07abd49
--- /dev/null
@@ -0,0 +1,153 @@
+From 4c5c6aa9967dbe55bd017bb509885928d0f31206 Mon Sep 17 00:00:00 2001
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Tue, 22 Apr 2025 21:52:43 +0200
+Subject: netfilter: nft_set_pipapo: prevent overflow in lookup table allocation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 4c5c6aa9967dbe55bd017bb509885928d0f31206 upstream.
+
+When calculating the lookup table size, ensure the following
+multiplication does not overflow:
+
+- desc->field_len[] maximum value is U8_MAX multiplied by
+  NFT_PIPAPO_GROUPS_PER_BYTE(f) that can be 2, worst case.
+- NFT_PIPAPO_BUCKETS(f->bb) is 2^8, worst case.
+- sizeof(unsigned long), from sizeof(*f->lt), lt in
+  struct nft_pipapo_field.
+
+Then, use check_mul_overflow() to multiply by bucket size and then use
+check_add_overflow() to the alignment for avx2 (if needed). Finally, add
+lt_size_check_overflow() helper and use it to consolidate this.
+
+While at it, replace leftover allocation using the GFP_KERNEL to
+GFP_KERNEL_ACCOUNT for consistency, in pipapo_resize().
+
+Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+[ Adjust context ]
+Signed-off-by: Bin Lan <lanbincn@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nft_set_pipapo.c |   58 +++++++++++++++++++++++++++++++----------
+ 1 file changed, 44 insertions(+), 14 deletions(-)
+
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -610,6 +610,30 @@ static void *nft_pipapo_get(const struct
+                        nft_genmask_cur(net), get_jiffies_64());
+ }
++
++/**
++ * lt_calculate_size() - Get storage size for lookup table with overflow check
++ * @groups:   Amount of bit groups
++ * @bb:               Number of bits grouped together in lookup table buckets
++ * @bsize:    Size of each bucket in lookup table, in longs
++ *
++ * Return: allocation size including alignment overhead, negative on overflow
++ */
++static ssize_t lt_calculate_size(unsigned int groups, unsigned int bb,
++                               unsigned int bsize)
++{
++      ssize_t ret = groups * NFT_PIPAPO_BUCKETS(bb) * sizeof(long);
++
++      if (check_mul_overflow(ret, bsize, &ret))
++              return -1;
++      if (check_add_overflow(ret, NFT_PIPAPO_ALIGN_HEADROOM, &ret))
++              return -1;
++      if (ret > INT_MAX)
++              return -1;
++
++      return ret;
++}
++
+ /**
+  * pipapo_resize() - Resize lookup or mapping table, or both
+  * @f:                Field containing lookup and mapping tables
+@@ -628,6 +652,7 @@ static int pipapo_resize(struct nft_pipa
+       union nft_pipapo_map_bucket *new_mt, *old_mt = f->mt;
+       size_t new_bucket_size, copy;
+       int group, bucket;
++      ssize_t lt_size;
+       new_bucket_size = DIV_ROUND_UP(rules, BITS_PER_LONG);
+ #ifdef NFT_PIPAPO_ALIGN
+@@ -643,10 +668,11 @@ static int pipapo_resize(struct nft_pipa
+       else
+               copy = new_bucket_size;
+-      new_lt = kvzalloc(f->groups * NFT_PIPAPO_BUCKETS(f->bb) *
+-                        new_bucket_size * sizeof(*new_lt) +
+-                        NFT_PIPAPO_ALIGN_HEADROOM,
+-                        GFP_KERNEL);
++      lt_size = lt_calculate_size(f->groups, f->bb, new_bucket_size);
++      if (lt_size < 0)
++              return -ENOMEM;
++
++      new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT);
+       if (!new_lt)
+               return -ENOMEM;
+@@ -845,7 +871,7 @@ static void pipapo_lt_bits_adjust(struct
+ {
+       unsigned long *new_lt;
+       int groups, bb;
+-      size_t lt_size;
++      ssize_t lt_size;
+       lt_size = f->groups * NFT_PIPAPO_BUCKETS(f->bb) * f->bsize *
+                 sizeof(*f->lt);
+@@ -855,15 +881,17 @@ static void pipapo_lt_bits_adjust(struct
+               groups = f->groups * 2;
+               bb = NFT_PIPAPO_GROUP_BITS_LARGE_SET;
+-              lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
+-                        sizeof(*f->lt);
++              lt_size = lt_calculate_size(groups, bb, f->bsize);
++              if (lt_size < 0)
++                      return;
+       } else if (f->bb == NFT_PIPAPO_GROUP_BITS_LARGE_SET &&
+                  lt_size < NFT_PIPAPO_LT_SIZE_LOW) {
+               groups = f->groups / 2;
+               bb = NFT_PIPAPO_GROUP_BITS_SMALL_SET;
+-              lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize *
+-                        sizeof(*f->lt);
++              lt_size = lt_calculate_size(groups, bb, f->bsize);
++              if (lt_size < 0)
++                      return;
+               /* Don't increase group width if the resulting lookup table size
+                * would exceed the upper size threshold for a "small" set.
+@@ -874,7 +902,7 @@ static void pipapo_lt_bits_adjust(struct
+               return;
+       }
+-      new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL_ACCOUNT);
++      new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT);
+       if (!new_lt)
+               return;
+@@ -1347,13 +1375,15 @@ static struct nft_pipapo_match *pipapo_c
+       for (i = 0; i < old->field_count; i++) {
+               unsigned long *new_lt;
++              ssize_t lt_size;
+               memcpy(dst, src, offsetof(struct nft_pipapo_field, lt));
+-              new_lt = kvzalloc(src->groups * NFT_PIPAPO_BUCKETS(src->bb) *
+-                                src->bsize * sizeof(*dst->lt) +
+-                                NFT_PIPAPO_ALIGN_HEADROOM,
+-                                GFP_KERNEL_ACCOUNT);
++              lt_size = lt_calculate_size(src->groups, src->bb, src->bsize);
++              if (lt_size < 0)
++                      goto out_lt;
++
++              new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT);
+               if (!new_lt)
+                       goto out_lt;
diff --git a/queue-6.6/nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch b/queue-6.6/nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch
new file mode 100644 (file)
index 0000000..959b386
--- /dev/null
@@ -0,0 +1,92 @@
+From 930b64ca0c511521f0abdd1d57ce52b2a6e3476b Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Thu, 6 Feb 2025 13:12:13 -0500
+Subject: nfsd: don't ignore the return code of svc_proc_register()
+
+From: Jeff Layton <jlayton@kernel.org>
+
+commit 930b64ca0c511521f0abdd1d57ce52b2a6e3476b upstream.
+
+Currently, nfsd_proc_stat_init() ignores the return value of
+svc_proc_register(). If the procfile creation fails, then the kernel
+will WARN when it tries to remove the entry later.
+
+Fix nfsd_proc_stat_init() to return the same type of pointer as
+svc_proc_register(), and fix up nfsd_net_init() to check that and fail
+the nfsd_net construction if it occurs.
+
+svc_proc_register() can fail if the dentry can't be allocated, or if an
+identical dentry already exists. The second case is pretty unlikely in
+the nfsd_net construction codepath, so if this happens, return -ENOMEM.
+
+Reported-by: syzbot+e34ad04f27991521104c@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/linux-nfs/67a47501.050a0220.19061f.05f9.GAE@google.com/
+Cc: stable@vger.kernel.org # v6.9
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+[ Update the cleanup path to use nfsd_stat_counters_destroy. This ensures
+ the teardown logic is correctly paired with nfsd_stat_counters_init, as
+ required by the current NFSD implementation.]
+Signed-off-by: Jianqiang kang <jianqkang@sina.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfsctl.c |    9 ++++++++-
+ fs/nfsd/stats.c  |    4 ++--
+ fs/nfsd/stats.h  |    2 +-
+ 3 files changed, 11 insertions(+), 4 deletions(-)
+
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -1526,17 +1526,24 @@ static __net_init int nfsd_net_init(stru
+       retval = nfsd_stat_counters_init(nn);
+       if (retval)
+               goto out_repcache_error;
++
+       memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
+       nn->nfsd_svcstats.program = &nfsd_program;
++      if (!nfsd_proc_stat_init(net)) {
++              retval = -ENOMEM;
++              goto out_proc_error;
++      }
++
+       nn->nfsd_versions = NULL;
+       nn->nfsd4_minorversions = NULL;
+       nfsd4_init_leases_net(nn);
+       get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
+       seqlock_init(&nn->writeverf_lock);
+-      nfsd_proc_stat_init(net);
+       return 0;
++out_proc_error:
++      nfsd_stat_counters_destroy(nn);
+ out_repcache_error:
+       nfsd_idmap_shutdown(net);
+ out_idmap_error:
+--- a/fs/nfsd/stats.c
++++ b/fs/nfsd/stats.c
+@@ -115,11 +115,11 @@ void nfsd_stat_counters_destroy(struct n
+       nfsd_percpu_counters_destroy(nn->counter, NFSD_STATS_COUNTERS_NUM);
+ }
+-void nfsd_proc_stat_init(struct net *net)
++struct proc_dir_entry *nfsd_proc_stat_init(struct net *net)
+ {
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+-      svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
++      return svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
+ }
+ void nfsd_proc_stat_shutdown(struct net *net)
+--- a/fs/nfsd/stats.h
++++ b/fs/nfsd/stats.h
+@@ -15,7 +15,7 @@ void nfsd_percpu_counters_reset(struct p
+ void nfsd_percpu_counters_destroy(struct percpu_counter *counters, int num);
+ int nfsd_stat_counters_init(struct nfsd_net *nn);
+ void nfsd_stat_counters_destroy(struct nfsd_net *nn);
+-void nfsd_proc_stat_init(struct net *net);
++struct proc_dir_entry *nfsd_proc_stat_init(struct net *net);
+ void nfsd_proc_stat_shutdown(struct net *net);
+ static inline void nfsd_stats_rc_hits_inc(struct nfsd_net *nn)
diff --git a/queue-6.6/selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch b/queue-6.6/selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch
new file mode 100644 (file)
index 0000000..132640b
--- /dev/null
@@ -0,0 +1,84 @@
+From 29f4801e9c8dfd12bdcb33b61a6ac479c7162bd7 Mon Sep 17 00:00:00 2001
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+Date: Fri, 5 Dec 2025 19:55:15 +0100
+Subject: selftests: mptcp: pm: ensure unknown flags are ignored
+
+From: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+
+commit 29f4801e9c8dfd12bdcb33b61a6ac479c7162bd7 upstream.
+
+This validates the previous commit: the userspace can set unknown flags
+-- the 7th bit is currently unused -- without errors, but only the
+supported ones are printed in the endpoints dumps.
+
+The 'Fixes' tag here below is the same as the one from the previous
+commit: this patch here is not fixing anything wrong in the selftests,
+but it validates the previous fix for an issue introduced by this commit
+ID.
+
+Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-2-9e4781a6c1b8@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Conflicts in pm_netlink.sh, because some refactoring have been done
+  later on: commit 0d16ed0c2e74 ("selftests: mptcp: add
+  {get,format}_endpoint(s) helpers") and commit c99d57d0007a
+  ("selftests: mptcp: use pm_nl endpoint ops") are not in this version.
+  The same operation can still be done at the same place, without using
+  the new helpers. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/net/mptcp/pm_netlink.sh |    4 ++++
+ tools/testing/selftests/net/mptcp/pm_nl_ctl.c   |   11 +++++++++++
+ 2 files changed, 15 insertions(+)
+
+--- a/tools/testing/selftests/net/mptcp/pm_netlink.sh
++++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh
+@@ -127,6 +127,10 @@ id 8 flags signal 10.0.1.8" "id limit"
+ ip netns exec $ns1 ./pm_nl_ctl flush
+ check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "flush addrs"
++ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.1 flags unknown
++check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags  10.0.1.1" "ignore unknown flags"
++ip netns exec $ns1 ./pm_nl_ctl flush
++
+ ip netns exec $ns1 ./pm_nl_ctl limits 9 1 2>/dev/null
+ check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "rcv addrs above hard limit"
+--- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c
++++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c
+@@ -29,6 +29,8 @@
+ #define IPPROTO_MPTCP 262
+ #endif
++#define MPTCP_PM_ADDR_FLAG_UNKNOWN _BITUL(7)
++
+ static void syntax(char *argv[])
+ {
+       fprintf(stderr, "%s add|ann|rem|csf|dsf|get|set|del|flush|dump|events|listen|accept [<args>]\n", argv[0]);
+@@ -825,6 +827,8 @@ int add_addr(int fd, int pm_family, int
+                                       flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+                               else if (!strcmp(tok, "fullmesh"))
+                                       flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;
++                              else if (!strcmp(tok, "unknown"))
++                                      flags |= MPTCP_PM_ADDR_FLAG_UNKNOWN;
+                               else
+                                       error(1, errno,
+                                             "unknown flag %s", argv[arg]);
+@@ -1029,6 +1033,13 @@ static void print_addr(struct rtattr *at
+                               if (flags)
+                                       printf(",");
+                       }
++
++                      if (flags & MPTCP_PM_ADDR_FLAG_UNKNOWN) {
++                              printf("unknown");
++                              flags &= ~MPTCP_PM_ADDR_FLAG_UNKNOWN;
++                              if (flags)
++                                      printf(",");
++                      }
+                       /* bump unknown flags, if any */
+                       if (flags)
index acb0e3ffd399e855f0fa5ee80b14a093811afb30..774edb3347d740d86cda55caafa1692638fc7b67 100644 (file)
@@ -14,3 +14,11 @@ scsi-qla2xxx-allow-recovery-for-tape-devices.patch
 scsi-qla2xxx-delay-module-unload-while-fabric-scan-in-progress.patch
 scsi-qla2xxx-free-sp-in-error-path-to-fix-system-crash.patch
 scsi-qla2xxx-query-fw-again-before-proceeding-with-login.patch
+net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch
+nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch
+netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch
+netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch
+vsock-test-verify-socket-options-after-setting-them.patch
+spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch
+selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch
+mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch
diff --git a/queue-6.6/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch b/queue-6.6/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch
new file mode 100644 (file)
index 0000000..52fc4fd
--- /dev/null
@@ -0,0 +1,115 @@
+From 7446284023e8ef694fb392348185349c773eefb3 Mon Sep 17 00:00:00 2001
+From: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+Date: Tue, 26 Aug 2025 08:33:58 +0800
+Subject: spi: cadence-quadspi: Implement refcount to handle unbind during busy
+
+From: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+
+commit 7446284023e8ef694fb392348185349c773eefb3 upstream.
+
+driver support indirect read and indirect write operation with
+assumption no force device removal(unbind) operation. However
+force device removal(removal) is still available to root superuser.
+
+Unbinding driver during operation causes kernel crash. This changes
+ensure driver able to handle such operation for indirect read and
+indirect write by implementing refcount to track attached devices
+to the controller and gracefully wait and until attached devices
+remove operation completed before proceed with removal operation.
+
+Signed-off-by: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
+Reviewed-by: Niravkumar L Rabara <nirav.rabara@altera.com>
+Link: https://patch.msgid.link/8704fd6bd2ff4d37bba4a0eacf5eba3ba001079e.1756168074.git.khairul.anuar.romli@altera.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[Add cqspi defination in cqspi_exec_mem_op and minor context change fixed.]
+Signed-off-by: Robert Garcia <rob_garcia@163.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/spi/spi-cadence-quadspi.c |   34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -100,6 +100,8 @@ struct cqspi_st {
+       bool                    apb_ahb_hazard;
+       bool                    is_jh7110; /* Flag for StarFive JH7110 SoC */
++      refcount_t              refcount;
++      refcount_t              inflight_ops;
+ };
+ struct cqspi_driver_platdata {
+@@ -705,6 +707,9 @@ static int cqspi_indirect_read_execute(s
+       u8 *rxbuf_end = rxbuf + n_rx;
+       int ret = 0;
++      if (!refcount_read(&cqspi->refcount))
++              return -ENODEV;
++
+       writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
+       writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
+@@ -1021,6 +1026,9 @@ static int cqspi_indirect_write_execute(
+       unsigned int write_bytes;
+       int ret;
++      if (!refcount_read(&cqspi->refcount))
++              return -ENODEV;
++
+       writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
+       writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
+@@ -1412,11 +1420,29 @@ static int cqspi_mem_process(struct spi_
+ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ {
+       int ret;
++      struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
++
++      if (refcount_read(&cqspi->inflight_ops) == 0)
++              return -ENODEV;
++
++      if (!refcount_read(&cqspi->refcount))
++              return -EBUSY;
++
++      refcount_inc(&cqspi->inflight_ops);
++
++      if (!refcount_read(&cqspi->refcount)) {
++              if (refcount_read(&cqspi->inflight_ops))
++                      refcount_dec(&cqspi->inflight_ops);
++              return -EBUSY;
++      }
+       ret = cqspi_mem_process(mem, op);
+       if (ret)
+               dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
++      if (refcount_read(&cqspi->inflight_ops) > 1)
++              refcount_dec(&cqspi->inflight_ops);
++
+       return ret;
+ }
+@@ -1847,6 +1873,9 @@ static int cqspi_probe(struct platform_d
+               }
+       }
++      refcount_set(&cqspi->refcount, 1);
++      refcount_set(&cqspi->inflight_ops, 1);
++
+       ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
+                              pdev->name, cqspi);
+       if (ret) {
+@@ -1899,6 +1928,11 @@ static void cqspi_remove(struct platform
+ {
+       struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++      refcount_set(&cqspi->refcount, 0);
++
++      if (!refcount_dec_and_test(&cqspi->inflight_ops))
++              cqspi_wait_idle(cqspi);
++
+       spi_unregister_controller(cqspi->host);
+       cqspi_controller_enable(cqspi, 0);
diff --git a/queue-6.6/vsock-test-verify-socket-options-after-setting-them.patch b/queue-6.6/vsock-test-verify-socket-options-after-setting-them.patch
new file mode 100644 (file)
index 0000000..eba7624
--- /dev/null
@@ -0,0 +1,286 @@
+From 86814d8ffd55fd4ad19c512eccd721522a370fb2 Mon Sep 17 00:00:00 2001
+From: Konstantin Shkolnyy <kshk@linux.ibm.com>
+Date: Tue, 3 Dec 2024 09:06:56 -0600
+Subject: vsock/test: verify socket options after setting them
+
+From: Konstantin Shkolnyy <kshk@linux.ibm.com>
+
+commit 86814d8ffd55fd4ad19c512eccd721522a370fb2 upstream.
+
+Replace setsockopt() calls with calls to functions that follow
+setsockopt() with getsockopt() and check that the returned value and its
+size are the same as have been set. (Except in vsock_perf.)
+
+Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com>
+Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[Stefano: patch needed to avoid vsock test build failure reported by
+ Johan Korsnes after backporting commit 0a98de8013696 ("vsock/test: fix
+ seqpacket message bounds test") in 6.6-stable tree. Several tests are
+ missing here compared to upstream, so this version has been adapted by
+ removing some hunks.]
+Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/vsock/control.c    |    9 --
+ tools/testing/vsock/util.c       |  143 +++++++++++++++++++++++++++++++++++++++
+ tools/testing/vsock/util.h       |    7 +
+ tools/testing/vsock/vsock_test.c |   31 +++-----
+ 4 files changed, 164 insertions(+), 26 deletions(-)
+
+--- a/tools/testing/vsock/control.c
++++ b/tools/testing/vsock/control.c
+@@ -27,6 +27,7 @@
+ #include "timeout.h"
+ #include "control.h"
++#include "util.h"
+ static int control_fd = -1;
+@@ -50,7 +51,6 @@ void control_init(const char *control_ho
+       for (ai = result; ai; ai = ai->ai_next) {
+               int fd;
+-              int val = 1;
+               fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (fd < 0)
+@@ -65,11 +65,8 @@ void control_init(const char *control_ho
+                       break;
+               }
+-              if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+-                             &val, sizeof(val)) < 0) {
+-                      perror("setsockopt");
+-                      exit(EXIT_FAILURE);
+-              }
++              setsockopt_int_check(fd, SOL_SOCKET, SO_REUSEADDR, 1,
++                                   "setsockopt SO_REUSEADDR");
+               if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
+                       goto next;
+--- a/tools/testing/vsock/util.c
++++ b/tools/testing/vsock/util.c
+@@ -12,6 +12,7 @@
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <signal.h>
++#include <string.h>
+ #include <unistd.h>
+ #include <assert.h>
+ #include <sys/epoll.h>
+@@ -420,3 +421,145 @@ unsigned long hash_djb2(const void *data
+       return hash;
+ }
++
++/* Set "unsigned long long" socket option and check that it's indeed set */
++void setsockopt_ull_check(int fd, int level, int optname,
++                        unsigned long long val, char const *errmsg)
++{
++      unsigned long long chkval;
++      socklen_t chklen;
++      int err;
++
++      err = setsockopt(fd, level, optname, &val, sizeof(val));
++      if (err) {
++              fprintf(stderr, "setsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++      chkval = ~val; /* just make storage != val */
++      chklen = sizeof(chkval);
++
++      err = getsockopt(fd, level, optname, &chkval, &chklen);
++      if (err) {
++              fprintf(stderr, "getsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++      if (chklen != sizeof(chkval)) {
++              fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
++                      chklen);
++              goto fail;
++      }
++
++      if (chkval != val) {
++              fprintf(stderr, "value mismatch: set %llu got %llu\n", val,
++                      chkval);
++              goto fail;
++      }
++      return;
++fail:
++      fprintf(stderr, "%s  val %llu\n", errmsg, val);
++      exit(EXIT_FAILURE);
++;
++}
++
++/* Set "int" socket option and check that it's indeed set */
++void setsockopt_int_check(int fd, int level, int optname, int val,
++                        char const *errmsg)
++{
++      int chkval;
++      socklen_t chklen;
++      int err;
++
++      err = setsockopt(fd, level, optname, &val, sizeof(val));
++      if (err) {
++              fprintf(stderr, "setsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++      chkval = ~val; /* just make storage != val */
++      chklen = sizeof(chkval);
++
++      err = getsockopt(fd, level, optname, &chkval, &chklen);
++      if (err) {
++              fprintf(stderr, "getsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++      if (chklen != sizeof(chkval)) {
++              fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
++                      chklen);
++              goto fail;
++      }
++
++      if (chkval != val) {
++              fprintf(stderr, "value mismatch: set %d got %d\n", val, chkval);
++              goto fail;
++      }
++      return;
++fail:
++      fprintf(stderr, "%s val %d\n", errmsg, val);
++      exit(EXIT_FAILURE);
++}
++
++static void mem_invert(unsigned char *mem, size_t size)
++{
++      size_t i;
++
++      for (i = 0; i < size; i++)
++              mem[i] = ~mem[i];
++}
++
++/* Set "timeval" socket option and check that it's indeed set */
++void setsockopt_timeval_check(int fd, int level, int optname,
++                            struct timeval val, char const *errmsg)
++{
++      struct timeval chkval;
++      socklen_t chklen;
++      int err;
++
++      err = setsockopt(fd, level, optname, &val, sizeof(val));
++      if (err) {
++              fprintf(stderr, "setsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++       /* just make storage != val */
++      chkval = val;
++      mem_invert((unsigned char *)&chkval, sizeof(chkval));
++      chklen = sizeof(chkval);
++
++      err = getsockopt(fd, level, optname, &chkval, &chklen);
++      if (err) {
++              fprintf(stderr, "getsockopt err: %s (%d)\n",
++                      strerror(errno), errno);
++              goto fail;
++      }
++
++      if (chklen != sizeof(chkval)) {
++              fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val),
++                      chklen);
++              goto fail;
++      }
++
++      if (memcmp(&chkval, &val, sizeof(val)) != 0) {
++              fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n",
++                      val.tv_sec, val.tv_usec, chkval.tv_sec, chkval.tv_usec);
++              goto fail;
++      }
++      return;
++fail:
++      fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec);
++      exit(EXIT_FAILURE);
++}
++
++void enable_so_zerocopy_check(int fd)
++{
++      setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1,
++                           "setsockopt SO_ZEROCOPY");
++}
+--- a/tools/testing/vsock/util.h
++++ b/tools/testing/vsock/util.h
+@@ -50,4 +50,11 @@ void list_tests(const struct test_case *
+ void skip_test(struct test_case *test_cases, size_t test_cases_len,
+              const char *test_id_str);
+ unsigned long hash_djb2(const void *data, size_t len);
++void setsockopt_ull_check(int fd, int level, int optname,
++                        unsigned long long val, char const *errmsg);
++void setsockopt_int_check(int fd, int level, int optname, int val,
++                        char const *errmsg);
++void setsockopt_timeval_check(int fd, int level, int optname,
++                            struct timeval val, char const *errmsg);
++void enable_so_zerocopy_check(int fd);
+ #endif /* UTIL_H */
+--- a/tools/testing/vsock/vsock_test.c
++++ b/tools/testing/vsock/vsock_test.c
+@@ -503,17 +503,13 @@ static void test_seqpacket_msg_bounds_se
+       sock_buf_size = SOCK_BUF_SIZE;
+-      if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
+-                     &sock_buf_size, sizeof(sock_buf_size))) {
+-              perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
+-              exit(EXIT_FAILURE);
+-      }
+-
+-      if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
+-                     &sock_buf_size, sizeof(sock_buf_size))) {
+-              perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
+-              exit(EXIT_FAILURE);
+-      }
++      setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
++                           sock_buf_size,
++                           "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
++
++      setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
++                           sock_buf_size,
++                           "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
+       /* Ready to receive data. */
+       control_writeln("SRVREADY");
+@@ -648,10 +644,8 @@ static void test_seqpacket_timeout_clien
+       tv.tv_sec = RCVTIMEO_TIMEOUT_SEC;
+       tv.tv_usec = 0;
+-      if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) {
+-              perror("setsockopt(SO_RCVTIMEO)");
+-              exit(EXIT_FAILURE);
+-      }
++      setsockopt_timeval_check(fd, SOL_SOCKET, SO_RCVTIMEO, tv,
++                               "setsockopt(SO_RCVTIMEO)");
+       read_enter_ns = current_nsec();
+@@ -928,11 +922,8 @@ static void test_stream_poll_rcvlowat_cl
+               exit(EXIT_FAILURE);
+       }
+-      if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
+-                     &lowat_val, sizeof(lowat_val))) {
+-              perror("setsockopt(SO_RCVLOWAT)");
+-              exit(EXIT_FAILURE);
+-      }
++      setsockopt_int_check(fd, SOL_SOCKET, SO_RCVLOWAT,
++                           lowat_val, "setsockopt(SO_RCVLOWAT)");
+       control_expectln("SRVSENT");