From: Greg Kroah-Hartman Date: Fri, 13 Feb 2026 12:20:45 +0000 (+0100) Subject: 6.6-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a4dc868e798146f5a09b2254c9fc9e5ddedf3b93;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches 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 --- 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 index 0000000000..7d696a6f9b --- /dev/null +++ b/queue-6.6/mptcp-fix-race-in-mptcp_pm_nl_flush_addrs_doit.patch @@ -0,0 +1,79 @@ +From e2a9eeb69f7d4ca4cf4c70463af77664fdb6ab1d Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 24 Jan 2026 11:59:18 +0100 +Subject: mptcp: fix race in mptcp_pm_nl_flush_addrs_doit() + +From: Eric Dumazet + +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 +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 +Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/611 +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260124-net-mptcp-race_nl_flush_addrs-v3-1-b2dc1b613e9d@kernel.org +Signed-off-by: Jakub Kicinski +[ 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) +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..1c3895f383 --- /dev/null +++ b/queue-6.6/net-sfp-fix-quirk-for-ubiquiti-u-fiber-instant-sfp-module.patch @@ -0,0 +1,50 @@ +From adcbadfd8e05d3558c9cfaa783f17c645181165f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +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 + +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 +Reviewed-by: Maxime Chevallier +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260129082227.17443-1-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..cde42f23aa --- /dev/null +++ b/queue-6.6/netfilter-nf_tables-missing-objects-with-no-memcg-accounting.patch @@ -0,0 +1,174 @@ +From 69e687cea79fc99a17dfb0116c8644b9391b915e Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Wed, 18 Sep 2024 14:19:45 +0200 +Subject: netfilter: nf_tables: missing objects with no memcg accounting + +From: Pablo Neira Ayuso + +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 +[ Adjust context ] +Signed-off-by: Bin Lan +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..07abd49343 --- /dev/null +++ b/queue-6.6/netfilter-nft_set_pipapo-prevent-overflow-in-lookup-table-allocation.patch @@ -0,0 +1,153 @@ +From 4c5c6aa9967dbe55bd017bb509885928d0f31206 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Tue, 22 Apr 2025 21:52:43 +0200 +Subject: netfilter: nft_set_pipapo: prevent overflow in lookup table allocation + +From: Pablo Neira Ayuso + +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 +Reviewed-by: Stefano Brivio +Signed-off-by: Pablo Neira Ayuso +[ Adjust context ] +Signed-off-by: Bin Lan +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..959b386348 --- /dev/null +++ b/queue-6.6/nfsd-don-t-ignore-the-return-code-of-svc_proc_register.patch @@ -0,0 +1,92 @@ +From 930b64ca0c511521f0abdd1d57ce52b2a6e3476b Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Thu, 6 Feb 2025 13:12:13 -0500 +Subject: nfsd: don't ignore the return code of svc_proc_register() + +From: Jeff Layton + +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 +Signed-off-by: Chuck Lever +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..132640b701 --- /dev/null +++ b/queue-6.6/selftests-mptcp-pm-ensure-unknown-flags-are-ignored.patch @@ -0,0 +1,84 @@ +From 29f4801e9c8dfd12bdcb33b61a6ac479c7162bd7 Mon Sep 17 00:00:00 2001 +From: "Matthieu Baerts (NGI0)" +Date: Fri, 5 Dec 2025 19:55:15 +0100 +Subject: selftests: mptcp: pm: ensure unknown flags are ignored + +From: Matthieu Baerts (NGI0) + +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 +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-2-9e4781a6c1b8@kernel.org +Signed-off-by: Jakub Kicinski +[ 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) +Signed-off-by: Greg Kroah-Hartman +--- + 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 []\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) diff --git a/queue-6.6/series b/queue-6.6/series index acb0e3ffd3..774edb3347 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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 index 0000000000..52fc4fd759 --- /dev/null +++ b/queue-6.6/spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch @@ -0,0 +1,115 @@ +From 7446284023e8ef694fb392348185349c773eefb3 Mon Sep 17 00:00:00 2001 +From: Khairul Anuar Romli +Date: Tue, 26 Aug 2025 08:33:58 +0800 +Subject: spi: cadence-quadspi: Implement refcount to handle unbind during busy + +From: Khairul Anuar Romli + +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 +Reviewed-by: Matthew Gerlach +Reviewed-by: Niravkumar L Rabara +Link: https://patch.msgid.link/8704fd6bd2ff4d37bba4a0eacf5eba3ba001079e.1756168074.git.khairul.anuar.romli@altera.com +Signed-off-by: Mark Brown +[Add cqspi defination in cqspi_exec_mem_op and minor context change fixed.] +Signed-off-by: Robert Garcia +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 0000000000..eba76246f4 --- /dev/null +++ b/queue-6.6/vsock-test-verify-socket-options-after-setting-them.patch @@ -0,0 +1,286 @@ +From 86814d8ffd55fd4ad19c512eccd721522a370fb2 Mon Sep 17 00:00:00 2001 +From: Konstantin Shkolnyy +Date: Tue, 3 Dec 2024 09:06:56 -0600 +Subject: vsock/test: verify socket options after setting them + +From: Konstantin Shkolnyy + +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 +Reviewed-by: Stefano Garzarella +Signed-off-by: Paolo Abeni +[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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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"); +