6.18.32-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 741/957 btrfs: fix double-decrement of bytes_may_use in submit_one_async_extent()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ]
submit_one_async_extent() calls btrfs_reserve_extent(), which decrements bytes_may_use. If the call btrfs_create_io_em() fails, we jump to out_free_reserve, which calls extent_clear_unlock_delalloc().
Because we're specifying EXTENT_DO_ACCOUNTING, i.e. EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases bytes_may_use again. This can lead to problems later on, as an initial write can fail only for the writeback to silently ENOSPC.
Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved extents in cow_one_range()"), which is the same fix in cow_one_range().
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -1208,7 +1208,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,NULL , &cached,EXTENT_LOCKED |EXTENT_DELALLOC |EXTENT_DELALLOC_NEW | -EXTENT_DEFRAG |EXTENT_DO_ACCOUNTING , +EXTENT_DEFRAG |EXTENT_CLEAR_META_RESV ,PAGE_UNLOCK |PAGE_START_WRITEBACK | PAGE_END_WRITEBACK);free_async_extent_pages (async_extent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 742/957 cgroup: Increment nr_dying_subsys_* from rmdir context
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Malat <[email protected]>
[ Upstream commit 13e786b64bd3fd81c7eb22aa32bf8305c32f2ccf ]
Incrementing nr_dying_subsys_* in offline_css(), which is executed by cgroup_offline_wq worker, leads to a race where user can see the value to be 0 if he reads cgroup.stat after calling rmdir and before the worker executes. This makes the user wrongly expect resources released by the removed cgroup to be available for a new assignment.
Increment nr_dying_subsys_* from kill_css(), which is called from the cgroup_rmdir() context.
--- kernel/cgroup/cgroup.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
kernel/cgroup/cgroup.c +12 -10
@@ -5773,16 +5773,6 @@ static void offline_css(struct cgroup_subsys_state *css)RCU_INIT_POINTER (css->cgroup->subsys[ss->id],NULL );wake_up_all (&css->cgroup->offline_waitq); - - css->cgroup->nr_dying_subsys[ss->id]++; -/* -* Parent css and cgroup cannot be freed until after the freeing -* of child css, see css_free_rwork_fn(). -*/ -while ((css = css->parent)) { - css->nr_descendants--; - css->cgroup->nr_dying_subsys[ss->id]++; - } }/**
@@ -6094,6 +6084,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref)*/ static void kill_css (struct cgroup_subsys_state *css) { +struct cgroup_subsys *ss = css->ss; +lockdep_assert_held (&cgroup_mutex);if (css->flags &CSS_DYING )
@@ -6130,6 +6122,16 @@ static void kill_css(struct cgroup_subsys_state *css)* css is confirmed to be seen as killed on all CPUs. */ percpu_ref_kill_and_confirm (&css->refcnt, css_killed_ref_fn); + + css->cgroup->nr_dying_subsys[ss->id]++; +/* +* Parent css and cgroup cannot be freed until after the freeing +* of child css, see css_free_rwork_fn(). +*/ +while ((css = css->parent)) { + css->nr_descendants--; + css->cgroup->nr_dying_subsys[ss->id]++; + } }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 743/957 tracing: branch: Fix inverted check on stat tracer registration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ]
init_annotated_branch_stats() and all_annotated_branch_stats() check the return value of register_stat_tracer() with "if (!ret)", but register_stat_tracer() returns 0 on success and a negative errno on failure. The inverted check causes the warning to be printed on every successful registration, e.g.:
Warning: could not register annotated branches stats
while leaving real failures silent. The initcall also returned a hard-coded 1 instead of the actual error.
Invert the check and propagate ret so that the warning fires on real errors and the initcall reports the correct status.
--- kernel/trace/trace_branch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/trace/trace_branch.c +4 -4
@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&annotated_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "annotated branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&all_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "all branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 744/957 nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its callers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ]
Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) and returns early. However, because the function returns void, the callers are entirely unaware that a fatal error has occurred and that the cmd->recv_msg.msg_iter was left uninitialized.
Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA Consequently, the socket receiving loop may attempt to read incoming network data into the uninitialized iterator.
Fix this by shifting the error handling responsibility to the callers.
--- drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-)
drivers/nvme/target/tcp.c +29 -22
@@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue); -static void nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) +static int nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) {struct bio_vec *iov = cmd->iov;struct scatterlist *sg;
@@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) offset = cmd->rbytes_done; cmd->sg_idx = offset /PAGE_SIZE ; sg_offset = offset %PAGE_SIZE ; -if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) +return -EPROTO ; + sg = &cmd->req.sg[cmd->sg_idx]; sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;while (length) { -if (!sg_remaining) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } -if (!sg->length || sg->length <= sg_offset) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!sg_remaining) +return -EPROTO ; + +if (!sg->length || sg->length <= sg_offset) +return -EPROTO ; +u32 iov_len =min_t (u32, length, sg->length - sg_offset); bvec_set_page(iov, sg_page(sg), iov_len,
@@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)iov_iter_bvec (&cmd->recv_msg.msg_iter,ITER_DEST , cmd->iov, nr_pages, cmd->pdu_len); +return 0 ; }static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue)
@@ -958,7 +956,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)return 0 ; } -static void nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue, +static int nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue,struct nvmet_tcp_cmd *cmd,struct nvmet_req *req) {size_t data_len =le32_to_cpu (req->cmd->common.dptr.sgl.length);
@@ -974,19 +972,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,if (!nvme_is_write (cmd->req.cmd) || !data_len || data_len > cmd->req.port->inline_data_size) {nvmet_prepare_receive_pdu (queue); -return ; +return 0 ; } ret =nvmet_tcp_map_data (cmd);if (unlikely (ret)) {pr_err ("queue %d: failed to map data\n" , queue->idx);nvmet_tcp_fatal_error (queue); -return ; +return -EPROTO ; } queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (cmd); cmd->flags |=NVMET_TCP_F_INIT_FAILED ; + ret =nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + +return ret; }static int nvmet_tcp_handle_h2c_data_pdu (struct nvmet_tcp_queue *queue)
@@ -1038,7 +1040,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) goto err_proto; } cmd->pdu_recv =0 ; -nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (nvmet_tcp_build_pdu_iovec (cmd))) { +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + goto err_proto; + } queue->cmd = cmd; queue->rcv_state =NVMET_TCP_RECV_DATA ;
@@ -1101,8 +1106,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)le32_to_cpu (req->cmd->common.dptr.sgl.length), le16_to_cpu(req->cqe->status)); -nvmet_tcp_handle_req_failure (queue, queue->cmd, req); -return 0 ; +return nvmet_tcp_handle_req_failure (queue, queue->cmd, req); } ret =nvmet_tcp_map_data (queue->cmd);
@@ -1119,8 +1123,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)if (nvmet_tcp_need_data_in (queue->cmd)) {if (nvmet_tcp_has_inline_data (queue->cmd)) { queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (queue->cmd); -return 0 ; + ret =nvmet_tcp_build_pdu_iovec (queue->cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , + queue->idx); +return ret; }/* send back R2T */ nvmet_tcp_queue_response (&queue->cmd->req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 745/957 netfilter: arp_tables: fix IEEE1394 ARP payload parsing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ]
Weiming Shi says:
"arp_packet_match() unconditionally parses the ARP payload assuming two hardware addresses are present (source and target). However, IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address field, and arp_hdr_len() already accounts for this by returning a shorter length for ARPHRD_IEEE1394 devices.
As a result, on IEEE1394 interfaces arp_packet_match() advances past a nonexistent target hardware address and reads the wrong bytes for both the target device address comparison and the target IP address. This causes arptables rules to match against garbage data, leading to incorrect filtering decisions: packets that should be accepted may be dropped and vice versa.
The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already handles this correctly by skipping the target hardware address for ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()."
Mangle the original patch to always return 0 (no match) in case user matches on the target hardware address which is never present in IEEE1394.
Note that this returns 0 (no match) for either normal and inverse match because matching in the target hardware address in ARPHRD_IEEE1394 has never been supported by arptables. This is intentional, matching on the target hardware address should never evaluate true for ARPHRD_IEEE1394.
Moreover, adjust arpt_mangle to drop the packet too as AI suggests:
In arpt_mangle, the logic assumes a standard ARP layout. Because IEEE1394 (FireWire) omits the target hardware address, the linear pointer arithmetic miscalculates the offset for the target IP address. This causes mangling operations to write to the wrong location, leading to packet corruption. To ensure safety, this patch drops packets (NF_DROP) when mangling is requested for these fields on IEEE1394 devices, as the current implementation cannot correctly map the FireWire ARP payload.
This omits both mangling target hardware and IP address. Even if IP address mangling should be possible in IEEE1394, this would require to adjust arpt_mangle offset calculation, which has never been supported.
Based on patch from Weiming Shi <[email protected]>.
--- net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ 2 files changed, 23 insertions(+), 3 deletions(-)
net/ipv4/netfilter/arp_tables.c +15 -3
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, arpptr += dev->addr_len;memcpy (&src_ipaddr, arpptr,sizeof (u32)); arpptr +=sizeof (u32); - tgt_devaddr = arpptr; - arpptr += dev->addr_len; + +if (IS_ENABLED (CONFIG_FIREWIRE_NET ) && dev->type ==ARPHRD_IEEE1394 ) { +if (unlikely (memchr_inv (arpinfo->tgt_devaddr.mask,0 , +sizeof (arpinfo->tgt_devaddr.mask)))) +return 0 ; + + tgt_devaddr =NULL ; + }else { + tgt_devaddr = arpptr; + arpptr += dev->addr_len; + }memcpy (&tgt_ipaddr, arpptr,sizeof (u32));if (NF_INVF (arpinfo,ARPT_INV_SRCDEVADDR ,arp_devaddr_compare (&arpinfo->src_devaddr, src_devaddr, - dev->addr_len)) || + dev->addr_len))) +return 0 ; + +if (tgt_devaddr &&NF_INVF (arpinfo,ARPT_INV_TGTDEVADDR ,arp_devaddr_compare (&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len)))
net/ipv4/netfilter/arpt_mangle.c +8 -0
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += pln;if (mangle->flags &ARPT_MANGLE_TDEV ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_DEV_ADDR_LEN_MAX < hln || (arpptr + hln >skb_tail_pointer (skb)))return NF_DROP ;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += hln;if (mangle->flags &ARPT_MANGLE_TIP ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_MANGLE_ADDR_LEN_MAX < pln || (arpptr + pln >skb_tail_pointer (skb)))return NF_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 746/957 netfilter: nf_tables: use list_del_rcu for netlink hooks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ]
nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need to use list_del_rcu(), this list can be walked by concurrent dumpers.
Add a new helper and use it consistently.
--- net/netfilter/nf_tables_api.c | 44 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 26 deletions(-)
net/netfilter/nf_tables_api.c +18 -26
@@ -373,6 +373,12 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook)call_rcu (&hook->rcu, __nft_netdev_hook_free_rcu); } +static void nft_netdev_hook_unlink_free_rcu (struct nft_hook *hook) +{ +list_del_rcu (&hook->list); +nft_netdev_hook_free_rcu (hook); +} +static void nft_netdev_unregister_hooks (struct net *net,struct list_head *hook_list,bool release_netdev)
@@ -383,10 +389,8 @@ static void nft_netdev_unregister_hooks(struct net *net,list_for_each_entry_safe (hook, next, hook_list, list) {list_for_each_entry (ops, &hook->ops_list, list)nf_unregister_net_hook (net, ops); -if (release_netdev) { -list_del (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +if (release_netdev) +nft_netdev_hook_unlink_free_rcu (hook); } }
@@ -2322,10 +2326,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)if (nft_base_chain_netdev (table->family, basechain->ops.hooknum)) {list_for_each_entry_safe (hook, next, - &basechain->hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } + &basechain->hook_list, list) +nft_netdev_hook_unlink_free_rcu (hook); }module_put (basechain->type->owner);if (rcu_access_pointer (basechain->stats)) {
@@ -3025,6 +3027,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,list_for_each_entry (ops, &h->ops_list, list)nf_unregister_net_hook (ctx->net, ops); } +/* hook.list is on stack, no need for list_del_rcu() */ list_del (&h->list);nft_netdev_hook_free_rcu (h); }
@@ -9069,10 +9072,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,list_for_each_entry_safe (hook, next, hook_list, list) {list_for_each_entry (ops, &hook->ops_list, list)nft_unregister_flowtable_ops (net, flowtable, ops); -if (release_netdev) { -list_del (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +if (release_netdev) +nft_netdev_hook_unlink_free_rcu (hook); } }
@@ -9143,8 +9144,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,nft_unregister_flowtable_ops (net, flowtable, ops); } -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); +nft_netdev_hook_unlink_free_rcu (hook); }return err;
@@ -9154,10 +9154,8 @@ static void nft_hooks_destroy(struct list_head *hook_list) {struct nft_hook *hook, *next; -list_for_each_entry_safe (hook, next, hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +list_for_each_entry_safe (hook, next, hook_list, list) +nft_netdev_hook_unlink_free_rcu (hook); } static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
@@ -9245,8 +9243,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,nft_unregister_flowtable_ops (ctx->net, flowtable, ops); } -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); +nft_netdev_hook_unlink_free_rcu (hook); }return err;
@@ -9752,13 +9749,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,static void nf_tables_flowtable_destroy (struct nft_flowtable *flowtable) { -struct nft_hook *hook, *next; - flowtable->data.type->free (&flowtable->data); -list_for_each_entry_safe (hook, next, &flowtable->hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +nft_hooks_destroy (&flowtable->hook_list);kfree (flowtable->name);module_put (flowtable->data.type->owner);kfree (flowtable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 747/957 nvme-pci: fix missed admin queue sq doorbell write
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ]
We can batch admin commands submitted through io_uring_cmd passthrough, which means bd->last may be false and skips the doorbell write to aggregate multiple commands per write. If a subsequent command can't be dispatched for whatever reason, we have to provide the blk-mq ops' commit_rqs callback in order to ensure we properly update the doorbell.
--- drivers/nvme/host/pci.c | 1 + 1 file changed, 1 insertion(+)
drivers/nvme/host/pci.c +1 -0
@@ -2028,6 +2028,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)static const struct blk_mq_ops nvme_mq_admin_ops = { .queue_rq = nvme_queue_rq, .complete = nvme_pci_complete_rq, + .commit_rqs = nvme_commit_rqs, .init_hctx = nvme_admin_init_hctx, .init_request = nvme_pci_init_request, .timeout = nvme_timeout,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 748/957 drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with VRAM
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ]
When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW:
Make sure that GART does not overlap with VRAM when VRAM is configured to be in the low address space.
Solve this according to the following logic:
- When GART fits before VRAM, use zero address for GART
- Otherwise, put GART after the end of VRAM, aligned to 4 GiB
Previously, I had assumed this was not possible so it was OK to not handle it, but now we got a report from a user who has a board that is configured this way.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +4 -1
@@ -313,7 +313,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, mc->gart_start = max_mc_address - mc->gart_size +1 ;break ;case AMDGPU_GART_PLACEMENT_LOW : - mc->gart_start =0 ; +if (size_bf >= mc->gart_size) + mc->gart_start =0 ; +else + mc->gart_start =ALIGN (mc->fb_end, four_gb);break ;case AMDGPU_GART_PLACEMENT_BEST_FIT :default :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 749/957 drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ]
There were multiple issues in that code.
First of all the order between the reset semaphore and the mm_lock was wrong (e.g. copy_to_user) was called while holding the lock.
Then we allocated memory while holding the reset semaphore which is also a pretty big bug and can deadlock.
Then we used down_read_trylock() instead of waiting for the reset to finish.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +24 -33
@@ -837,68 +837,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ? -EFAULT :0 ; }case AMDGPU_INFO_READ_MMR_REG : { -int ret =0 ; -unsigned int n, alloc_size; -uint32_t *regs;unsigned int se_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SE_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SE_INDEX_MASK ;unsigned int sh_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SH_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SH_INDEX_MASK ; - -if (!down_read_trylock (&adev->reset_domain->sem)) -return -ENOENT ; +unsigned int alloc_size; +uint32_t *regs; +int ret;/* set full masks if the userspace set all bits * in the bitfields */ -if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) { +if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) se_num =0xffffffff ; - }else if (se_num >=AMDGPU_GFX_MAX_SE ) { - ret = -EINVAL ; - goto out; - } +else if (se_num >=AMDGPU_GFX_MAX_SE ) +return -EINVAL ; -if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) { +if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) sh_num =0xffffffff ; - }else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) { - ret = -EINVAL ; - goto out; - } +else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) +return -EINVAL ; -if (info->read_mmr_reg.count >128 ) { - ret = -EINVAL ; - goto out; - } +if (info->read_mmr_reg.count >128 ) +return -EINVAL ; - regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs),GFP_KERNEL ); -if (!regs) { - ret = -ENOMEM ; - goto out; - } + regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs), +GFP_KERNEL ); +if (!regs) +return -ENOMEM ; +down_read (&adev->reset_domain->sem); alloc_size = info->read_mmr_reg.count *sizeof (*regs); -amdgpu_gfx_off_ctrl (adev, false); + ret =0 ;for (i =0 ; i < info->read_mmr_reg.count; i++) {if (amdgpu_asic_read_register (adev, se_num, sh_num, info->read_mmr_reg.dword_offset + i, ®s[i])) {DRM_DEBUG_KMS ("unallowed offset %#x\n" , info->read_mmr_reg.dword_offset + i); -kfree (regs); -amdgpu_gfx_off_ctrl (adev, true); ret = -EFAULT ; - goto out; +break ; } }amdgpu_gfx_off_ctrl (adev, true); - n =copy_to_user (out, regs,min (size, alloc_size)); -kfree (regs); - ret = (n ? -EFAULT :0 ); -out:up_read (&adev->reset_domain->sem); + +if (!ret) { + ret =copy_to_user (out, regs,min (size, alloc_size)) + ? -EFAULT :0 ; + } +kfree (regs);return ret; }case AMDGPU_INFO_DEV_INFO : {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 750/957 drm/amdgpu/uvd3.1: Dont validate the firmware when already validated
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ]
UVD 3.1 firmware validation seems to always fail after attempting it when it had already been validated. (This works similarly with the VCE 1.0 as well.)
Don't attempt repeating the validation when it's already done.
This caused issues in situations when the system isn't able to suspend the GPU properly and so the GPU isn't actually powered down. Then amdgpu would fail when calling the IP block resume function.
--- drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +10 -0
@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)uint64_t addr;uint32_t size; +/* When the keyselect is already set, don't perturb it. */ +if (RREG32 (mmUVD_FW_START)) +return ; +/* program the VCPU memory controller bits 0-27 */ addr = (adev->uvd.inst->gpu_addr +AMDGPU_UVD_FIRMWARE_OFFSET ) >>3 ; size =AMDGPU_UVD_FIRMWARE_SIZE (adev) >>3 ;
@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)int i;uint32_t keysel = adev->uvd.keyselect; +if (RREG32 (mmUVD_FW_START) &UVD_FW_STATUS__PASS_MASK ) { +dev_dbg (adev->dev,"UVD keyselect already set: 0x%x (on CPU: 0x%x)\n" , +RREG32 (mmUVD_FW_START), adev->uvd.keyselect); +return 0 ; + } +WREG32 (mmUVD_FW_START, keysel);for (i =0 ; i <10 ; ++i) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 751/957 drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2)
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ]
This commit fixes amdgpu to work on the Radeon HD 7870 XT which has never worked with the Linux open source drivers before.
Some boards have "harvested" chips, meaning that some parts of the chip are disabled and fused, and it's sold for cheaper and under a different marketing name.
On a harvested chip, any of the following can be disabled:
- CUs (Compute Units)
- RBs (Render Backend, aka. ROP)
- Memory channels (ie. the chip has a lower bandwidth)
- TCCs (ie. less L2 cache)
Handle chips with harvested TCCs by patching the registers that configure how TCCs are mapped.
If some TCCs are disabled, we need to make sure that the disabled TCCs are not used, and the remaining TCCs are used optimally.
TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used.
Note that the TCC configuration is highly relevant to performance. Suboptimal configuration (eg. CHAN_STEER=0) can significantly reduce gaming performance.
For optimal performance:
- Rely on the CHAN_STEER from the golden registers table, only skip disabled TCCs but keep the mapping order.
- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, which performs better than using the same TCC twice.
v2:
- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +66 -0
@@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)mutex_unlock (&adev->grbm_idx_mutex); } +/** +* gfx_v6_0_setup_tcc() - setup which TCCs are used +* +* @adev: amdgpu_device pointer +* +* Verify whether the current GPU has any TCCs disabled, +* which can happen when the GPU is harvested and some +* memory channels are disabled, reducing the memory bus width. +* For example, on the Radeon HD 7870 XT (Tahiti LE). +* +* If some TCCs are disabled, we need to make sure that +* the disabled TCCs are not used, and the remaining TCCs +* are used optimally. +* +* TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +* TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. +* +* For optimal performance: +* - Rely on the CHAN_STEER from the golden registers table, +* only skip disabled TCCs but keep the mapping order. +* - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, +* which performs better than using the same TCC twice. +*/ +static void gfx_v6_0_setup_tcc (struct amdgpu_device *adev) +{ +u32 i, tcc, tcp_addr_config, num_active_tcc =0 ; +u64 chan_steer, patched_chan_steer =0 ; +const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; +const u32 dis_tcc_mask = +amdgpu_gfx_create_bitmask (num_max_tcc) & + (REG_GET_FIELD (RREG32 (mmCGTS_TCC_DISABLE), +CGTS_TCC_DISABLE ,TCC_DISABLE ) | +REG_GET_FIELD (RREG32 (mmCGTS_USER_TCC_DISABLE), +CGTS_USER_TCC_DISABLE ,TCC_DISABLE )); + +/* When no TCC is disabled, the golden registers table already has optimal TCC setup */ +if (!dis_tcc_mask) +return ; + +/* Each 4-bit nibble contains the index of a TCC used by all TCPs */ + chan_steer =RREG32 (mmTCP_CHAN_STEER_LO) | ((u64 )RREG32 (mmTCP_CHAN_STEER_HI) <<32ull ); + +/* Patch the TCP to TCC mapping to skip disabled TCCs */ +for (i =0 ; i < num_max_tcc; ++i) { + tcc = (chan_steer >> (u64)(4 * i)) &0xf ; + +if (!((1 << tcc) & dis_tcc_mask)) { +/* Copy enabled TCC indices to the patched register value. */ + patched_chan_steer |= (u64 )tcc << (u64)(4 * num_active_tcc); + ++num_active_tcc; + } + } + +WARN_ON (num_active_tcc != num_max_tcc -hweight32 (dis_tcc_mask)); + +/* Patch number of TCCs used by TCPs */ + tcp_addr_config =REG_SET_FIELD (RREG32 (mmTCP_ADDR_CONFIG), +TCP_ADDR_CONFIG ,NUM_TCC_BANKS , + num_active_tcc -1 ); + +WREG32 (mmTCP_ADDR_CONFIG, tcp_addr_config); +WREG32 (mmTCP_CHAN_STEER_HI,upper_32_bits (patched_chan_steer)); +WREG32 (mmTCP_CHAN_STEER_LO,lower_32_bits (patched_chan_steer)); +} +static void gfx_v6_0_config_init (struct amdgpu_device *adev) { adev->gfx.config.double_offchip_lds_buf =0 ;
@@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev)gfx_v6_0_tiling_mode_table_init (adev);gfx_v6_0_setup_rb (adev); +gfx_v6_0_setup_tcc (adev);gfx_v6_0_setup_spi (adev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 752/957 netfilter: xt_policy: fix strict mode inbound policy matching
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiexun Wang <[email protected]>
[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ]
match_policy_in() walks sec_path entries from the last transform to the first one, but strict policy matching needs to consume info->pol[] in the same forward order as the rule layout.
Derive the strict-match policy position from the number of transforms already consumed so that multi-element inbound rules are matched consistently.
--- net/netfilter/xt_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_policy.c +1 -1
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,return 0 ;for (i = sp->len -1 ; i >=0 ; i--) { - pos = strict ? i - sp->len +1 :0 ; + pos = strict ? sp->len - i -1 :0 ;if (pos >= info->len)return 0 ; e = &info->pol[pos];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 753/957 netfilter: nf_conntrack_sip: dont use simple_strtoul
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ]
Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), and ct_sip_parse_request() with a new sip_parse_port() helper that validates each digit against the buffer limit, eliminating the use of simple_strtoul() which assumes NUL-terminated strings.
The previous code dereferenced pointers without bounds checks after sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated skb data. A port that reaches the buffer limit without a trailing character is also rejected as malformed.
Also get rid of all simple_strtoul() usage in conntrack, prefer a stricter version instead. There are intentional changes:
- Bail out if number is > UINT_MAX and indicate a failure, same for too long sequences.
While we do accept 05535 as port 5535, we will not accept e.g. 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, we should restrict this to not waste cycles when presented with malformed packets with 64k '0' characters.
- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch 'expire=' and 'rports='; both are expected to use base-10.
- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k range.
- epaddr_len now returns 0 if the port is invalid, as it already does for invalid ip addresses. This is intentional. nf_conntrack_sip performs lots of guesswork to find the right parts of the message to parse. Being stricter could break existing setups. Connection tracking helpers are designed to allow traffic to pass, not to block it.
Based on an earlier patch from Jenny Guanni Qu <[email protected]>.
--- net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- net/netfilter/nf_nat_sip.c | 1 + 2 files changed, 119 insertions(+), 34 deletions(-)
net/netfilter/nf_conntrack_sip.c +118 -34
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,return 1 ; } +/* Parse optional port number after IP address. +* Returns false on malformed input, true otherwise. +* If port is non-NULL, stores parsed port in network byte order. +* If no port is present, sets *port to default SIP port. +*/ +static bool sip_parse_port (const char *dptr,const char **endp, +const char *limit,__be16 *port) +{ +unsigned int p =0 ; +int len =0 ; + +if (dptr >= limit) +return false; + +if (*dptr !=':' ) { +if (port) + *port =htons (SIP_PORT ); +if (endp) + *endp = dptr; +return true; + } + + dptr++;/* skip ':' */ + +while (dptr < limit &&isdigit (*dptr)) { + p = p *10 + (*dptr -'0' ); + dptr++; + len++; +if (len >5 )/* max "65535" */ +return false; + } + +if (len ==0 ) +return false; + +/* reached limit while parsing port */ +if (dptr >= limit) +return false; + +if (p <1024 || p >65535 ) +return false; + +if (port) + *port =htons (p); + +if (endp) + *endp = dptr; + +return true; +} +/* skip ip address. returns its length. */ static int epaddr_len (const struct nf_conn *ct,const char *dptr,const char *limit,int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,return 0 ; } -/* Port number */ -if (*dptr ==':' ) { - dptr++; - dptr +=digits_len (ct, dptr, limit, shift); - } +if (!sip_parse_port (dptr, &dptr, limit,NULL )) +return 0 ;return dptr - aux; }
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,return epaddr_len (ct, dptr, limit, shift); } +/* simple_strtoul stops after first non-number character. +* But as we're not dealing with c-strings, we can't rely on +* hitting \r,\n,\0 etc. before moving past end of buffer. +* +* This is a variant of simple_strtoul, but doesn't require +* a c-string. +* +* If value exceeds UINT_MAX, 0 is returned. +*/ +static unsigned int sip_strtouint (const char *cp,unsigned int len,char **endp) +{ +const unsigned int max =sizeof ("4294967295" ); +unsigned int olen = len; +const char *s = cp; +u64 result =0 ; + +if (len > max) + len = max; + +while (olen >0 &&isdigit (*s)) { +unsigned int value; + +if (len ==0 ) + goto err; + + value = *s -'0' ; + result = result *10 + value; + +if (result >UINT_MAX ) + goto err; + s++; + len--; + olen--; + } + +if (endp) + *endp = (char *)s; + +return result; +err: +if (endp) + *endp = (char *)cp; +return 0 ; +} +/* Parse a SIP request line of the form: * * Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, {const char *start = dptr, *limit = dptr + datalen, *end;unsigned int mlen; -unsigned int p;int shift =0 ;/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,if (!sip_parse_addr (ct, dptr, &end, addr, limit, true))return -1 ; -if (end < limit && *end ==':' ) { - end++; - p =simple_strtoul (end, (char **)&end,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (end, &end, limit, port)) +return -1 ;if (end == dptr)return 0 ;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, union nf_inet_addr *addr, __be16 *port) { const char *c, *limit = dptr + datalen; -unsigned int p;int ret; ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,if (!sip_parse_addr (ct, dptr + *matchoff, &c, addr, limit, true))return -1 ; -if (*c ==':' ) { - c++; - p =simple_strtoul (c, (char **)&c,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (c, &c, limit, port)) +return -1 ;if (dataoff) *dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,return 0 ; start +=strlen (name); - *val =simple_strtoul (start, &end,0 ); + *val =sip_strtouint (start, limit - start, (char **)&end);if (start == end)return -1 ;if (matchoff && matchlen) {
@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff = sdpoff;for (i =0 ; i <ARRAY_SIZE (sdp_media_types); ) { +char *end; +if (ct_sip_get_sdp_header (ct, *dptr, mediaoff, *datalen,SDP_HDR_MEDIA ,SDP_HDR_UNSPEC , &mediaoff, &medialen) <=0 )
@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff += t->len; medialen -= t->len; - port =simple_strtoul (*dptr + mediaoff,NULL ,10 ); -if (port ==0 ) + port =sip_strtouint (*dptr + mediaoff, *datalen - mediaoff, (char **)&end); +if (port ==0 || *dptr + mediaoff == end)continue ;if (port <1024 || port >65535 ) {nf_ct_helper_log (skb, ct,"wrong port %u" , port);
@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,*/ if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL ); ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, SIP_HDR_CONTACT, NULL,
@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL );while (1 ) {unsigned int c_expires = expires;
@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,struct nf_conn *ct =nf_ct_get (skb, &ctinfo);unsigned int matchoff, matchlen, matchend;unsigned int code, cseq, i; +char *end;if (*datalen <strlen ("SIP/2.0 200" ))return NF_ACCEPT ; - code =simple_strtoul (*dptr +strlen ("SIP/2.0 " ),NULL ,10 ); + code =sip_strtouint (*dptr +strlen ("SIP/2.0 " ), + *datalen -strlen ("SIP/2.0 " ),NULL );if (!code) {nf_ct_helper_log (skb, ct,"cannot get code" );return NF_DROP ;
@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,for (i =0 ; i <ARRAY_SIZE (sip_handlers); i++) {const struct sip_handler *handler; +char *end; handler = &sip_handlers[i];if (handler->request ==NULL )
@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0)break ; - clen =simple_strtoul (dptr + matchoff, (char **)&end,10 ); + clen =sip_strtouint (dptr + matchoff, datalen - matchoff, (char **)&end);if (dptr + matchoff == end)break ;
net/netfilter/nf_nat_sip.c +1 -0
@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,if (ct_sip_parse_numerical_param (ct, *dptr, matchend, *datalen,"rport=" , &poff, &plen, &n) >0 && + n >=1024 && n <=65535 &&htons (n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&htons (n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 754/957 ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guilherme G. Piccoli <[email protected]>
[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ]
Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") introduced a change that "broke" Steam Deck's audio probe, in the OLED
model, as observed in the following dmesg snippet:
[...]snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not existsof_mach nau8821-max: ASoC: topology: could not load header: -22snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 sof_mach nau8821-max: ASoC: failed to instantiate card -22sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max)sof_mach nau8821-max: probe with driver sof_mach failed with error -22
[...]
Notice the quotes in "broke": it's not really a bug in such commit, but instead a problem with a topology file from Steam Deck OLED. This was discussed to great extent in [1], and Cristian proposed a pretty simple and functional change that resolved the issue for the Deck's issue. That change, though, would break other devices, so it wasn't accepted upstream. And the proper suggested solution (fix the topology) was never implemented, so Valve's kernel (and anyone that wants to boot the mainline on Steam Deck OLED) is carrying that fix downstream.
So, we propose hereby a different approach: a DMI quirk, as many already present in the sound drivers, to address this issue solely on Steam Deck OLED, not breaking other devices and as a bonus, allowing simple patch up in case eventually the topology file gets fixed (we'd just need to check against any DMI info reflecting that or the topology/FW versions).
The motivation of such upstream quirk is related to users that want to test latest kernel trees on their devices and get no only non-working sound device, but seems some games (like Ori and the Blind Forest) can't properly work without a proper functional audio device. Example of such report can be seen at [2].
--- sound/soc/amd/acp/acp-legacy-mach.c | 2 +- sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- sound/soc/amd/acp/acp-mach.h | 4 ++++ sound/soc/amd/acp/acp-sof-mach.c | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-)
sound/soc/amd/acp/acp-legacy-mach.c +1 -1
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; ret =acp_legacy_dai_links_create (card);
sound/soc/amd/acp/acp-mach-common.c +19 -3
@@ -20,6 +20,7 @@#include <sound/soc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/dmi.h> #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@#define NAU8821_FREQ_OUT 12288000#define MAX98388_CODEC_DAI "max98388-aif1" -#define TDM_MODE_ENABLE 1 -const struct dmi_system_id acp_quirk_table[] = { {/* Google skyrim proto-0 */ .matches = {DMI_EXACT_MATCH (DMI_PRODUCT_FAMILY ,"Google_Skyrim" ), }, - .driver_data = (void *)TDM_MODE_ENABLE , + .driver_data = (void *)QUIRK_TDM_MODE_ENABLE , + }, + { +/* Valve Steam Deck OLED */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Valve" ), +DMI_MATCH (DMI_PRODUCT_NAME ,"Galileo" ), + }, + .driver_data = (void *)QUIRK_REMAP_DMIC_BT , }, {} };
@@ -1385,6 +1392,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)struct snd_soc_dai_link *links;struct device *dev = card->dev;struct acp_card_drvdata *drv_data = card->drvdata; +const struct dmi_system_id *dmi_id =dmi_first_match (acp_quirk_table);int i =0 , num_links =0 ;if (drv_data->hs_cpu_id)
@@ -1556,6 +1564,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].codecs = &snd_soc_dummy_dlc; links[i].num_codecs =1 ; } + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) + links[i].id =DMIC_BE_ID ; i++; }
@@ -1571,6 +1582,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].capture_only =1 ; links[i].nonatomic = true; links[i].no_pcm =1 ; + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) { + links[i].id =BT_BE_ID ; +dev_dbg (dev,"quirk REMAP_DMIC_BT enabled\n" ); + } } card->dai_link = links;
sound/soc/amd/acp/acp-mach.h +4 -0
@@ -26,6 +26,10 @@#define acp_get_drvdata (card) ((struct acp_card_drvdata *)(card)->drvdata) +/* List of DMI quirks - check acp-mach-common.c for usage. */ +#define QUIRK_TDM_MODE_ENABLE 1 +#define QUIRK_REMAP_DMIC_BT 2 +enum be_id {HEADSET_BE_ID =0 ,AMP_BE_ID ,
sound/soc/amd/acp/acp-sof-mach.c +1 -1
@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) acp_card_drvdata = card->drvdata; dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 755/957 spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Madieu <[email protected]>
[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ]
rockchip_spi_isr() decides whether the current interrupt was the cs-inactive event by reading IMR:
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) ctlr->target_abort(ctlr);
IMR is the interrupt mask register: it tells which sources are enabled, not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true:
if (rs->cs_inactive) writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR);
so the IMR check is always true once cs_inactive is enabled, and every PIO interrupt - including normal RF_FULL completions - is dispatched to ctlr->target_abort(), aborting the transfer. The bug is reachable on ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller when the transfer is short enough to fall back to PIO (rockchip_spi_can_dma() returns false below fifo_len).
Read ISR (which is RISR masked by IMR) so the check actually reflects which interrupt fired, and parenthesise the expression for clarity while at it.
--- drivers/spi/spi-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-rockchip.c +2 -1
@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)struct rockchip_spi *rs =spi_controller_get_devdata (ctlr);/* When int_cs_inactive comes, spi target abort */ -if (rs->cs_inactive &&readl_relaxed (rs->regs +ROCKCHIP_SPI_IMR ) &INT_CS_INACTIVE ) { +if (rs->cs_inactive && + (readl_relaxed (rs->regs +ROCKCHIP_SPI_ISR ) &INT_CS_INACTIVE )) { ctlr->target_abort (ctlr);writel_relaxed (0 , rs->regs +ROCKCHIP_SPI_IMR );writel_relaxed (0xffffffff , rs->regs +ROCKCHIP_SPI_ICR );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 756/957 ASoC: tas2764: Mark die temp register as volatile
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Calligeros <[email protected]>
[ Upstream commit 4cfb5971c2fbfac061c23fb4224a3a008199de81 ]
Reading the temperature register always returns the first value read from the chip due to regcache.
Mark TAS2764_TEMP as volatile to prevent returning stale, cached values when reading the die temp.
--- sound/soc/codecs/tas2764.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/codecs/tas2764.c +1 -0
@@ -809,6 +809,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) {switch (reg) {case TAS2764_SW_RST : +case TAS2764_TEMP : case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:case TAS2764_INT_CLK_CFG :return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 757/957 ASoC: tas2770: Fix order of operations for temperature calculation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Calligeros <[email protected]>
[ Upstream commit c7ecb6a61908c2604dda6e42da66724d256de7b9 ]
The order of operations to derive the temperature from the temp register values was wrong, since 1000 / 16 is not an integer. This resulted in the calculated temperature value deviating from the value represented by the registers slightly, which was most obvious when the registers were zeroed (-92.265 *C vs the expected -93.000 *C).
Scale the reading before dividing the whole thing by 16 to correct this.
--- sound/soc/codecs/tas2770.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/tas2770.c +2 -2
@@ -549,7 +549,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)/* * As per datasheet: divide register by 16 and subtract 93 to get * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding -* errors by subtracting 93 * 16 then multiplying by 1000 / 16. +* errors by subtracting 93 * 16 and scaling before dividing. * * NOTE: The ADC registers are initialised to 0 on reset. This means * that the temperature will read -93 *C until the chip is brought out
@@ -558,7 +558,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)* value read back from its registers will be the last value sampled * before entering software shutdown. */ - *result = (reading - (93 *16 )) * (1000 /16 ); + *result = (reading - (93 *16 )) *1000 /16 ;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 758/957 drm/sysfb: ofdrm: fix PCI device reference leaks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ]
display_get_pci_dev_of() gets a referenced PCI device via pci_get_device(). Drop that reference when pci_enable_device() fails and release it during the managed teardown path after pci_disable_device().
Without that, ofdrm leaks the pci_dev reference on both the error path and the normal cleanup path.
--- drivers/gpu/drm/sysfb/ofdrm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sysfb/ofdrm.c +2 -0
@@ -349,6 +349,7 @@ static void ofdrm_pci_release(void *data)struct pci_dev *pcidev = data;pci_disable_device (pcidev); +pci_dev_put (pcidev); }static int ofdrm_device_init_pci (struct ofdrm_device *odev)
@@ -374,6 +375,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev)if (ret) {drm_err (dev,"pci_enable_device(%s) failed: %d\n" ,dev_name (&pcidev->dev), ret); +pci_dev_put (pcidev);return ret; } ret =devm_add_action_or_reset (&pdev->dev, ofdrm_pci_release, pcidev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 759/957 drm/color-mgmt: Typo s/R332/RGB332/
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit 9d5a2b8f6281f6090002517fb9272ea07038afe8 ]
Fix a typo of "RGB332" in kerneldoc for the drm_crtc_fill_palette_332() helper.
--- drivers/gpu/drm/drm_color_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/drm_color_mgmt.c +1 -1
@@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b, }/** -* drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats +* drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats * @crtc: The displaying CRTC * @set_palette: Callback for programming the hardware gamma LUT *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 760/957 arm64/scs: Fix potential sign extension issue of advance_loc4
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ]
The expression (*opcode++ << 24) and exp * code_alignment_factor may overflow signed int and becomes negative.
Fix this by casting each byte to u64 before shifting. Also fix the misaligned break statement while we are here.
Example of the result can be seen here:
It maybe not a real problem, but could be a issue in future.
--- arch/arm64/kernel/pi/patch-scs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/pi/patch-scs.c +2 -2
@@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, loc += *opcode++ * code_alignment_factor; loc += (*opcode++ <<8 ) * code_alignment_factor; loc += (*opcode++ <<16 ) * code_alignment_factor; - loc += (*opcode++ <<24 ) * code_alignment_factor; + loc += ((u64)*opcode++ <<24 ) * code_alignment_factor; size -=4 ; -break ; +break ;case DW_CFA_def_cfa:case DW_CFA_offset_extended:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 761/957 ACPICA: Provide #defines for EINJV2 error types
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Luck <[email protected]>
[ Upstream commit 1f6008538384453eb4c13a3d7ff9e37ee8aee6b9 ]
EINJV2 defined new error types by moving the severity (correctable, uncorrectable non-fatal, uncorrectable fatal) out of the "type".
ACPI 6.5 introduced EINJV2 and defined a vendor defined error type using bit 31. This was dropped in ACPI 6.6.
Stable-dep-of: 0c00cfbcfcff ("ACPI: APEI: EINJ: Fix EINJV2 memory error injection")
--- include/acpi/actbl1.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/acpi/actbl1.h +6 -0
@@ -1129,6 +1129,12 @@ enum acpi_einj_command_status {#define ACPI_EINJ_CXL_MEM_FATAL (1<<17)#define ACPI_EINJ_VENDOR_DEFINED (1<<31) +/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */ + +#define ACPI_EINJV2_PROCESSOR (1) +#define ACPI_EINJV2_MEMORY (1<<1) +#define ACPI_EINJV2_PCIE (1<<2) +/******************************************************************************* * * ERST - Error Record Serialization Table (ACPI 4.0)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 762/957 ACPI: APEI: EINJ: Fix EINJV2 memory error injection
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Luck <[email protected]>
[ Upstream commit 0c00cfbcfcffa7085e4f0c7fd7a4caada4e7a90f ]
Error types in EINJV2 use different bit positions for each flavor of injection from legacy EINJ.
Two issues:
1) The address sanity checks in einj_error_inject() were skipped for EINJV2 injections. Noted by sashiko[1]
2) __einj_error_trigger() failed to drop the entry of the target physical address from the list of resources that need to be requested.
Add a helper function that checks if an injection is to memory and use it to solve each of these issues.
Note that the old test in __einj_error_trigger() checked that param2 was not zero. This isn't needed because the sanity checks in einj_error_inject() reject memory injections with param2 == 0.
--- drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/acpi/apei/einj-core.c +25 -20
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(return NULL ; } + +static bool is_memory_injection (u32 type,u32 flags) +{ +if (flags &SETWA_FLAGS_EINJV2 ) +return !!(type &ACPI_EINJV2_MEMORY ); +if (type &ACPI5_VENDOR_BIT ) +return !!(vendor_flags &SETWA_FLAGS_MEM ); +return !!(type &MEM_ERROR_MASK ) || !!(flags &SETWA_FLAGS_MEM ); +} +/* Execute instructions in trigger error action table */ -static int __einj_error_trigger (u64 trigger_paddr,u32 type, +static int __einj_error_trigger (u64 trigger_paddr,u32 type,u32 flags,u64 param1,u64 param2) {struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,* This will cause resource conflict with regular memory. So * remove it from trigger table resources. */ -if ((param_extension || acpi5) && (type &MEM_ERROR_MASK ) && param2) { +if ((param_extension || acpi5) &&is_memory_injection (type, flags)) {struct apei_resources addr_resources;apei_resources_init (&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,return rc; trigger_paddr =apei_exec_ctx_get_output (&ctx);if (notrigger ==0 ) { - rc =__einj_error_trigger (trigger_paddr, type, param1, param2); + rc =__einj_error_trigger (trigger_paddr, type, flags, param1, param2);if (rc)return rc; }
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))return -EINVAL ; +/* +* Injections targeting a CXL 1.0/1.1 port have to be injected +* via the einj_cxl_rch_error_inject() path as that does the proper +* validation of the given RCRB base (MMIO) address. +*/ +if (einj_is_cxl_error_type (type) && (flags &SETWA_FLAGS_MEM )) +return -EINVAL ; +/* check if type is a valid EINJv2 error type */ if (is_v2) {if (!(type & available_error_type_v2))return -EINVAL ; } -/* -* We need extra sanity checks for memory errors. -* Other types leap directly to injection. -*/ /* ensure param1/param2 existed */ if (!(param_extension || acpi5)) goto inject; -/* ensure injection is memory related */ -if (type &ACPI5_VENDOR_BIT ) { -if (vendor_flags !=SETWA_FLAGS_MEM ) - goto inject; - }else if (!(type &MEM_ERROR_MASK ) && !(flags &SETWA_FLAGS_MEM )) { - goto inject; - } -/* -* Injections targeting a CXL 1.0/1.1 port have to be injected -* via the einj_cxl_rch_error_inject() path as that does the proper -* validation of the given RCRB base (MMIO) address. +* We need extra sanity checks for memory errors. +* Other types leap directly to injection. */ -if (einj_is_cxl_error_type (type) && (flags &SETWA_FLAGS_MEM )) -return -EINVAL ; +if (!is_memory_injection (type, flags)) + goto inject;/* * Disallow crazy address masks that give BIOS leeway to pick
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 763/957 cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daan De Meyer <[email protected]>
[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ]
The cdrom core never calls set_disk_ro() for a registered device, so BLKROGET on a CD-ROM device always returns 0 (writable), even when the drive has no write capabilities and writes will inevitably fail. This causes problems for userspace that relies on BLKROGET to determine whether a block device is read-only. For example, systemd's loop device setup uses BLKROGET to decide whether to create a loop device with LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the loop device to the CD-ROM and fail with I/O errors. systemd-fsck similarly checks BLKROGET to decide whether to run fsck in no-repair mode (-n).
The write-capability bits in cdi->mask come from two different sources:CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE SENSE capabilities page (page 0x2A) before register_cdrom() is called, while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command and were only probed by cdrom_open_write() at device open time. This meant that any attempt to compute the writable state from the full mask at probe time was incorrect, because the GET CONFIGURATION bits were still unset (and cdi->mask is initialized such that capabilities are assumed present).
Fix this by factoring the GET CONFIGURATION probing out of cdrom_open_write() into a new exported helper, cdrom_probe_write_features(), and having sr call it from sr_probe() right after get_capabilities() has populated the MODE SENSE bits. register_cdrom() then calls set_disk_ro() based on the full write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) so the block layer reflects the drive's actual write support. The feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with RT=00) report drive-level capabilities that are persistent across media, so a single probe before register_cdrom() is sufficient and the redundant probe at open time is dropped.
With set_disk_ro() now accurate, the long-vestigial cd->writeable flag in sr can go: get_capabilities() used to set cd->writeable based on the same four mask bits, but because CDC_MRW_W and CDC_RAM default to "capability present" in cdi->mask and aren't touched by MODE SENSE, the condition that gated cd->writeable was always true, making it unconditionally 1. Replace the corresponding gate in sr_init_command() with get_disk_ro(cd->disk), which turns a previously no-op check into a real one and also catches kernel-internal bio writers that bypass blkdev_write_iter()'s bdev_read_only() check.
The sd driver (SCSI disks) does not have this problem because it checks the MODE SENSE Write Protect bit and calls set_disk_ro() accordingly. The sr driver cannot use the same approach because the MMC specification does not define the WP bit in the MODE SENSE device-specific parameter byte for CD-ROM devices.
--- drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- drivers/scsi/sr.c | 11 ++----- drivers/scsi/sr.h | 1 - include/linux/cdrom.h | 1 + 4 files changed, 51 insertions(+), 35 deletions(-)
drivers/cdrom/cdrom.c +48 -25
@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)WARN_ON (!cdo->generic_packet); +/* +* Propagate the drive's write support to the block layer so BLKROGET +* reflects actual write capability. Drivers that use GET CONFIGURATION +* features (CDC_MRW_W, CDC_RAM) must have called +* cdrom_probe_write_features() before register_cdrom() so the mask is +* complete here. +*/ +set_disk_ro (disk, !CDROM_CAN (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM | +CDC_CD_RW )); +cd_dbg (CD_REG_UNREG ,"drive \"/dev/%s\" registered\n" , cdi->name);mutex_lock (&cdrom_mutex);list_add (&cdi->list, &cdrom_list);
@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)return 0 ; } +/* +* Probe write-related MMC features via GET CONFIGURATION and update +* cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE +* capabilities page (e.g. sr) should call this after those MODE SENSE bits +* have been set but before register_cdrom(), so that the full set of +* write-capability bits is known by the time register_cdrom() decides on the +* initial read-only state of the disk. +*/ +void cdrom_probe_write_features (struct cdrom_device_info *cdi) +{ +int mrw, mrw_write, ram_write; + + mrw =0 ; +if (!cdrom_is_mrw (cdi, &mrw_write)) + mrw =1 ; + +if (CDROM_CAN (CDC_MO_DRIVE )) + ram_write =1 ; +else + (void )cdrom_is_random_writable (cdi, &ram_write); + +if (mrw) + cdi->mask &= ~CDC_MRW ; +else + cdi->mask |=CDC_MRW ; + +if (mrw_write) + cdi->mask &= ~CDC_MRW_W ; +else + cdi->mask |=CDC_MRW_W ; + +if (ram_write) + cdi->mask &= ~CDC_RAM ; +else + cdi->mask |=CDC_RAM ; +} +EXPORT_SYMBOL (cdrom_probe_write_features); +static int cdrom_media_erasable (struct cdrom_device_info *cdi) {disc_information di;
@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)*/ static int cdrom_open_write (struct cdrom_device_info *cdi) { -int mrw, mrw_write, ram_write;int ret =1 ; - mrw =0 ; -if (!cdrom_is_mrw (cdi, &mrw_write)) - mrw =1 ; - -if (CDROM_CAN (CDC_MO_DRIVE )) - ram_write =1 ; -else - (void )cdrom_is_random_writable (cdi, &ram_write); - -if (mrw) - cdi->mask &= ~CDC_MRW ; -else - cdi->mask |=CDC_MRW ; - -if (mrw_write) - cdi->mask &= ~CDC_MRW_W ; -else - cdi->mask |=CDC_MRW_W ; - -if (ram_write) - cdi->mask &= ~CDC_RAM ; -else - cdi->mask |=CDC_RAM ; -if (CDROM_CAN (CDC_MRW_W )) ret =cdrom_mrw_open_write (cdi);else if (CDROM_CAN (CDC_DVD_RAM ))
drivers/scsi/sr.c +2 -9
@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)switch (req_op (rq)) {case REQ_OP_WRITE : -if (!cd->writeable) +if (get_disk_ro (cd->disk)) goto out; SCpnt->cmnd[0 ] =WRITE_10 ; cd->cdi.media_written =1 ;
@@ -681,6 +681,7 @@ static int sr_probe(struct device *dev) error = -ENOMEM ;if (get_capabilities (cd)) goto fail_minor; +cdrom_probe_write_features (&cd->cdi);sr_vendor_init (cd);set_capacity (disk, cd->capacity);
@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd)/*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ -/* -* if DVD-RAM, MRW-W or CD-RW, we are randomly writable -*/ -if ((cd->cdi.mask & (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) != - (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) { - cd->writeable =1 ; - } -kfree (buffer);return 0 ; }
drivers/scsi/sr.h +0 -1
@@ -35,7 +35,6 @@ typedef struct scsi_cd {struct scsi_device *device;unsigned int vendor;/* vendor code, see sr_vendor.c */ unsigned long ms_offset;/* for reading multisession-CD's */ - unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
include/linux/cdrom.h +1 -0
@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,extern unsigned int cdrom_check_events (struct cdrom_device_info *cdi,unsigned int clearing); +extern void cdrom_probe_write_features (struct cdrom_device_info *cdi);extern int register_cdrom (struct gendisk *disk,struct cdrom_device_info *cdi);extern void unregister_cdrom (struct cdrom_device_info *cdi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 764/957 netdevsim: zero initialize struct iphdr in dummy sk_buff
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikola Z. Ivanov <[email protected]>
[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ]
Syzbot reports a KMSAN uninit-value originating from nsim_dev_trap_skb_build, with the allocation also being performed in the same function.
Fix this by calling skb_put_zero instead of skb_put to guarantee zero initialization of the whole IP header.
--- drivers/net/netdevsim/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/netdevsim/dev.c +1 -1
@@ -773,7 +773,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) skb->protocol =htons (ETH_P_IP );skb_set_network_header (skb, skb->len); - iph =skb_put (skb,sizeof (struct iphdr )); + iph =skb_put_zero (skb,sizeof (struct iphdr )); iph->protocol =IPPROTO_UDP ; iph->saddr =in_aton ("192.0.2.1" ); iph->daddr =in_aton ("198.51.100.1" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 765/957 net/sched: netem: fix probability gaps in 4-state loss model
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ]
The 4-state Markov chain in loss_4state() has gaps at the boundaries between transition probability ranges. The comparisons use:
if (rnd < a4) else if (a4 < rnd && rnd < a1 + a4)
When rnd equals a boundary value exactly, neither branch matches and no state transition occurs. The redundant lower-bound check (a4 < rnd) is already implied by being in the else branch.
Remove the unnecessary lower-bound comparisons so the ranges are contiguous and every random value produces a transition, matching the GI (General and Intuitive) loss model specification.
This bug goes back to original implementation of this model.
--- net/sched/sch_netem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +4 -4
@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q)if (rnd < clg->a4) { clg->state =LOST_IN_GAP_PERIOD ;return true; - }else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { + }else if (rnd < clg->a1 + clg->a4) { clg->state =LOST_IN_BURST_PERIOD ;return true; - }else if (clg->a1 + clg->a4 < rnd) { + }else { clg->state =TX_IN_GAP_PERIOD ; }
@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q)case LOST_IN_BURST_PERIOD :if (rnd < clg->a3) clg->state =TX_IN_BURST_PERIOD ; -else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { +else if (rnd < clg->a2 + clg->a3) { clg->state =TX_IN_GAP_PERIOD ; - }else if (clg->a2 + clg->a3 < rnd) { + }else { clg->state =LOST_IN_BURST_PERIOD ;return true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 766/957 net/sched: netem: fix queue limit check to include reordered packets
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ]
The queue limit check in netem_enqueue() uses q->t_len which only counts packets in the internal tfifo. Packets placed in sch->q by the reorder path (__qdisc_enqueue_head) are not counted, allowing the total queue occupancy to exceed sch->limit under reordering.
Include sch->q.qlen in the limit check.
--- net/sched/sch_netem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_netem.c +1 -1
@@ -523,7 +523,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,1 <<get_random_u32_below (8 ); } -if (unlikely (q->t_len >= sch->limit)) { +if (unlikely (sch->q.qlen >= sch->limit)) {/* re-link segs, so that qdisc_drop_all() frees them all */ skb->next = segs;qdisc_drop_all (skb, sch, to_free);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 767/957 net/sched: netem: only reseed PRNG when seed is explicitly provided
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ]
netem_change() unconditionally reseeds the PRNG on every tc change command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed is generated, destroying reproducibility for users who set a deterministic seed on a previous change.
Move the initial random seed generation to netem_init() and only reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly provided by the user.
--- net/sched/sch_netem.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +6 -4
@@ -1111,11 +1111,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,/* capping jitter to the range acceptable by tabledist() */ q->jitter =min_t (s64,abs (q->jitter),INT_MAX ); -if (tb[TCA_NETEM_PRNG_SEED ]) +if (tb[TCA_NETEM_PRNG_SEED ]) { q->prng.seed =nla_get_u64 (tb[TCA_NETEM_PRNG_SEED ]); -else - q->prng.seed =get_random_u64 (); -prandom_seed_state (&q->prng.prng_state, q->prng.seed); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + } unlock:sch_tree_unlock (sch);
@@ -1138,6 +1137,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,return -EINVAL ; q->loss_model =CLG_RANDOM ; + q->prng.seed =get_random_u64 (); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + ret =netem_change (sch, opt, extack);if (ret)pr_info ("netem: change failed\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 768/957 net/sched: netem: validate slot configuration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ]
Reject slot configurations that have no defensible meaning:
- negative min_delay or max_delay
- min_delay greater than max_delay
- negative dist_delay or dist_jitter
- negative max_packets or max_bytes
Negative or out-of-order delays underflow in get_slot_next(), producing garbage intervals. Negative limits trip the per-slot accounting (packets_left/bytes_left <= 0) on the first packet of every slot, defeating the rate-limiting half of the slot feature.
Note that dist_jitter has been silently coerced to its absolute value by get_slot() since the feature was introduced; rejecting negatives here converts that silent coercion into -EINVAL. The abs() can be removed in a follow-up.
--- net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
net/sched/sch_netem.c +29 -0
@@ -826,6 +826,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) +{ +const struct tc_netem_slot *c =nla_data (attr); + +if (c->min_delay <0 || c->max_delay <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot delay" ); +return -EINVAL ; + } +if (c->min_delay > c->max_delay) { +NL_SET_ERR_MSG_ATTR (extack, attr,"slot min delay greater than max delay" ); +return -EINVAL ; + } +if (c->dist_delay <0 || c->dist_jitter <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative dist delay" ); +return -EINVAL ; + } +if (c->max_packets <0 || c->max_bytes <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot limit" ); +return -EINVAL ; + } +return 0 ; +} +static void get_slot (struct netem_sched_data *q,const struct nlattr *attr) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1039,6 +1062,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_SLOT ]) { + ret =validate_slot (tb[TCA_NETEM_SLOT ], extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 769/957 net/sched: netem: fix slot delay calculation overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ]
get_slot_next() computes a random delay between min_delay and max_delay using:
get_random_u32() * (max_delay - min_delay) >> 32
This overflows signed 64-bit arithmetic when the delay range exceeds approximately 2.1 seconds (2^31 nanoseconds), producing a negative result that effectively disables slot-based pacing. This is a realistic configuration for WAN emulation (e.g., slot 1s 5s).
Use mul_u64_u32_shr() which handles the widening multiply without overflow.
--- net/sched/sch_netem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/sched/sch_netem.c +2 -3
@@ -658,9 +658,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)if (!q->slot_dist) next_delay = q->slot_config.min_delay + - (get_random_u32 () * - (q->slot_config.max_delay - - q->slot_config.min_delay) >>32 ); +mul_u64_u32_shr (q->slot_config.max_delay - q->slot_config.min_delay, +get_random_u32 (),32 );else next_delay = tabledist(q->slot_config.dist_delay, (s32)(q->slot_config.dist_jitter),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 770/957 net/sched: netem: check for negative latency and jitter
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ]
Reject requests with negative latency or jitter.
A negative value added to current timestamp (u64) wraps
to an enormous time_to_send, disabling dequeue.
The original UAPI used u32 for these values; the conversion to 64-bit time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 allowed signed values to reach the kernel without validation.
Jitter is already silently clamped by an abs() in netem_change(); that abs() can be removed in a follow-up once this rejection is in place.
--- net/sched/sch_netem.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
net/sched/sch_netem.c +22 -0
@@ -825,6 +825,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_time (const struct nlattr *attr,const char *name, +struct netlink_ext_ack *extack) +{ +if (nla_get_s64 (attr) <0 ) { +NL_SET_ERR_MSG_ATTR_FMT (extack, attr,"negative %s" , name); +return -EINVAL ; + } +return 0 ; +} +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1067,6 +1077,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_LATENCY64 ]) { + ret =validate_time (tb[TCA_NETEM_LATENCY64 ],"latency" , extack); +if (ret) + goto table_free; + } + +if (tb[TCA_NETEM_JITTER64 ]) { + ret =validate_time (tb[TCA_NETEM_JITTER64 ],"jitter" , extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 771/957 net: airoha: stop net_device TX queue before updating CPU index
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 3854de7b38be742cf7558476956d12414cb274f2 ]
Currently, airoha_eth driver updates the CPU index register prior of verifying whether the number of free descriptors has fallen below the threshold.
Move net_device TX queue length check before updating the TX CPU index in order to update TX CPU index even if there are more packets to be transmitted but the net_device TX queue is going to be stopped accounting the inflight packets.
--- drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +4 -5
@@ -2111,17 +2111,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,skb_tx_timestamp (skb);netdev_tx_sent_queue (txq, skb->len); +if (q->ndesc - q->queued < q->free_thr) { +netif_tx_stop_queue (txq); + q->txq_stopped = true; + }if (netif_xmit_stopped (txq) || !netdev_xmit_more ())airoha_qdma_rmw (qdma,REG_TX_CPU_IDX (qid),TX_RING_CPU_IDX_MASK ,FIELD_PREP (TX_RING_CPU_IDX_MASK , index)); -if (q->ndesc - q->queued < q->free_thr) { -netif_tx_stop_queue (txq); - q->txq_stopped = true; - } -spin_unlock_bh (&q->lock);return NETDEV_TX_OK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 772/957 net: airoha: fix typo in function name
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengping Zhang <[email protected]>
[ Upstream commit aebf15e8eb09b01e99f043e9f5d423798aac9d32 ]
Corrected the typo in the function name from
airhoa_is_lan_gdm_port to airoha_is_lan_gdm_port. This change ensures consistency in the API naming convention.
Stable-dep-of: e070aac63b42 ("net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()")
--- drivers/net/ethernet/airoha/airoha_eth.c | 2 +- drivers/net/ethernet/airoha/airoha_eth.h | 2 +- drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +1 -1
@@ -76,7 +76,7 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)struct airoha_eth *eth = port->qdma->eth;u32 val, reg; - reg =airhoa_is_lan_gdm_port (port) ?REG_FE_LAN_MAC_H + reg =airoha_is_lan_gdm_port (port) ?REG_FE_LAN_MAC_H :REG_FE_WAN_MAC_H ; val = (addr[0 ] <<16 ) | (addr[1 ] <<8 ) | addr[2 ];airoha_fe_wr (eth, reg, val);
drivers/net/ethernet/airoha/airoha_eth.h +1 -1
@@ -627,7 +627,7 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);#define airoha_qdma_clear (qdma, offset, val) \ airoha_rmw((qdma)->regs, (offset), (val), 0) -static inline bool airhoa_is_lan_gdm_port (struct airoha_gdm_port *port) +static inline bool airoha_is_lan_gdm_port (struct airoha_gdm_port *port) {/* GDM1 port on EN7581 SoC is connected to the lan dsa switch. * GDM{2,3,4} can be used as wan port connected to an external
drivers/net/ethernet/airoha/airoha_ppe.c +1 -1
@@ -331,7 +331,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,/* For downlink traffic consume SRAM memory for hw * forwarding descriptors queue. */ -if (airhoa_is_lan_gdm_port (port)) +if (airoha_is_lan_gdm_port (port)) val |=AIROHA_FOE_IB2_FAST_PATH ;if (dsa_port >=0 ) val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 773/957 net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit e070aac63b42bf81f4dc565f9f841ff47e6c992f ]
Do not wake every netdev TX queue across all ports sharing the QDMA running netif_tx_wake_all_queues routine in airoha_qdma_wake_netdev_txqs() but only the ones that are mapped the specific QDMA stopped hw TX queue. This patch can potentially avoid waking already stopped netdev TX queues that are mapped to a different QDMA hw TX queue.
Introduce airoha_qdma_get_txq utility routine.
--- drivers/net/ethernet/airoha/airoha_eth.c | 19 +++++++++++++++---- drivers/net/ethernet/airoha/airoha_eth.h | 5 +++++ 2 files changed, 20 insertions(+), 4 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +15 -4
@@ -878,13 +878,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) {struct airoha_qdma *qdma = q->qdma;struct airoha_eth *eth = qdma->eth; -int i; +int i, qid = q - &qdma->q_tx[0 ];for (i =0 ; i <ARRAY_SIZE (eth->ports); i++) {struct airoha_gdm_port *port = eth->ports[i]; +int j; + +if (!port) +continue ; -if (port && port->qdma == qdma) -netif_tx_wake_all_queues (port->dev); +if (port->qdma != qdma) +continue ; + +for (j =0 ; j < port->dev->num_tx_queues; j++) { +if (airoha_qdma_get_txq (qdma, j) != qid) +continue ; + +netif_wake_subqueue (port->dev, j); + } } q->txq_stopped = false; }
@@ -2018,7 +2029,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,u16 index;u8 fport; - qid =skb_get_queue_mapping (skb) %ARRAY_SIZE (qdma->q_tx); + qid =airoha_qdma_get_txq (qdma,skb_get_queue_mapping (skb)); tag =airoha_get_dsa_tag (skb, dev); msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
drivers/net/ethernet/airoha/airoha_eth.h +5 -0
@@ -627,6 +627,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);#define airoha_qdma_clear (qdma, offset, val) \ airoha_rmw((qdma)->regs, (offset), (val), 0) +static inline u16 airoha_qdma_get_txq (struct airoha_qdma *qdma,u16 qid) +{ +return qid %ARRAY_SIZE (qdma->q_tx); +} +static inline bool airoha_is_lan_gdm_port (struct airoha_gdm_port *port) {/* GDM1 port on EN7581 SoC is connected to the lan dsa switch.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 774/957 net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit bde34e84edc8b5571fbde7e941e175a4293ee1eb ]
The transmit loop in airoha_dev_xmit() reads fragment address and length during its final iteration, when the loop index equals skb_shinfo(skb)->nr_frags, at which point the fragment data is uninitialized. While these values are never consumed, the read itself is unsafe and may trigger a page fault. Fix this by avoiding the fragment read on the last iteration.
Additionally, move the skb pointer from the first to the last used packet descriptor, so that airoha_qdma_tx_napi_poll() defers freeing the skb until the final descriptor is processed.
--- drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +6 -3
@@ -2024,8 +2024,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,struct netdev_queue *txq;struct airoha_queue *q;LIST_HEAD (tx_list); +int i =0 , qid;void *data; -int i, qid;u16 index;u8 fport;
@@ -2084,7 +2084,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, list); index = e - q->entry; -for (i =0 ; i < nr_frags; i++) { +while (true) {struct airoha_qdma_desc *desc = &q->desc[index];skb_frag_t *frag = &skb_shinfo (skb)->frags[i];dma_addr_t addr;
@@ -2096,7 +2096,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, goto error_unmap;list_move_tail (&e->list, &tx_list); - e->skb = i ?NULL : skb; + e->skb = i == nr_frags -1 ? skb :NULL ; e->dma_addr = addr; e->dma_len = len;
@@ -2115,6 +2115,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,WRITE_ONCE (desc->msg1,cpu_to_le32 (msg1));WRITE_ONCE (desc->msg2,cpu_to_le32 (0xffff )); +if (++i == nr_frags) +break ; + data =skb_frag_address (frag); len =skb_frag_size (frag); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 775/957 net/sched: sch_choke: annotate data-races in choke_dump_stats()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ]
choke_dump_stats() only runs with RTNL held. It reads fields that can be changed in qdisc fast path. Add READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_choke.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
net/sched/sch_choke.c +16 -10
@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* Draw a packet at random from queue and compare flow */ if (choke_match_random (q, skb, &idx)) { - q->stats.matched++; +WRITE_ONCE (q->stats.matched, q->stats.matched +1 );choke_drop_by_idx (sch, idx, to_free); goto congestion_drop; }
@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (use_harddrop (q) || !use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; } - q->stats.forced_mark++; +WRITE_ONCE (q->stats.forced_mark, + q->stats.forced_mark +1 ); }else if (++q->vars.qcount) {if (red_mark_probability (p, &q->vars, q->vars.qavg)) { q->vars.qcount =0 ;
@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (!use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; } - q->stats.prob_mark++; +WRITE_ONCE (q->stats.prob_mark, + q->stats.prob_mark +1 ); } }else q->vars.qR =red_random (p);
@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,return NET_XMIT_SUCCESS ; } - q->stats.pdrop++; +WRITE_ONCE (q->stats.pdrop, q->stats.pdrop +1 );return qdisc_drop (skb, sch, to_free); congestion_drop:
@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct choke_sched_data *q =qdisc_priv (sch);struct tc_choke_xstats st = { - .early = q->stats.prob_drop + q->stats.forced_drop, - .marked = q->stats.prob_mark + q->stats.forced_mark, - .pdrop = q->stats.pdrop, - .matched = q->stats.matched, + .early =READ_ONCE (q->stats.prob_drop) + +READ_ONCE (q->stats.forced_drop), + .marked =READ_ONCE (q->stats.prob_mark) + +READ_ONCE (q->stats.forced_mark), + .pdrop =READ_ONCE (q->stats.pdrop), + .matched =READ_ONCE (q->stats.matched), };return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 776/957 net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ]
fq_codel_dump_stats() acquires the qdisc spinlock a bit too late.
Move this acquisition before we fill tc_fq_pie_xstats with live data.
Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, but the spinlock is needed anyway to scan q->new_flows and q->old_flows.
--- net/sched/sch_fq_pie.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
net/sched/sch_fq_pie.c +10 -9
@@ -510,18 +510,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb)static int fq_pie_dump_stats (struct Qdisc *sch,struct gnet_dump *d) {struct fq_pie_sched_data *q =qdisc_priv (sch); -struct tc_fq_pie_xstats st = { - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .overmemory = q->overmemory, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, - .new_flow_count = q->new_flow_count, - .memory_usage = q->memory_usage, - }; +struct tc_fq_pie_xstats st = {0 };struct list_head *pos;sch_tree_lock (sch); + + st.packets_in = q->stats.packets_in; + st.overlimit = q->stats.overlimit; + st.overmemory = q->overmemory; + st.dropped = q->stats.dropped; + st.ecn_mark = q->stats.ecn_mark; + st.new_flow_count = q->new_flow_count; + st.memory_usage = q->memory_usage; +list_for_each (pos, &q->new_flows) st.new_flows_len++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 777/957 vrf: Fix a potential NPD when removing a port from a VRF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ]
RCU readers that identified a net device as a VRF port using netif_is_l3_slave() assume that a subsequent call to netdev_master_upper_dev_get_rcu() will return a VRF device. They then continue to dereference its l3mdev operations.
This assumption is not always correct and can result in a NPD [1]. There is no RCU synchronization when removing a port from a VRF, so it is possible for an RCU reader to see a new master device (e.g., a bridge) that does not have l3mdev operations.
Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE flag. Skip this synchronization when a net device is removed from a VRF as part of its deletion and when the VRF device itself is deleted. In the latter case an RCU grace period will pass by the time RTNL is released.
[1]
BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) [...] Call Trace: <TASK> l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) __inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) inet_bind_sk (net/ipv4/af_inet.c:469) __sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) __x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1))
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
--- drivers/net/vrf.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/net/vrf.c +11 -4
@@ -1084,6 +1084,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, err: port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +synchronize_net ();return ret; }
@@ -1103,10 +1104,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, }/* inverse of do_vrf_add_slave */ -static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev) +static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev, +bool needs_sync) {netdev_upper_dev_unlink (port_dev, dev); port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +/* Make sure that concurrent RCU readers that identified the device +* as a VRF port see a VRF master or no master at all. +*/ +if (needs_sync) +synchronize_net ();cycle_netdev (port_dev,NULL );
@@ -1115,7 +1122,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)static int vrf_del_slave (struct net_device *dev,struct net_device *port_dev) { -return do_vrf_del_slave (dev, port_dev); +return do_vrf_del_slave (dev, port_dev, true); }static void vrf_dev_uninit (struct net_device *dev)
@@ -1669,7 +1676,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head)struct list_head *iter;netdev_for_each_lower_dev (dev, port_dev, iter) -vrf_del_slave (dev, port_dev); +do_vrf_del_slave (dev, port_dev, false);vrf_map_unregister_dev (dev);
@@ -1801,7 +1808,7 @@ static int vrf_device_event(struct notifier_block *unused, goto out; vrf_dev =netdev_master_upper_dev_get (dev); -vrf_del_slave (vrf_dev, dev); +do_vrf_del_slave (vrf_dev, dev, false); } out:return NOTIFY_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 778/957 net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Jun <[email protected]>
[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ]
syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() when accessing skb->len for tx statistics after usb_submit_urb() has been called:
BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760
drivers/net/usb/rtl8150.c:712
Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226The URB completion handler write_bulk_callback() frees the skb via dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU in softirq context before usb_submit_urb() returns in the submitter, so by the time the submitter reads skb->len the skb has already been queued to the per-CPU completion_queue and freed by net_tx_action():
CPU A (xmit) CPU B (USB completion softirq)
------------ ------------------------------
dev->tx_skb = skb;
usb_submit_urb() --+
|-------> write_bulk_callback()
| dev_kfree_skb_irq(dev->tx_skb)
| net_tx_action()
| napi_skb_cache_put() <-- free
netdev->stats.tx_bytes |
+= skb->len; <-- UAF readFix it by caching skb->len before submitting the URB and using the cached value when updating the tx_bytes counter.
The pre-existing tx_bytes semantics are preserved: the counter tracks the original frame length (skb->len), not the ETH_ZLEN/USB-alignment padded "count" value that is handed to the device. Changing that would be a user-visible accounting change and is out of scope for this UAF fix.
--- drivers/net/usb/rtl8150.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/usb/rtl8150.c +4 -1
@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) {rtl8150_t *dev =netdev_priv (netdev); +unsigned int skb_len;int count, res;/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,return NETDEV_TX_OK ; } + skb_len = skb->len; +netif_stop_queue (netdev); dev->tx_skb = skb; usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, } }else { netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; + netdev->stats.tx_bytes += skb_len;netif_trans_update (netdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 779/957 net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <[email protected]>
[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ]
When rtl8150_start_xmit() fails to submit the tx URB, the URB is never handed to the USB core and write_bulk_callback() will not run. The driver returns NETDEV_TX_OK, which tells the networking stack that the skb has been consumed, but nothing actually frees the skb on this error path:
dev->tx_skb = skb;
...
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
...
/* no kfree_skb here */
}
return NETDEV_TX_OK;This leaks the skb on every submit failure and also leaves dev->tx_skb pointing at memory that the driver itself may later free, which is fragile.
Free the skb with dev_kfree_skb_any() in the error path and clear dev->tx_skb so no stale pointer is left behind.
--- drivers/net/usb/rtl8150.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/usb/rtl8150.c +7 -0
@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, netdev->stats.tx_errors++;netif_start_queue (netdev); } +/* +* The URB was not submitted, so write_bulk_callback() will +* never run to free dev->tx_skb. Drop the skb here and +* clear tx_skb to avoid leaving a stale pointer. +*/ + dev->tx_skb =NULL ; +dev_kfree_skb_any (skb); }else { netdev->stats.tx_packets++; netdev->stats.tx_bytes += skb_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 780/957 spi: amlogic-spisg: initialize completion before requesting IRQ
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 8d0189c1ea98b56481eb809e3d1bdbf85557e819 ]
Move init_completion(&spisg->completion) to before devm_request_irq() to avoid a potential race condition where an interrupt could fire before the completion structure is initialized.
--- drivers/spi/spi-amlogic-spisg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/spi/spi-amlogic-spisg.c +1 -2
@@ -795,6 +795,7 @@ static int aml_spisg_probe(struct platform_device *pdev)dma_set_max_seg_size (&pdev->dev,SPISG_BLOCK_MAX ); +init_completion (&spisg->completion); ret =devm_request_irq (&pdev->dev, irq, aml_spisg_irq,0 ,NULL , spisg);if (ret) {dev_err (&pdev->dev,"irq request failed\n" );
@@ -807,8 +808,6 @@ static int aml_spisg_probe(struct platform_device *pdev) goto out_clk; } -init_completion (&spisg->completion); -pm_runtime_put (&spisg->pdev->dev);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 781/957 NFC: trf7970a: Ignore antenna noise when checking for RF field
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Geurts <[email protected]>
[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ]
The main channel Received Signal Strength Indicator (RSSI) measurement is used to determine whether an RF field is present or not. RSSI != 0 is interpreted as an RF Field is present. This does not take RF noise and measurement inaccuracy into account, and results in false positives in the field.
Define a noise level and make sure the RF field is only interpreted as present when the RSSI is above the noise level.
--- drivers/nfc/trf7970a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/nfc/trf7970a.c +2 -1
@@ -317,6 +317,7 @@#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) +#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)if (ret)return ret; -if (rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) +if ((rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) >TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL ) *is_rf_field = true;else *is_rf_field = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 782/957 net/sched: taprio: fix NULL pointer dereference in class dump
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ]
When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. Subsequent RTM_GETTCLASS dump operations walk all classes via taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() returning the NULL pointer, then dereferences it to read child->handle, causing a kernel NULL pointer dereference.
The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user namespaces enabled, an unprivileged local user can trigger a kernel panic by creating a taprio qdisc inside a new network namespace, grafting an explicit child qdisc, deleting it, and requesting a class dump. The RTM_GETTCLASS dump itself requires no capability.
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) Call Trace: <TASK> tc_fill_tclass (net/sched/sch_api.c:1966) qdisc_class_dump (net/sched/sch_api.c:2326) taprio_walk (net/sched/sch_taprio.c:2514) tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) tc_dump_tclass_root (net/sched/sch_api.c:2370) tc_dump_tclass (net/sched/sch_api.c:2431) rtnl_dumpit (net/core/rtnetlink.c:6864) netlink_dump (net/netlink/af_netlink.c:2325) rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Fix this by substituting &noop_qdisc when new is NULL in taprio_graft(), a common pattern used by other qdiscs (e.g., multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. This makes control-plane dump paths safe without requiring individual NULL checks.
Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) previously had explicit NULL guards that would drop/skip the packet cleanly, update those checks to test for &noop_qdisc instead. Without this, packets would reach taprio_enqueue_one() which increments the root qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc drops the packet but those counters are never rolled back, permanently inflating the root qdisc's statistics.
After this change *old can be a valid qdisc, NULL, or &noop_qdisc. Only call qdisc_put(*old) in the first case to avoid decreasing noop_qdisc's refcount, which was never increased.
--- net/sched/sch_taprio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
net/sched/sch_taprio.c +8 -5
@@ -633,7 +633,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, queue =skb_get_queue_mapping (skb); child = q->qdiscs[queue]; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return qdisc_drop (skb, sch, to_free);if (taprio_skb_exceeds_queue_max_sdu (sch, skb)) {
@@ -716,7 +716,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,int len;u8 tc; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return NULL ;if (TXTIME_ASSIST_IS_ENABLED (q->flags))
@@ -2185,6 +2185,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,if (!dev_queue)return -EINVAL ; +if (!new) + new = &noop_qdisc; +if (dev->flags &IFF_UP )dev_deactivate (dev);
@@ -2198,14 +2201,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, *old = q->qdiscs[cl -1 ];if (FULL_OFFLOAD_IS_ENABLED (q->flags)) {WARN_ON_ONCE (dev_graft_qdisc (dev_queue, new) != *old); -if (new) +if (new != &noop_qdisc)qdisc_refcount_inc (new); -if (*old) +if (*old && *old != &noop_qdisc)qdisc_put (*old); } q->qdiscs[cl -1 ] = new; -if (new) +if (new != &noop_qdisc) new->flags |=TCQ_F_ONETXQUEUE |TCQ_F_NOPARENT ;if (dev->flags &IFF_UP )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 783/957 neigh: let neigh_xmit take skb ownership
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ]
neigh_xmit always releases the skb, except when no neighbour table is found. But even the first added user of neigh_xmit (mpls) relied on neigh_xmit to release the skb (or queue it for tx).
sashiko reported:
If neigh_xmit() is called with an uninitialized neighbor table (for example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT and bypasses its internal out_kfree_skb error path. Because the return value of neigh_xmit() is ignored here, does this leak the SKB?
Assume full ownership and remove the last code path that doesn't xmit or free skb.
--- net/core/neighbour.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/neighbour.c +5 -5
@@ -3182,8 +3182,10 @@ int neigh_xmit(int index, struct net_device *dev,rcu_read_lock (); tbl =rcu_dereference (neigh_tables[index]); -if (!tbl) - goto out_unlock; +if (!tbl) { +rcu_read_unlock (); + goto out_kfree_skb; + }if (index ==NEIGH_ARP_TABLE ) {u32 key = *((u32 *)addr);
@@ -3199,7 +3201,6 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; } err =READ_ONCE (neigh->output)(neigh, skb); -out_unlock:rcu_read_unlock (); }else if (index ==NEIGH_LINK_TABLE ) {
@@ -3209,11 +3210,10 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; err =dev_queue_xmit (skb); } -out:return err; out_kfree_skb:kfree_skb (skb); - goto out; +return err; }EXPORT_SYMBOL (neigh_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 784/957 tcp: make probe0 timer handle expired user timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Altan Hacigumus <[email protected]>
[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ]
tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies using subtraction with an unsigned lvalue. If elapsed probing time exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large value.
This ends up re-arming the probe timer for a full backoff interval instead of expiring immediately, delaying connection teardown beyond the configured timeout.
Fix this by preventing underflow so user-set timeout expiration is handled correctly without extending the probe timer.
--- net/ipv4/tcp_timer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp_timer.c +3 -2
@@ -49,7 +49,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)u32 tcp_clamp_probe0_to_user_timeout (const struct sock *sk,u32 when) {const struct inet_connection_sock *icsk =inet_csk (sk); -u32 remaining, user_timeout; +u32 user_timeout; +s32 remaining;s32 elapsed; user_timeout =READ_ONCE (icsk->icsk_user_timeout);
@@ -60,7 +61,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)if (unlikely (elapsed <0 )) elapsed =0 ; remaining =msecs_to_jiffies (user_timeout) - elapsed; - remaining =max_t (u32, remaining,TCP_TIMEOUT_MIN ); + remaining =max_t (int, remaining,TCP_TIMEOUT_MIN );return min_t (u32, remaining, when); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 785/957 netpoll: fix IPv6 local-address corruption
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ]
netpoll_setup() decides whether to auto-populate the local source address by testing np->local_ip.ip, which only inspects the first 4 bytes of the union inet_addr storage.
For an IPv6 netpoll whose caller-supplied local address has a zero high-32 bits (::1, ::<suffix>, IPv4-mapped ::ffff:a.b.c.d, etc.), this misdetects the address as unset (which they are not, but the first 4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with whatever matching link-local/global address the device happens to expose first.
Introduce a helper netpoll_local_ip_unset() that picks the correct family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it from netpoll_setup().
Reproducer is something like:
echo "::2" > local_ip
echo 1 > enabled
cat local_ip
# before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) # after this fix: ::2
--- net/core/netpoll.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
net/core/netpoll.c +18 -1
@@ -706,6 +706,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)return 0 ; } +/* +* Test whether the caller left np->local_ip unset, so that +* netpoll_setup() should auto-populate it from the egress device. +* +* np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), +* so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, +* IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — +* doing so would misclassify a caller-supplied address as unset and +* silently overwrite it with whatever address the device exposes. +*/ +static bool netpoll_local_ip_unset (const struct netpoll *np) +{ +if (np->ipv6) +return ipv6_addr_any (&np->local_ip.in6); +return !np->local_ip.ip; +} +int netpoll_setup (struct netpoll *np) {struct net *net = current->nsproxy->net_ns;
@@ -750,7 +767,7 @@ int netpoll_setup(struct netpoll *np)rtnl_lock (); } -if (!np->local_ip.ip) { +if (netpoll_local_ip_unset (np)) {if (!np->ipv6) { err =netpoll_take_ipv4 (np, ndev);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 786/957 ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ]
At parsing UAC3 streams, we allocate a PD object at each time, and either assign or free it. But there is a case where the PD object may be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an audioformat shares the same endpoint with others, it's put to a link and returns from snd_usb_add_audio_stream(), but the PD is forgotten afterwards. Overall, the treatment of PD object in the parser code is a bit flaky, and we should be more careful about the object ownership.
This patch tries to fix the above case and improve the code a bit. The pd object is now managed with the auto-cleanup in the loop, and the ownership is updated when the pd object gets assigned to the stream, which guarantees the release of the leftover object.
--- sound/usb/quirks.c | 2 +- sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- sound/usb/stream.h | 3 ++- 3 files changed, 25 insertions(+), 38 deletions(-)
sound/usb/quirks.c +1 -1
@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,snd_usb_audioformat_set_sync_ep (chip, fp); - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream, fp,NULL );if (err <0 )return err;
sound/usb/stream.c +22 -36
129 lines not on this page · raw message
sound/usb/stream.h +2 -1
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,int snd_usb_add_audio_stream (struct snd_usb_audio *chip,int stream, -struct audioformat *fp); +struct audioformat *fp, +struct snd_usb_power_domain **pdptr);#endif /* __USBAUDIO_STREAM_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 787/957 sched/fair: Reimplement NEXT_BUDDY to align with EEVDF goals
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mel Gorman <[email protected]>
[ Upstream commit e837456fdca81899a3c8e47b3fd39e30eae6e291 ]
Reimplement NEXT_BUDDY preemption to take into account the deadline and eligibility of the wakee with respect to the waker. In the event multiple buddies could be considered, the one with the earliest deadline is selected.
Sync wakeups are treated differently to every other type of wakeup. The WF_SYNC assumption is that the waker promises to sleep in the very near future. This is violated in enough cases that WF_SYNC should be treated as a suggestion instead of a contract. If a waker does go to sleep almost immediately then the delay in wakeup is negligible. In other cases, it's throttled based on the accumulated runtime of the waker so there is a chance that some batched wakeups have been issued before preemption.
For all other wakeups, preemption happens if the wakee has a earlier deadline than the waker and eligible to run.
While many workloads were tested, the two main targets were a modified dbench4 benchmark and hackbench because the are on opposite ends of the spectrum -- one prefers throughput by avoiding preemption and the other relies on preemption.
First is the dbench throughput data even though it is a poor metric but it is the default metric. The test machine is a 2-socket machine and the backing filesystem is XFS as a lot of the IO work is dispatched to kernel threads. It's important to note that these results are not representative across all machines, especially Zen machines, as different bottlenecks are exposed on different machines and filesystems.
dbench4 Throughput (misleading but traditional)
6.18-rc1 6.18-rc1
vanilla sched-preemptnext-v5
Hmean 1 1268.80 ( 0.00%) 1269.74 ( 0.07%)
Hmean 4 3971.74 ( 0.00%) 3950.59 ( -0.53%)
Hmean 7 5548.23 ( 0.00%) 5420.08 ( -2.31%)
Hmean 12 7310.86 ( 0.00%) 7165.57 ( -1.99%)
Hmean 21 8874.53 ( 0.00%) 9149.04 ( 3.09%)
Hmean 30 9361.93 ( 0.00%) 10530.04 ( 12.48%)
Hmean 48 9540.14 ( 0.00%) 11820.40 ( 23.90%)
Hmean 79 9208.74 ( 0.00%) 12193.79 ( 32.42%)
Hmean 110 8573.12 ( 0.00%) 11933.72 ( 39.20%)
Hmean 141 7791.33 ( 0.00%) 11273.90 ( 44.70%)
Hmean 160 7666.60 ( 0.00%) 10768.72 ( 40.46%)As throughput is misleading, the benchmark is modified to use a short loadfile report the completion time duration in milliseconds.
dbench4 Loadfile Execution Time
6.18-rc1 6.18-rc1
vanilla sched-preemptnext-v5
Amean 1 14.62 ( 0.00%) 14.69 ( -0.46%)
Amean 4 18.76 ( 0.00%) 18.85 ( -0.45%)
Amean 7 23.71 ( 0.00%) 24.38 ( -2.82%)
Amean 12 31.25 ( 0.00%) 31.87 ( -1.97%)
Amean 21 45.12 ( 0.00%) 43.69 ( 3.16%)
Amean 30 61.07 ( 0.00%) 54.33 ( 11.03%)
Amean 48 95.91 ( 0.00%) 77.22 ( 19.49%)
Amean 79 163.38 ( 0.00%) 123.08 ( 24.66%)
Amean 110 243.91 ( 0.00%) 175.11 ( 28.21%)
Amean 141 343.47 ( 0.00%) 239.10 ( 30.39%)
Amean 160 401.15 ( 0.00%) 283.73 ( 29.27%)
Stddev 1 0.52 ( 0.00%) 0.51 ( 2.45%)
Stddev 4 1.36 ( 0.00%) 1.30 ( 4.04%)
Stddev 7 1.88 ( 0.00%) 1.87 ( 0.72%)
Stddev 12 3.06 ( 0.00%) 2.45 ( 19.83%)
Stddev 21 5.78 ( 0.00%) 3.87 ( 33.06%)
Stddev 30 9.85 ( 0.00%) 5.25 ( 46.76%)
Stddev 48 22.31 ( 0.00%) 8.64 ( 61.27%)
Stddev 79 35.96 ( 0.00%) 18.07 ( 49.76%)
Stddev 110 59.04 ( 0.00%) 30.93 ( 47.61%)
Stddev 141 85.38 ( 0.00%) 40.93 ( 52.06%)
Stddev 160 96.38 ( 0.00%) 39.72 ( 58.79%)That is still looking good and the variance is reduced quite a bit. Finally, fairness is a concern so the next report tracks how many milliseconds does it take for all clients to complete a workfile. This one is tricky because dbench makes to effort to synchronise clients so the durations at benchmark start time differ substantially from typical runtimes. This problem could be mitigated by warming up the benchmark for a number of minutes but it's a matter of opinion whether that counts as an evasion of inconvenient results.
dbench4 All Clients Loadfile Execution Time
6.18-rc1 6.18-rc1
vanilla sched-preemptnext-v5
Amean 1 15.06 ( 0.00%) 15.07 ( -0.03%)
Amean 4 603.81 ( 0.00%) 524.29 ( 13.17%)
Amean 7 855.32 ( 0.00%) 1331.07 ( -55.62%)
Amean 12 1890.02 ( 0.00%) 2323.97 ( -22.96%)
Amean 21 3195.23 ( 0.00%) 2009.29 ( 37.12%)
Amean 30 13919.53 ( 0.00%) 4579.44 ( 67.10%)
Amean 48 25246.07 ( 0.00%) 5705.46 ( 77.40%)
Amean 79 29701.84 ( 0.00%) 15509.26 ( 47.78%)
Amean 110 22803.03 ( 0.00%) 23782.08 ( -4.29%)
Amean 141 36356.07 ( 0.00%) 25074.20 ( 31.03%)
Amean 160 17046.71 ( 0.00%) 13247.62 ( 22.29%)
Stddev 1 0.47 ( 0.00%) 0.49 ( -3.74%)
Stddev 4 395.24 ( 0.00%) 254.18 ( 35.69%)
Stddev 7 467.24 ( 0.00%) 764.42 ( -63.60%)
Stddev 12 1071.43 ( 0.00%) 1395.90 ( -30.28%)
Stddev 21 1694.50 ( 0.00%) 1204.89 ( 28.89%)
Stddev 30 7945.63 ( 0.00%) 2552.59 ( 67.87%)
Stddev 48 14339.51 ( 0.00%) 3227.55 ( 77.49%)
Stddev 79 16620.91 ( 0.00%) 8422.15 ( 49.33%)
Stddev 110 12912.15 ( 0.00%) 13560.95 ( -5.02%)
Stddev 141 20700.13 ( 0.00%) 14544.51 ( 29.74%)
Stddev 160 9079.16 ( 0.00%) 7400.69 ( 18.49%)This is more of a mixed bag but it at least shows that fairness is not crippled.
The hackbench results are more neutral but this is still important. It's possible to boost the dbench figures by a large amount but only by crippling the performance of a workload like hackbench. The WF_SYNC behaviour is important for these workloads and is why the WF_SYNC changes are not a separate patch.
hackbench-process-pipes
6.18-rc1 6.18-rc1
vanilla sched-preemptnext-v5
Amean 1 0.2657 ( 0.00%) 0.2150 ( 19.07%)
Amean 4 0.6107 ( 0.00%) 0.6060 ( 0.76%)
Amean 7 0.7923 ( 0.00%) 0.7440 ( 6.10%)
Amean 12 1.1500 ( 0.00%) 1.1263 ( 2.06%)
Amean 21 1.7950 ( 0.00%) 1.7987 ( -0.20%)
Amean 30 2.3207 ( 0.00%) 2.5053 ( -7.96%)
Amean 48 3.5023 ( 0.00%) 3.9197 ( -11.92%)
Amean 79 4.8093 ( 0.00%) 5.2247 ( -8.64%)
Amean 110 6.1160 ( 0.00%) 6.6650 ( -8.98%)
Amean 141 7.4763 ( 0.00%) 7.8973 ( -5.63%)
Amean 172 8.9560 ( 0.00%) 9.3593 ( -4.50%)
Amean 203 10.4783 ( 0.00%) 10.8347 ( -3.40%)
Amean 234 12.4977 ( 0.00%) 13.0177 ( -4.16%)
Amean 265 14.7003 ( 0.00%) 15.5630 ( -5.87%)
Amean 296 16.1007 ( 0.00%) 17.4023 ( -8.08%)Processes using pipes are impacted but the variance (not presented) indicates it's close to noise and the results are not always reproducible. If executed across multiple reboots, it may show neutral or small gains so the worst measured results are presented.
Hackbench using sockets is more reliably neutral as the wakeup mechanisms are different between sockets and pipes.
hackbench-process-sockets
6.18-rc1 6.18-rc1
vanilla sched-preemptnext-v2
Amean 1 0.3073 ( 0.00%) 0.3263 ( -6.18%)
Amean 4 0.7863 ( 0.00%) 0.7930 ( -0.85%)
Amean 7 1.3670 ( 0.00%) 1.3537 ( 0.98%)
Amean 12 2.1337 ( 0.00%) 2.1903 ( -2.66%)
Amean 21 3.4683 ( 0.00%) 3.4940 ( -0.74%)
Amean 30 4.7247 ( 0.00%) 4.8853 ( -3.40%)
Amean 48 7.6097 ( 0.00%) 7.8197 ( -2.76%)
Amean 79 14.7957 ( 0.00%) 16.1000 ( -8.82%)
Amean 110 21.3413 ( 0.00%) 21.9997 ( -3.08%)
Amean 141 29.0503 ( 0.00%) 29.0353 ( 0.05%)
Amean 172 36.4660 ( 0.00%) 36.1433 ( 0.88%)
Amean 203 39.7177 ( 0.00%) 40.5910 ( -2.20%)
Amean 234 42.1120 ( 0.00%) 43.5527 ( -3.42%)
Amean 265 45.7830 ( 0.00%) 50.0560 ( -9.33%)
Amean 296 50.7043 ( 0.00%) 54.3657 ( -7.22%)As schbench has been mentioned in numerous bugs recently, the results are interesting. A test case that represents the default schbench behaviour is
schbench Wakeup Latency (usec)
6.18.0-rc1 6.18.0-rc1
vanilla sched-preemptnext-v5
Amean Wakeup-50th-80 7.17 ( 0.00%) 6.00 ( 16.28%)
Amean Wakeup-90th-80 46.56 ( 0.00%) 19.78 ( 57.52%)
Amean Wakeup-99th-80 119.61 ( 0.00%) 89.94 ( 24.80%)
Amean Wakeup-99.9th-80 3193.78 ( 0.00%) 328.22 ( 89.72%)schbench Requests Per Second (ops/sec)
6.18.0-rc1 6.18.0-rc1
vanilla sched-preemptnext-v5
Hmean RPS-20th-80 8900.91 ( 0.00%) 9176.78 ( 3.10%)
Hmean RPS-50th-80 8987.41 ( 0.00%) 9217.89 ( 2.56%)
Hmean RPS-90th-80 9123.73 ( 0.00%) 9273.25 ( 1.64%)
Hmean RPS-max-80 9193.50 ( 0.00%) 9301.47 ( 1.17%)Stable-dep-of: ac8e69e69363 ("sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue")
--- kernel/sched/fair.c | 152 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 130 insertions(+), 22 deletions(-)
kernel/sched/fair.c +130 -22
@@ -1021,6 +1021,16 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect)if (cfs_rq->nr_queued ==1 )return curr && curr->on_rq ? curr : se; +/* +* Picking the ->next buddy will affect latency but not fairness. +*/ +if (sched_feat (PICK_BUDDY ) && + cfs_rq->next &&entity_eligible (cfs_rq, cfs_rq->next)) { +/* ->next will never be delayed */ +WARN_ON_ONCE (cfs_rq->next->sched_delayed); +return cfs_rq->next; + } +if (curr && (!curr->on_rq || !entity_eligible (cfs_rq, curr))) curr =NULL ;
@@ -1260,6 +1270,8 @@ static s64 update_se(struct rq *rq, struct sched_entity *se)return delta_exec; } +static void set_next_buddy (struct sched_entity *se); +/* * Used by other classes to account runtime. */
@@ -5576,16 +5588,6 @@ pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq) {struct sched_entity *se; -/* -* Picking the ->next buddy will affect latency but not fairness. -*/ -if (sched_feat (PICK_BUDDY ) && - cfs_rq->next &&entity_eligible (cfs_rq, cfs_rq->next)) { -/* ->next will never be delayed */ -WARN_ON_ONCE (cfs_rq->next->sched_delayed); -return cfs_rq->next; - } - se =pick_eevdf (cfs_rq);if (se->sched_delayed) {dequeue_entities (rq, se,DEQUEUE_SLEEP |DEQUEUE_DELAYED );
@@ -7099,8 +7101,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)hrtick_update (rq); } -static void set_next_buddy (struct sched_entity *se); -/* * Basically dequeue_task_fair(), except it can deal with dequeue_entity() * failing half-way through and resume the dequeue later.
@@ -8796,16 +8796,81 @@ static void set_next_buddy(struct sched_entity *se) } } +enum preempt_wakeup_action { +PREEMPT_WAKEUP_NONE ,/* No preemption. */ +PREEMPT_WAKEUP_SHORT ,/* Ignore slice protection. */ +PREEMPT_WAKEUP_PICK ,/* Let __pick_eevdf() decide. */ +PREEMPT_WAKEUP_RESCHED ,/* Force reschedule. */ +}; + +static inline bool +set_preempt_buddy (struct cfs_rq *cfs_rq,int wake_flags, +struct sched_entity *pse,struct sched_entity *se) +{ +/* +* Keep existing buddy if the deadline is sooner than pse. +* The older buddy may be cache cold and completely unrelated +* to the current wakeup but that is unpredictable where as +* obeying the deadline is more in line with EEVDF objectives. +*/ +if (cfs_rq->next &&entity_before (cfs_rq->next, pse)) +return false; + +set_next_buddy (pse); +return true; +} + +/* +* WF_SYNC|WF_TTWU indicates the waker expects to sleep but it is not +* strictly enforced because the hint is either misunderstood or +* multiple tasks must be woken up. +*/ +static inline enum preempt_wakeup_action +preempt_sync (struct rq *rq,int wake_flags, +struct sched_entity *pse,struct sched_entity *se) +{ +u64 threshold, delta; + +/* +* WF_SYNC without WF_TTWU is not expected so warn if it happens even +* though it is likely harmless. +*/ +WARN_ON_ONCE (!(wake_flags &WF_TTWU )); + + threshold = sysctl_sched_migration_cost; + delta =rq_clock_task (rq) - se->exec_start; +if ((s64 )delta <0 ) + delta =0 ; + +/* +* WF_RQ_SELECTED implies the tasks are stacking on a CPU when they +* could run on other CPUs. Reduce the threshold before preemption is +* allowed to an arbitrary lower value as it is more likely (but not +* guaranteed) the waker requires the wakee to finish. +*/ +if (wake_flags &WF_RQ_SELECTED ) + threshold >>=2 ; + +/* +* As WF_SYNC is not strictly obeyed, allow some runtime for batch +* wakeups to be issued. +*/ +if (entity_before (pse, se) && delta >= threshold) +return PREEMPT_WAKEUP_RESCHED ; + +return PREEMPT_WAKEUP_NONE ; +} +/* * Preempt the current task with a newly woken task if needed: */ static void check_preempt_wakeup_fair (struct rq *rq,struct task_struct *p,int wake_flags) { +enum preempt_wakeup_action preempt_action =PREEMPT_WAKEUP_PICK ;struct task_struct *donor = rq->donor;struct sched_entity *se = &donor->se, *pse = &p->se;struct cfs_rq *cfs_rq =task_cfs_rq (donor);int cse_is_idle, pse_is_idle; -bool do_preempt_short = false;if (unlikely (se == pse))return ;
@@ -8819,10 +8884,6 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, intif (task_is_throttled (p))return ; -if (sched_feat (NEXT_BUDDY ) && !(wake_flags &WF_FORK ) && !pse->sched_delayed) { -set_next_buddy (pse); - } -/* * We can come here with TIF_NEED_RESCHED already set from new task * wake up path.
@@ -8854,7 +8915,7 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int* When non-idle entity preempt an idle entity, * don't give idle entity slice protection. */ - do_preempt_short = true; + preempt_action =PREEMPT_WAKEUP_SHORT ; goto preempt; }
@@ -8873,21 +8934,68 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int* If @p has a shorter slice than current and @p is eligible, override * current's slice protection in order to allow preemption. */ - do_preempt_short =sched_feat (PREEMPT_SHORT ) && (pse->slice < se->slice); +if (sched_feat (PREEMPT_SHORT ) && (pse->slice < se->slice)) { + preempt_action =PREEMPT_WAKEUP_SHORT ; + goto pick; + } +/* +* Ignore wakee preemption on WF_FORK as it is less likely that +* there is shared data as exec often follow fork. Do not +* preempt for tasks that are sched_delayed as it would violate +* EEVDF to forcibly queue an ineligible task. +*/ +if ((wake_flags &WF_FORK ) || pse->sched_delayed) +return ; + +/* +* If @p potentially is completing work required by current then +* consider preemption. +* +* Reschedule if waker is no longer eligible. */ +if (in_task () && !entity_eligible (cfs_rq, se)) { + preempt_action =PREEMPT_WAKEUP_RESCHED ; + goto preempt; + } + +/* Prefer picking wakee soon if appropriate. */ +if (sched_feat (NEXT_BUDDY ) && +set_preempt_buddy (cfs_rq, wake_flags, pse, se)) { + +/* +* Decide whether to obey WF_SYNC hint for a new buddy. Old +* buddies are ignored as they may not be relevant to the +* waker and less likely to be cache hot. +*/ +if (wake_flags &WF_SYNC ) + preempt_action =preempt_sync (rq, wake_flags, pse, se); + } + +switch (preempt_action) { +case PREEMPT_WAKEUP_NONE : +return ; +case PREEMPT_WAKEUP_RESCHED : + goto preempt; +case PREEMPT_WAKEUP_SHORT : + fallthrough; +case PREEMPT_WAKEUP_PICK : +break ; + } + +pick:/* * If @p has become the most eligible task, force preemption. */ -if (__pick_eevdf (cfs_rq, !do_preempt_short) == pse) +if (__pick_eevdf (cfs_rq, preempt_action !=PREEMPT_WAKEUP_SHORT ) == pse) goto preempt; -if (sched_feat (RUN_TO_PARITY ) && do_preempt_short) +if (sched_feat (RUN_TO_PARITY ))update_protect_slice (cfs_rq, se);return ; preempt: -if (do_preempt_short) +if (preempt_action ==PREEMPT_WAKEUP_SHORT )cancel_protect_slice (se);resched_curr_lazy (rq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 788/957 sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Guittot <[email protected]>
[ Upstream commit ac8e69e693631689d74d8f1ebee6f84f737f797f ]
Similar to how pick_next_entity() must dequeue delayed entities, so too must wakeup_preempt_fair(). Any delayed task being found means it is eligible and hence past the 0-lag point, ready for removal.
Worse, by not removing delayed entities from consideration, it can skew the preemption decision, with the end result that a short slice wakeup will not result in a preemption.
tip/sched/core tip/sched/core +this patch
cyclictest slice (ms) (default)2.8 8 8
hackbench slice (ms) (default)2.8 20 20
Total Samples | 22559 22595 22683 Average (us) | 157 64( 59%) 59( 8%) Median (P50) (us) | 57 57( 0%) 58(- 2%) 90th Percentile (us) | 64 60( 6%) 60( 0%) 99th Percentile (us) | 2407 67( 97%) 67( 0%) 99.9th Percentile (us) | 3400 2288( 33%) 727( 68%) Maximum (us) | 5037 9252(-84%) 7461( 19%)
--- kernel/sched/fair.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
kernel/sched/fair.c +14 -13
@@ -1007,7 +1007,7 @@ static inline void cancel_protect_slice(struct sched_entity *se)* * Which allows tree pruning through eligibility. */ -static struct sched_entity *__pick_eevdf (struct cfs_rq *cfs_rq,bool protect) +static struct sched_entity *pick_eevdf (struct cfs_rq *cfs_rq,bool protect) {struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node;struct sched_entity *se =__pick_first_entity (cfs_rq);
@@ -1078,11 +1078,6 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect)return best; } -static struct sched_entity *pick_eevdf (struct cfs_rq *cfs_rq) -{ -return __pick_eevdf (cfs_rq, true); -} -struct sched_entity *__pick_last_entity (struct cfs_rq *cfs_rq) {struct rb_node *last =rb_last (&cfs_rq->tasks_timeline.rb_root);
@@ -5584,11 +5579,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags);* 4) do not run the "skip" process, if something else is available */ static struct sched_entity * -pick_next_entity (struct rq *rq,struct cfs_rq *cfs_rq) +pick_next_entity (struct rq *rq,struct cfs_rq *cfs_rq,bool protect) {struct sched_entity *se; - se =pick_eevdf (cfs_rq); + se =pick_eevdf (cfs_rq, protect);if (se->sched_delayed) {dequeue_entities (rq, se,DEQUEUE_SLEEP |DEQUEUE_DELAYED );/*
@@ -8868,7 +8863,7 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int {enum preempt_wakeup_action preempt_action =PREEMPT_WAKEUP_PICK ;struct task_struct *donor = rq->donor; -struct sched_entity *se = &donor->se, *pse = &p->se; +struct sched_entity *nse, *se = &donor->se, *pse = &p->se;struct cfs_rq *cfs_rq =task_cfs_rq (donor);int cse_is_idle, pse_is_idle;
@@ -8983,11 +8978,17 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int } pick: + nse =pick_next_entity (rq, cfs_rq, preempt_action !=PREEMPT_WAKEUP_SHORT ); +/* If @p has become the most eligible task, force preemption */ +if (nse == pse) + goto preempt; +/* -* If @p has become the most eligible task, force preemption. +* Because p is enqueued, nse being null can only mean that we +* dequeued a delayed task. */ -if (__pick_eevdf (cfs_rq, preempt_action !=PREEMPT_WAKEUP_SHORT ) == pse) - goto preempt; +if (!nse) + goto pick;if (sched_feat (RUN_TO_PARITY ))update_protect_slice (cfs_rq, se);
@@ -9022,7 +9023,7 @@ static struct task_struct *pick_task_fair(struct rq *rq) throttled |=check_cfs_rq_runtime (cfs_rq); - se =pick_next_entity (rq, cfs_rq); + se =pick_next_entity (rq, cfs_rq, true);if (!se) goto again; cfs_rq =group_cfs_rq (se);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 789/957 sched/fair: Clear rel_deadline when initializing forked entities
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zicheng Qu <[email protected]>
[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ]
A yield-triggered crash can happen when a newly forked sched_entity enters the fair class with se->rel_deadline unexpectedly set.
The failing sequence is:
1. A task is forked while se->rel_deadline is still set.
2. __sched_fork() initializes vruntime, vlag and other sched_entity state, but does not clear rel_deadline.
3. On the first enqueue, enqueue_entity() calls place_entity().
4. Because se->rel_deadline is set, place_entity() treats se->deadline as a relative deadline and converts it to an absolute deadline by adding the current vruntime.
5. However, the forked entity's deadline is not a valid inherited relative deadline for this new scheduling instance, so the conversion produces an abnormally large deadline.
6. If the task later calls sched_yield(), yield_task_fair() advances
se->vruntime to se->deadline.
7. The inflated vruntime is then used by the following enqueue path, where the vruntime-derived key can overflow when multiplied by the entity weight.
8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility calculation, and can eventually make all entities appear ineligible. pick_next_entity() may then return NULL unexpectedly, leading to a later NULL dereference.
A captured trace shows the effect clearly. Before yield, the entity's vruntime was around:
9834017729983308
After yield_task_fair() executed:
se->vruntime = se->deadline
the vruntime jumped to:
19668035460670230
and the deadline was later advanced further to:
19668035463470230
This shows that the deadline had already become abnormally large before yield_task_fair() copied it into vruntime.
rel_deadline is only meaningful when se->deadline really carries a relative deadline that still needs to be placed against vruntime. A freshly forked sched_entity should not inherit or retain this state. Clear se->rel_deadline in __sched_fork(), together with the other sched_entity runtime state, so that the first enqueue does not interpret the new entity's deadline as a stale relative deadline.
--- kernel/sched/core.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/core.c +1 -0
@@ -4453,6 +4453,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p) p->se.nr_migrations =0 ; p->se.vruntime =0 ; p->se.vlag =0 ; + p->se.rel_deadline =0 ;INIT_LIST_HEAD (&p->se.group_node);/* A delayed task cannot be in clone(). */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 790/957 net: mctp i2c: check length before marking flow active
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: William A. Kennington III <[email protected]>
[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ]
Currently, mctp_i2c_get_tx_flow_state() is called before the packet length sanity check. This function marks a new flow as active in the MCTP core.
If the sanity check fails, mctp_i2c_xmit() returns early without calling mctp_i2c_lock_nest(). This results in a mismatched locking state: the flow is active, but the I2C bus lock was never acquired for it.
When the flow is later released, mctp_i2c_release_flow() will see the active state and queue an unlock marker. The TX thread will then decrement midev->i2c_lock_count from 0, causing it to underflow to -1.
This underflow permanently breaks the driver's locking logic, allowing future transmissions to occur without holding the I2C bus lock, leading to bus collisions and potential hardware hangs.
Move the mctp_i2c_get_tx_flow_state() call to after the length sanity check to ensure we only transition the flow state if we are actually going to proceed with the transmission and locking.
--- drivers/net/mctp/mctp-i2c.c | 4 ++-- net/sched/cls_flower.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/mctp/mctp-i2c.c +2 -2
@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)u8 *pecp;int rc; - fs =mctp_i2c_get_tx_flow_state (midev, skb); - hdr = (void *)skb_mac_header (skb);/* Sanity check that packet contents matches skb length, * and can't exceed MCTP_I2C_BUFSZ
@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)return ; } + fs =mctp_i2c_get_tx_flow_state (midev, skb); +if (skb_tailroom (skb) >=1 ) {/* Linear case with space, we can just append the PEC */ skb_put (skb,1 );
net/sched/cls_flower.c +3 -1
@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); +struct fl_flow_mask *mask; *last = false;
@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - *last =fl_mask_put (head, f->mask); + mask = f->mask;if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); + *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 791/957 md/raid1,raid10: dont fail devices for invalid IO errors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit f7b24c7b41f23b5f9caa8b913afe79cd4c397d39 ]
BLK_STS_INVAL indicates the IO request itself was invalid, not that the device has failed. When raid1 treats this as a device error, it retries on alternate mirrors which fail the same way, eventually exceeding the read error threshold and removing the device from the array.
This happens when stacking configurations bypass bio_split_to_limits() in the IO path: dm-raid calls md_handle_request() directly without going through md_submit_bio(), skipping the alignment validation that would otherwise reject invalid bios early. The invalid bio reaches the lower block layers, which fail the bio with BLK_STS_INVAL, and raid1 wrongly interprets this as a device failure.
Add BLK_STS_INVAL to raid1_should_handle_error() so that invalid IO errors are propagated back to the caller rather than triggering device removal. This is consistent with the previous kernel behavior when alignment checks were done earlier in the direct-io path.
--- drivers/md/raid1-10.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/raid1-10.c +6 -1
@@ -298,8 +298,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,* bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is * submitted to the underlying disks, hence don't record badblocks or retry * in this case. +* +* BLK_STS_INVAL means the bio was not valid for the underlying device. This +* is a user error, not a device failure, so retrying or recording bad blocks +* would be wrong. */ static inline bool raid1_should_handle_error (struct bio *bio) { -return !(bio->bi_opf & (REQ_RAHEAD |REQ_NOWAIT )); +return !(bio->bi_opf & (REQ_RAHEAD |REQ_NOWAIT )) && + bio->bi_status !=BLK_STS_INVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 792/957 md: add fallback to correct bitmap_ops on version mismatch
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 09af773650024279a60348e7319d599e6571b15c ]
If default bitmap version and on-disk version doesn't match, and mdadm is not the latest version to set bitmap_type, set bitmap_ops based on the disk version.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-)
drivers/md/md.c +110 -1
@@ -6329,15 +6329,124 @@ static void md_safemode_timeout(struct timer_list *t)static int start_dirty_degraded; +/* +* Read bitmap superblock and return the bitmap_id based on disk version. +* This is used as fallback when default bitmap version and on-disk version +* doesn't match, and mdadm is not the latest version to set bitmap_type. +*/ +static enum md_submodule_id md_bitmap_get_id_from_sb (struct mddev *mddev) +{ +struct md_rdev *rdev; +struct page *sb_page; +bitmap_super_t *sb; +enum md_submodule_id id =ID_BITMAP_NONE ; +sector_t sector; +u32 version; + +if (!mddev->bitmap_info.offset) +return ID_BITMAP_NONE ; + + sb_page =alloc_page (GFP_KERNEL ); +if (!sb_page) { +pr_warn ("md: %s: failed to allocate memory for bitmap\n" , +mdname (mddev)); +return ID_BITMAP_NONE ; + } + + sector = mddev->bitmap_info.offset; + +rdev_for_each (rdev, mddev) { +u32 iosize; + +if (!test_bit (In_sync, &rdev->flags) || +test_bit (Faulty, &rdev->flags) || +test_bit (Bitmap_sync, &rdev->flags)) +continue ; + + iosize =roundup (sizeof (bitmap_super_t), +bdev_logical_block_size (rdev->bdev)); +if (sync_page_io (rdev, sector, iosize, sb_page,REQ_OP_READ , + true)) + goto read_ok; + } +pr_warn ("md: %s: failed to read bitmap from any device\n" , +mdname (mddev)); + goto out; + +read_ok: + sb =kmap_local_page (sb_page); +if (sb->magic !=cpu_to_le32 (BITMAP_MAGIC )) { +pr_warn ("md: %s: invalid bitmap magic 0x%x\n" , +mdname (mddev),le32_to_cpu (sb->magic)); + goto out_unmap; + } + + version =le32_to_cpu (sb->version); +switch (version) { +case BITMAP_MAJOR_LO : +case BITMAP_MAJOR_HI : +case BITMAP_MAJOR_CLUSTERED : + id =ID_BITMAP ; +break ; +case BITMAP_MAJOR_LOCKLESS : + id =ID_LLBITMAP ; +break ; +default : +pr_warn ("md: %s: unknown bitmap version %u\n" , +mdname (mddev), version); +break ; + } + +out_unmap: +kunmap_local (sb); +out: +__free_page (sb_page); +return id; +} +static int md_bitmap_create (struct mddev *mddev) { +enum md_submodule_id orig_id = mddev->bitmap_id; +enum md_submodule_id sb_id; +int err; +if (mddev->bitmap_id ==ID_BITMAP_NONE )return -EINVAL ;if (!mddev_set_bitmap_ops (mddev))return -ENOENT ; -return mddev->bitmap_ops->create (mddev); + err = mddev->bitmap_ops->create (mddev); +if (!err) +return 0 ; + +/* +* Create failed, if default bitmap version and on-disk version +* doesn't match, and mdadm is not the latest version to set +* bitmap_type, set bitmap_ops based on the disk version. +*/ +mddev_clear_bitmap_ops (mddev); + + sb_id =md_bitmap_get_id_from_sb (mddev); +if (sb_id ==ID_BITMAP_NONE || sb_id == orig_id) +return err; + +pr_info ("md: %s: bitmap version mismatch, switching from %d to %d\n" , +mdname (mddev), orig_id, sb_id); + + mddev->bitmap_id = sb_id; +if (!mddev_set_bitmap_ops (mddev)) { + mddev->bitmap_id = orig_id; +return -ENOENT ; + } + + err = mddev->bitmap_ops->create (mddev); +if (err) { +mddev_clear_bitmap_ops (mddev); + mddev->bitmap_id = orig_id; + } + +return err; }static void md_bitmap_destroy (struct mddev *mddev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 793/957 md: factor bitmap creation away from sysfs handling
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 8776d342cf8fa0b98ca5e6fb2d956966fb5ca364 ]
Factor bitmap creation and destruction into helpers that do not touch bitmap sysfs registration.
This prepares the bitmap sysfs rework so callers such as the sysfs bitmap location path can create or destroy a bitmap backend without coupling that to sysfs group lifetime management.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md.c | 78 +++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 29 deletions(-)
drivers/md/md.c +49 -29
@@ -686,7 +686,25 @@ static void active_io_release(struct percpu_ref *ref)static void no_op (struct percpu_ref *r) {} -static bool mddev_set_bitmap_ops (struct mddev *mddev) +static void md_bitmap_sysfs_add (struct mddev *mddev) +{ +if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) +pr_warn ("md: cannot register extra bitmap attributes for %s\n" , +mdname (mddev)); +else +/* +* Inform user with KOBJ_CHANGE about new bitmap +* attributes. +*/ +kobject_uevent (&mddev->kobj,KOBJ_CHANGE ); +} + +static void md_bitmap_sysfs_del (struct mddev *mddev) +{ +sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); +} + +static bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev) {struct bitmap_operations *old = mddev->bitmap_ops;struct md_submodule_head *head;
@@ -710,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) mddev->bitmap_ops = (void *)head;xa_unlock (&md_submodule); - -if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) { -if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) -pr_warn ("md: cannot register extra bitmap attributes for %s\n" , -mdname (mddev)); -else -/* -* Inform user with KOBJ_CHANGE about new bitmap -* attributes. -*/ -kobject_uevent (&mddev->kobj,KOBJ_CHANGE ); - }return true; err:
@@ -729,15 +735,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)return false; } -static void mddev_clear_bitmap_ops (struct mddev *mddev) -{ -if (!mddev_is_dm (mddev) && mddev->bitmap_ops && - mddev->bitmap_ops->group) -sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); - - mddev->bitmap_ops =NULL ; -} -int mddev_init (struct mddev *mddev) {int err =0 ;
@@ -6404,7 +6401,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)return id; } -static int md_bitmap_create (struct mddev *mddev) +static int md_bitmap_create_nosysfs (struct mddev *mddev) {enum md_submodule_id orig_id = mddev->bitmap_id;enum md_submodule_id sb_id;
@@ -6413,7 +6410,7 @@ static int md_bitmap_create(struct mddev *mddev)if (mddev->bitmap_id ==ID_BITMAP_NONE )return -EINVAL ; -if (!mddev_set_bitmap_ops (mddev)) +if (!mddev_set_bitmap_ops_nosysfs (mddev))return -ENOENT ; err = mddev->bitmap_ops->create (mddev);
@@ -6425,7 +6422,7 @@ static int md_bitmap_create(struct mddev *mddev)* doesn't match, and mdadm is not the latest version to set * bitmap_type, set bitmap_ops based on the disk version. */ -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; sb_id =md_bitmap_get_id_from_sb (mddev);if (sb_id ==ID_BITMAP_NONE || sb_id == orig_id)
@@ -6435,27 +6432,50 @@ static int md_bitmap_create(struct mddev *mddev) mdname(mddev), orig_id, sb_id); mddev->bitmap_id = sb_id; -if (!mddev_set_bitmap_ops (mddev)) { +if (!mddev_set_bitmap_ops_nosysfs (mddev)) { mddev->bitmap_id = orig_id;return -ENOENT ; } err = mddev->bitmap_ops->create (mddev);if (err) { -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; mddev->bitmap_id = orig_id; }return err; } -static void md_bitmap_destroy (struct mddev *mddev) +static int md_bitmap_create (struct mddev *mddev) +{ +int err; + + err =md_bitmap_create_nosysfs (mddev); +if (err) +return err; + +if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) +md_bitmap_sysfs_add (mddev); + +return 0 ; +} + +static void md_bitmap_destroy_nosysfs (struct mddev *mddev) {if (!md_bitmap_registered (mddev))return ; mddev->bitmap_ops->destroy (mddev); -mddev_clear_bitmap_ops (mddev); + mddev->bitmap_ops =NULL ; +} + +static void md_bitmap_destroy (struct mddev *mddev) +{ +if (!mddev_is_dm (mddev) && mddev->bitmap_ops && + mddev->bitmap_ops->group) +md_bitmap_sysfs_del (mddev); + +md_bitmap_destroy_nosysfs (mddev); }int md_run (struct mddev *mddev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 794/957 md/md-bitmap: split bitmap sysfs groups
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit aba3d6d6cb55c6e1116d1215140559dd7ecdf9a9 ]
Split the classic bitmap sysfs files into a common bitmap group with the location attribute and a separate internal bitmap group for the remaining files.
At the same time, convert bitmap operations from a single sysfs group to a sysfs group array so backends can share part of their sysfs layout while adding backend-specific attributes separately.
Switch the bitmap sysfs helpers to use sysfs_update_groups() for the add and update path, and remove groups in reverse order so shared named groups are unmerged before the last group removes the directory.
Also make bitmap operation lookup depend only on the currently selected bitmap id matching the installed backend. This prepares the lookup path for a later registered none backend.
Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow")
--- drivers/md/md-bitmap.c | 23 +++++++++++++++++++---- drivers/md/md-bitmap.h | 2 +- drivers/md/md-llbitmap.c | 7 ++++++- drivers/md/md.c | 21 ++++++++++++++------- 4 files changed, 40 insertions(+), 13 deletions(-)
drivers/md/md-bitmap.c +19 -4
@@ -2956,8 +2956,12 @@ static struct md_sysfs_entry max_backlog_used =__ATTR (max_backlog_used,S_IRUGO |S_IWUSR , behind_writes_used_show, behind_writes_used_reset); -static struct attribute *md_bitmap_attrs[] = { +static struct attribute *md_bitmap_common_attrs[] = { &bitmap_location.attr, +NULL +}; + +static struct attribute *md_bitmap_internal_attrs[] = { &bitmap_space.attr, &bitmap_timeout.attr, &bitmap_backlog.attr,
@@ -2968,9 +2972,20 @@ static struct attribute *md_bitmap_attrs[] = {NULL }; -static struct attribute_group md_bitmap_group = { +static struct attribute_group md_bitmap_common_group = { + .name ="bitmap" , + .attrs = md_bitmap_common_attrs, +}; + +static struct attribute_group md_bitmap_internal_group = { .name ="bitmap" , - .attrs = md_bitmap_attrs, + .attrs = md_bitmap_internal_attrs, +}; + +static const struct attribute_group *bitmap_groups[] = { + &md_bitmap_common_group, + &md_bitmap_internal_group, +NULL , };static struct bitmap_operations bitmap_ops = {
@@ -3014,7 +3029,7 @@ static struct bitmap_operations bitmap_ops = { .set_pages = bitmap_set_pages, .free = md_bitmap_free, - .group = &md_bitmap_group, + .groups = bitmap_groups, };int md_bitmap_init (void )
drivers/md/md-bitmap.h +1 -1
@@ -125,7 +125,7 @@ struct bitmap_operations {void (*set_pages)(void *data,unsigned long pages);void (*free)(void *data); -struct attribute_group *group; +const struct attribute_group **groups; };/* the bitmap API */
drivers/md/md-llbitmap.c +6 -1
@@ -1562,6 +1562,11 @@ static struct attribute_group md_llbitmap_group = { .attrs = md_llbitmap_attrs, }; +static const struct attribute_group *md_llbitmap_groups[] = { + &md_llbitmap_group, +NULL , +}; +static struct bitmap_operations llbitmap_ops = { .head = { .type =MD_BITMAP ,
@@ -1598,7 +1603,7 @@ static struct bitmap_operations llbitmap_ops = { .dirty_bits = llbitmap_dirty_bits, .write_all = llbitmap_write_all, - .group = &md_llbitmap_group, + .groups = md_llbitmap_groups, };int md_llbitmap_init (void )
drivers/md/md.c +14 -7
@@ -688,7 +688,7 @@ static void no_op(struct percpu_ref *r) {}static void md_bitmap_sysfs_add (struct mddev *mddev) { -if (sysfs_create_group (&mddev->kobj, mddev->bitmap_ops->group)) +if (sysfs_update_groups (&mddev->kobj, mddev->bitmap_ops->groups))pr_warn ("md: cannot register extra bitmap attributes for %s\n" ,mdname (mddev));else
@@ -701,16 +701,23 @@ static void md_bitmap_sysfs_add(struct mddev *mddev)static void md_bitmap_sysfs_del (struct mddev *mddev) { -sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->group); +int nr_groups =0 ; + +for (nr_groups =0 ; mddev->bitmap_ops->groups[nr_groups]; nr_groups++) + ; + +while (--nr_groups >=1 ) +sysfs_unmerge_group (&mddev->kobj, + mddev->bitmap_ops->groups[nr_groups]); +sysfs_remove_group (&mddev->kobj, mddev->bitmap_ops->groups[0 ]); }static bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev) { -struct bitmap_operations *old = mddev->bitmap_ops;struct md_submodule_head *head; -if (mddev->bitmap_id ==ID_BITMAP_NONE || - (old && old->head.id == mddev->bitmap_id)) +if (mddev->bitmap_ops && + mddev->bitmap_ops->head.id == mddev->bitmap_id)return true;xa_lock (&md_submodule);
@@ -6454,7 +6461,7 @@ static int md_bitmap_create(struct mddev *mddev)if (err)return err; -if (!mddev_is_dm (mddev) && mddev->bitmap_ops->group) +if (!mddev_is_dm (mddev) && mddev->bitmap_ops->groups)md_bitmap_sysfs_add (mddev);return 0 ;
@@ -6472,7 +6479,7 @@ static void md_bitmap_destroy_nosysfs(struct mddev *mddev)static void md_bitmap_destroy (struct mddev *mddev) {if (!mddev_is_dm (mddev) && mddev->bitmap_ops && - mddev->bitmap_ops->group) + mddev->bitmap_ops->groups)md_bitmap_sysfs_del (mddev);md_bitmap_destroy_nosysfs (mddev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 795/957 md/md-bitmap: add a none backend for bitmap grow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit f2926a533d03fe70d753b512b713e06a2aa174af ]
Add a real none bitmap backend that exposes the common bitmap sysfs group and use it to keep bitmap/location available when an array has no bitmap.
Then switch the bitmap location sysfs path to move only between none and the classic bitmap backend, using the no-sysfs bitmap helpers while merging or unmerging the internal bitmap sysfs group.
This restores mdadm --grow bitmap addition through bitmap/location.
--- drivers/md/md-bitmap.c | 108 ++++++++++++++++++++++++++++++++++++++--- drivers/md/md.c | 42 +++++++++++++--- drivers/md/md.h | 3 ++ 3 files changed, 137 insertions(+), 16 deletions(-)
drivers/md/md-bitmap.c +100 -8
@@ -216,6 +216,7 @@ struct bitmap { };static struct workqueue_struct *md_bitmap_wq; +static struct attribute_group md_bitmap_internal_group;static int __bitmap_resize (struct bitmap *bitmap,sector_t blocks,int chunksize,bool init);
@@ -2581,6 +2582,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)return __bitmap_resize (bitmap, blocks, chunksize, false); } +static bool bitmap_none_enabled (void *data,bool flush) +{ +return false; +} + +static int bitmap_none_create (struct mddev *mddev) +{ +return 0 ; +} + +static int bitmap_none_load (struct mddev *mddev) +{ +return 0 ; +} + +static void bitmap_none_destroy (struct mddev *mddev) +{ +} + +static int bitmap_none_get_stats (void *data,struct md_bitmap_stats *stats) +{ +return -ENOENT ; +} +static ssize_t location_show (struct mddev *mddev,char *page) {
@@ -2619,7 +2644,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len) goto out; } -bitmap_destroy (mddev); +sysfs_unmerge_group (&mddev->kobj, &md_bitmap_internal_group); +md_bitmap_destroy_nosysfs (mddev); + mddev->bitmap_id =ID_BITMAP_NONE ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + goto none_err; mddev->bitmap_info.offset =0 ;if (mddev->bitmap_info.file) {struct file *f = mddev->bitmap_info.file;
@@ -2655,16 +2684,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len) } mddev->bitmap_info.offset = offset; - rv =bitmap_create (mddev); +md_bitmap_destroy_nosysfs (mddev); + mddev->bitmap_id =ID_BITMAP ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + goto bitmap_err; + + rv =md_bitmap_create_nosysfs (mddev);if (rv) - goto out; + goto create_err; - rv =bitmap_load (mddev); + rv = mddev->bitmap_ops->load (mddev);if (rv) { mddev->bitmap_info.offset =0 ; -bitmap_destroy (mddev); - goto out; + goto load_err; } + + rv =sysfs_merge_group (&mddev->kobj, + &md_bitmap_internal_group); +if (rv) + goto merge_err; } }if (!mddev->external) {
@@ -2680,6 +2718,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len)if (rv)return rv;return len; + +merge_err: + mddev->bitmap_info.offset =0 ; +load_err: +md_bitmap_destroy_nosysfs (mddev); +create_err: + mddev->bitmap_info.offset =0 ; + mddev->bitmap_id =ID_BITMAP_NONE ; +if (!mddev_set_bitmap_ops_nosysfs (mddev)) + rv = -ENOENT ; + goto out; +bitmap_err: + rv = -ENOENT ; +none_err: + mddev->bitmap_info.offset =0 ; + goto out; } static struct md_sysfs_entry bitmap_location =
@@ -2988,6 +3042,27 @@ static const struct attribute_group *bitmap_groups[] = { NULL, }; +static const struct attribute_group *bitmap_none_groups[] = { + &md_bitmap_common_group, +NULL , +}; + +static struct bitmap_operations bitmap_none_ops = { + .head = { + .type =MD_BITMAP , + .id =ID_BITMAP_NONE , + .name ="none" , + }, + + .enabled = bitmap_none_enabled, + .create = bitmap_none_create, + .load = bitmap_none_load, + .destroy = bitmap_none_destroy, + .get_stats = bitmap_none_get_stats, + + .groups = bitmap_none_groups, +}; +static struct bitmap_operations bitmap_ops = { .head = { .type =MD_BITMAP ,
@@ -3034,16 +3109,33 @@ static struct bitmap_operations bitmap_ops = {int md_bitmap_init (void ) { +int err; + md_bitmap_wq =alloc_workqueue ("md_bitmap" ,WQ_MEM_RECLAIM |WQ_UNBOUND ,0 );if (!md_bitmap_wq)return -ENOMEM ; -return register_md_submodule (&bitmap_ops.head); + err =register_md_submodule (&bitmap_none_ops.head); +if (err) + goto err_wq; + + err =register_md_submodule (&bitmap_ops.head); +if (err) + goto err_none; + +return 0 ; + +err_none: +unregister_md_submodule (&bitmap_none_ops.head); +err_wq: +destroy_workqueue (md_bitmap_wq); +return err; }void md_bitmap_exit (void ) { -destroy_workqueue (md_bitmap_wq);unregister_md_submodule (&bitmap_ops.head); +unregister_md_submodule (&bitmap_none_ops.head); +destroy_workqueue (md_bitmap_wq); }
drivers/md/md.c +34 -8
125 lines not on this page · raw message
drivers/md/md.h +3 -0
@@ -932,6 +932,9 @@ extern void md_allow_write(struct mddev *mddev);extern void md_wait_for_blocked_rdev (struct md_rdev *rdev,struct mddev *mddev);extern void md_set_array_sectors (struct mddev *mddev,sector_t array_sectors);extern int md_check_no_bitmap (struct mddev *mddev); +bool mddev_set_bitmap_ops_nosysfs (struct mddev *mddev); +int md_bitmap_create_nosysfs (struct mddev *mddev); +void md_bitmap_destroy_nosysfs (struct mddev *mddev);extern int md_integrity_register (struct mddev *mddev);extern int strict_strtoul_scaled (const char *cp,unsigned long *res,int scale);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 796/957 s390/mm: Fix phys_to_folio() usage in do_secure_storage_access()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit b95e0e792822bad8fc9eb33ea3a90005e29e75e9 ]
In case of a Secure-Storage-Access exception the effective aka virtual address which caused the exception is contained within the TEID.
do_secure_storage_access() incorrectly uses phys_to_folio() instead of virt_to_folio() to translate the virtual address to the corresponding folio.
Fix this by using virt_to_folio() instead of phys_to_folio().
--- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/mm/fault.c +1 -1
@@ -433,7 +433,7 @@ void do_secure_storage_access(struct pt_regs *regs)panic ("Unexpected PGM 0x3d with TEID bit 61=0" ); }if (is_kernel_fault (regs)) { - folio =phys_to_folio (addr); + folio =virt_to_folio ((void *)addr);if (unlikely (!folio_try_get (folio)))return ; rc =uv_convert_from_secure (folio_to_phys (folio));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 797/957 net: phy: dp83869: fix setting CLK_O_SEL field.
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Schocher <[email protected]>
[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ]
Table 7-121 in datasheet says we have to set register 0xc6 to value 0x10 before CLK_O_SEL can be modified. No more infos about this field found in datasheet. With this fix, setting of CLK_O_SEL field in IO_MUX_CFG register worked through dts property "ti,clk-output-sel" on a DP83869HMRGZR.
--- drivers/net/phy/dp83869.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/net/phy/dp83869.c +12 -1
@@ -31,6 +31,7 @@#define DP83869_RGMIICTL 0x0032#define DP83869_STRAP_STS1 0x006e#define DP83869_RGMIIDCTL 0x0086 +#define DP83869_ANA_PLL_PROG_PI 0x00c6#define DP83869_RXFCFG 0x0134#define DP83869_RXFPMD1 0x0136#define DP83869_RXFPMD2 0x0137
@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev)dp83869_config_port_mirroring (phydev);/* Clock output selection if muxing property is set */ -if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) +if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) { +/* +* Table 7-121 in datasheet says we have to set register 0xc6 +* to value 0x10 before CLK_O_SEL can be modified. +*/ + ret =phy_write_mmd (phydev,DP83869_DEVADDR , +DP83869_ANA_PLL_PROG_PI ,0x10 ); +if (ret) +return ret; + ret =phy_modify_mmd (phydev,DP83869_DEVADDR ,DP83869_IO_MUX_CFG ,DP83869_IO_MUX_CFG_CLK_O_SEL_MASK , dp83869->clk_output_sel <<DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT ); + }if (phy_interface_is_rgmii (phydev)) { ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 798/957 drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +2 -0
@@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_0_dec_ring_get_rptr, .get_wptr = vcn_v2_0_dec_ring_get_wptr,
@@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr, .set_wptr = vcn_v2_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 799/957 drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +2 -0
@@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_5_dec_ring_get_rptr, .get_wptr = vcn_v2_5_dec_ring_get_wptr,
@@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr, .set_wptr = vcn_v2_5_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 800/957 drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +3 -0
@@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2037,6 +2038,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2139,6 +2141,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr, .set_wptr = vcn_v3_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 801/957 drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +1 -0
@@ -1995,6 +1995,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), .get_rptr = vcn_v4_0_unified_ring_get_rptr, .get_wptr = vcn_v4_0_unified_ring_get_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 802/957 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +1 -0
@@ -1628,6 +1628,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, .set_wptr = vcn_v4_0_3_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 803/957 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +1 -0
@@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, .set_wptr = vcn_v4_0_5_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 804/957 drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +1 -0
@@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, .set_wptr = vcn_v5_0_0_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 805/957 drm/amdgpu/vcn: set no_user_fence for VCN v5.0.1 enc ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8f4954722eab88e10c4ea0c0d3b1269c31421d3a ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +1 -0
@@ -1330,6 +1330,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, .set_wptr = vcn_v5_0_1_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 806/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +1 -0
@@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr, .set_wptr = jpeg_v2_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 807/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +2 -0
@@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
@@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 808/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +1 -0
@@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 809/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +1 -0
@@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 810/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +1 -0
@@ -1214,6 +1214,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 811/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +1 -0
@@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 812/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +1 -0
@@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 813/957 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.1 ring
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 2f8e3da71a1b469b6e157aa3972f1448b3157840 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +1 -0
@@ -875,6 +875,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 814/957 io_uring/napi: cap busy_poll_to 10 msec
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
[ Upstream commit df8599ee18c0e5fe343ffe0b4c379636b8bb839a ]
Currently there's no cap on the maximum amount of time that napi is allowed to poll if no events are found, which can lead to kernel complaints on a task being stuck as there's no conditional rescheduling done within that loop.
Just cap it to 10 msec in total, that's already way above any kind of sane value that will reap any benefits, yet low enough that it's nowhere near being able to trigger preemption complaints.
--- io_uring/napi.c | 2 ++ 1 file changed, 2 insertions(+)
io_uring/napi.c +2 -0
@@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx,/* clean the napi list for new settings */ io_napi_free (ctx);WRITE_ONCE (ctx->napi_track_mode, napi->op_param); +/* cap NAPI at 10 msec of spin time */ + napi->busy_poll_to =min (10000 , napi->busy_poll_to);WRITE_ONCE (ctx->napi_busy_poll_dt, napi->busy_poll_to *NSEC_PER_USEC );WRITE_ONCE (ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 815/957 net: psp: check for device unregister when creating assoc
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b89769f936a8fa9e66de72ddc1b71a9745a488e6 ]
psp_assoc_device_get_locked() obtains a psp_dev reference via psp_dev_get_for_sock() (which uses psp_dev_tryget() under RCU); it then acquires psd->lock and drops the reference. Before the lock is taken, psp_dev_unregister() can run to completion:
take psd->lock, clear out state, unlock, drop the registration reference.
The expectation is that the lock prevents device unregistration, but much like with netdevs special care has to be taken when "upgrading" a reference to a locked device. Add the missing check if device is still alive. psp_dev_is_registered() exists already but had no callers, which makes me wonder if I either forgot to add this or lost the check during refactoring...
--- net/psp/psp_nl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/psp/psp_nl.c +7 -3
@@ -303,8 +303,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, psd =psp_dev_get_for_sock (socket->sk);if (psd) { - err =psp_dev_check_access (psd,genl_info_net (info)); -if (err) { +/* Extra care needed here, psp_dev_get_for_sock() only gives +* us access to struct psp_dev's memory, which is quite weak. +*/ +mutex_lock (&psd->lock); +if (!psp_dev_is_registered (psd) || +psp_dev_check_access (psd,genl_info_net (info))) { +mutex_unlock (&psd->lock);psp_dev_put (psd); psd =NULL ; }
@@ -317,7 +322,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, id = info->attrs[PSP_A_ASSOC_DEV_ID ];if (psd) { -mutex_lock (&psd->lock);if (id && psd->id !=nla_get_u32 (id)) {mutex_unlock (&psd->lock); NL_SET_ERR_MSG_ATTR(info->extack, id,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 816/957 net: psp: require admin permission for dev-set and key-rotate
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit b718342a7fbaa2dff5fefc31988c07af8c6cbc21 ]
The dev-set and key-rotate netlink operations modify shared device state (PSP version configuration and cryptographic key material, respectively) but do not require CAP_NET_ADMIN. The only access control is psp_dev_check_access() which merely verifies netns membership.
--- Documentation/netlink/specs/psp.yaml | 2 ++ net/psp/psp-nl-gen.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
Documentation/netlink/specs/psp.yaml +2 -0
@@ -111,6 +111,7 @@ operations: name: dev-set doc: Set the configuration of a PSP device. attribute-set: dev + flags: [admin-perm] do: request: attributes:
@@ -130,6 +131,7 @@ operations: name: key-rotate doc: Rotate the device key. attribute-set: dev + flags: [admin-perm] do: request: attributes:
net/psp/psp-nl-gen.c +2 -2
@@ -70,7 +70,7 @@ static const struct genl_split_ops psp_nl_ops[] = { .post_doit = psp_device_unlock, .policy = psp_dev_set_nl_policy, .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, - .flags = GENL_CMD_CAP_DO, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = PSP_CMD_KEY_ROTATE,
@@ -79,7 +79,7 @@ static const struct genl_split_ops psp_nl_ops[] = { .post_doit = psp_device_unlock, .policy = psp_key_rotate_nl_policy, .maxattr = PSP_A_DEV_ID, - .flags = GENL_CMD_CAP_DO, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = PSP_CMD_RX_ASSOC,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 817/957 ASoC: codecs: ab8500: Fix casting of private data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian A. Ehrhardt <[email protected]>
[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ]
ab8500_filter_controls[i].private_value is initialized using
.private_value = (unsigned long)&(struct filter_control)
{.count = xcount, .min = xmin, .max = xmax}thus it's a pointer to a struct filter_control casted to unsigned long.
So to get back that pointer .private_data must be cast back, not its address.
--- sound/soc/codecs/ab8500-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/codecs/ab8500-codec.c +3 -3
@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)return status; } fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; drvdata->anc_fir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; drvdata->anc_iir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; drvdata->sid_fir_values = (long *)fc->value;snd_soc_dapm_disable_pin (dapm,"ANC Configure Input" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 818/957 netfilter: skip recording stale or retransmitted INIT
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ]
An INIT whose init_tag matches the peer's vtag does not provide new state information. It indicates either:
- a stale INIT (after INIT-ACK has already been seen on the same side), or
- a retransmitted INIT (after INIT has already been recorded on the same side).
In both cases, the INIT must not update ct->proto.sctp.init[] state, since it does not advance the handshake tracking and may otherwise corrupt INIT/INIT-ACK validation logic.
Allow INIT processing only when the conntrack entry is newly created (SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer vtag.
Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag.
--- net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/netfilter/nf_conntrack_proto_sctp.c +7 -3
@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,if (!ih) goto out_unlock; -if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) - ct->proto.sctp.init[!dir] =0 ; - ct->proto.sctp.init[dir] =1 ; +/* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ +if (old_state ==SCTP_CONNTRACK_NONE || + ct->proto.sctp.vtag[!dir] != ih->init_tag) { +if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) + ct->proto.sctp.init[!dir] =0 ; + ct->proto.sctp.init[dir] =1 ; + }pr_debug ("Setting vtag %x for dir %d\n" , ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 819/957 sctp: discard stale INIT after handshake completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ]
After an association reaches ESTABLISHED, the peer’s init_tag is already known from the handshake. Any subsequent INIT with the same init_tag is not a valid restart, but a delayed or duplicate INIT.
Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of processing them as new association attempts.
--- net/sctp/sm_statefuns.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_statefuns.c +6 -0
@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(/* Tag the variable length parameters. */ chunk->param_hdr.v =skb_pull (chunk->skb,sizeof (struct sctp_inithdr )); +if (asoc->state >=SCTP_STATE_ESTABLISHED ) { +/* Discard INIT matching peer vtag after handshake completion (stale INIT). */ +if (ntohl (chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) +return sctp_sf_pdiscard (net, ep, asoc, type, arg, commands); + } +/* Verify the INIT chunk before processing it. */ err_chunk =NULL ; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 820/957 bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ]
bareudp_fill_metadata_dst() passes bareudp->sock to udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. The socket is only created in bareudp_open() and NULLed in bareudp_stop(), so calling this function while the device is down triggers a NULL dereference via sock->sk.
BUG: kernel NULL pointer dereference, address: 0000000000000018 RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) Call Trace: <TASK> bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) do_execute_actions (net/openvswitch/actions.c:901) ovs_execute_actions (net/openvswitch/actions.c:1589) ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) genl_rcv_msg (net/netlink/genetlink.c:1209) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths in the same driver.
--- drivers/net/bareudp.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/bareudp.c +3 -0
@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,struct in6_addr saddr;struct socket *sock =rcu_dereference (bareudp->sock); +if (!sock) +return -ESHUTDOWN ; + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, 0, &saddr, &info->key, sport, bareudp->port, info->key.tos,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 821/957 net/sched: sch_cake: annotate data-races in cake_dump_stats() (III)
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 276a98a434964088fccd4745db5b34d6e831e358 ]
cake_dump_stats() runs without qdisc spinlock being held.
In this third patch, I add READ_ONCE()/WRITE_ONCE() annotations for the following fields:
- packets
- tin_dropped
- tin_ecn_mark
- ack_drops
- peak_delay
- avge_delay
- base_delay
Other annotations are added in following patches, to ease code review.
--- net/sched/sch_cake.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
net/sched/sch_cake.c +20 -18
@@ -1590,7 +1590,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) sch->qstats.backlog -= len; flow->dropped++; - b->tin_dropped++; +WRITE_ONCE (b->tin_dropped, b->tin_dropped +1 );if (q->rate_flags &CAKE_FLAG_INGRESS )cake_advance_shaper (q, b, skb, now, true);
@@ -1808,7 +1808,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, numsegs++; slen += segs->len; q->buffer_used += segs->truesize; - b->packets++; +WRITE_ONCE (b->packets, b->packets +1 ); }/* stats */
@@ -1832,7 +1832,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, ack =cake_ack_filter (q, flow);if (ack) { - b->ack_drops++; +WRITE_ONCE (b->ack_drops, b->ack_drops +1 ); sch->qstats.drops++; ack_pkt_len =qdisc_pkt_len (ack); b->bytes += ack_pkt_len;
@@ -1848,7 +1848,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, }/* stats */ - b->packets++; +WRITE_ONCE (b->packets, b->packets +1 ); b->bytes += len - ack_pkt_len; b->backlogs[idx] += len - ack_pkt_len; b->tin_backlog += len - ack_pkt_len;
@@ -2191,7 +2191,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) b->tin_deficit -= len; } flow->dropped++; - b->tin_dropped++; +WRITE_ONCE (b->tin_dropped, b->tin_dropped +1 );qdisc_tree_reduce_backlog (sch,1 ,qdisc_pkt_len (skb));qdisc_qstats_drop (sch);kfree_skb_reason (skb, reason);
@@ -2199,16 +2199,18 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) goto retry; } - b->tin_ecn_mark += !!flow->cvars.ecn_marked; +WRITE_ONCE (b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked);qdisc_bstats_update (sch, skb);/* collect delay stats */ delay =ktime_to_ns (ktime_sub (now,cobalt_get_enqueue_time (skb))); - b->avge_delay =cake_ewma (b->avge_delay, delay,8 ); - b->peak_delay =cake_ewma (b->peak_delay, delay, - delay > b->peak_delay ?2 :8 ); - b->base_delay =cake_ewma (b->base_delay, delay, - delay < b->base_delay ?2 :8 ); +WRITE_ONCE (b->avge_delay,cake_ewma (b->avge_delay, delay,8 )); +WRITE_ONCE (b->peak_delay, +cake_ewma (b->peak_delay, delay, + delay > b->peak_delay ?2 :8 )); +WRITE_ONCE (b->base_delay, +cake_ewma (b->base_delay, delay, + delay < b->base_delay ?2 :8 )); len =cake_advance_shaper (q, b, skb, now, false); flow->deficit -= len;
@@ -2940,17 +2942,17 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (INTERVAL_US ,ktime_to_us (ns_to_ktime (b->cparams.interval))); -PUT_TSTAT_U32 (SENT_PACKETS , b->packets); -PUT_TSTAT_U32 (DROPPED_PACKETS , b->tin_dropped); -PUT_TSTAT_U32 (ECN_MARKED_PACKETS , b->tin_ecn_mark); -PUT_TSTAT_U32 (ACKS_DROPPED_PACKETS , b->ack_drops); +PUT_TSTAT_U32 (SENT_PACKETS ,READ_ONCE (b->packets)); +PUT_TSTAT_U32 (DROPPED_PACKETS ,READ_ONCE (b->tin_dropped)); +PUT_TSTAT_U32 (ECN_MARKED_PACKETS ,READ_ONCE (b->tin_ecn_mark)); +PUT_TSTAT_U32 (ACKS_DROPPED_PACKETS ,READ_ONCE (b->ack_drops));PUT_TSTAT_U32 (PEAK_DELAY_US , -ktime_to_us (ns_to_ktime (b->peak_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->peak_delay))));PUT_TSTAT_U32 (AVG_DELAY_US , -ktime_to_us (ns_to_ktime (b->avge_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->avge_delay))));PUT_TSTAT_U32 (BASE_DELAY_US , -ktime_to_us (ns_to_ktime (b->base_delay))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->base_delay))));PUT_TSTAT_U32 (WAY_INDIRECT_HITS , b->way_hits);PUT_TSTAT_U32 (WAY_MISSES , b->way_misses);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 822/957 net/sched: sch_cake: annotate data-races in cake_dump_stats() (V)
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ]
cake_dump_stats() runs without qdisc spinlock being held.
In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations for cparams.target and cparams.interval.
--- net/sched/sch_cake.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
net/sched/sch_cake.c +7 -6
@@ -2305,10 +2305,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, byte_target_ns = (byte_target * rate_ns) >> rate_shft; - b->cparams.target =max ((byte_target_ns *3 ) /2 , target_ns); - b->cparams.interval =max (rtt_est_ns + - b->cparams.target - target_ns, - b->cparams.target *2 ); +WRITE_ONCE (b->cparams.target, +max ((byte_target_ns *3 ) /2 , target_ns)); +WRITE_ONCE (b->cparams.interval, +max (rtt_est_ns + b->cparams.target - target_ns, + b->cparams.target *2 )); b->cparams.mtu_time = byte_target_ns; b->cparams.p_inc =1 <<24 ;/* 1/256 */ b->cparams.p_dec =1 <<20 ;/* 1/4096 */
@@ -2938,9 +2939,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (BACKLOG_BYTES , b->tin_backlog);PUT_TSTAT_U32 (TARGET_US , -ktime_to_us (ns_to_ktime (b->cparams.target))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.target))));PUT_TSTAT_U32 (INTERVAL_US , -ktime_to_us (ns_to_ktime (b->cparams.interval))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.interval))));PUT_TSTAT_U32 (SENT_PACKETS ,READ_ONCE (b->packets));PUT_TSTAT_U32 (DROPPED_PACKETS ,READ_ONCE (b->tin_dropped));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 823/957 netconsole: propagate device name truncation in dev_name_store()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ]
dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without checking the return value. If userspace writes an interface name longer than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but the function ignores it and reports a fully successful write back to userspace.
If a real interface happens to match the truncated name, netconsole will bind to the wrong device on the next enable, sending kernel logs and panic output to an unintended network segment with no indication to userspace that anything was rewritten.
Reject writes whose length cannot fit in nt->np.dev_name up front:
if (count >= IFNAMSIZ) return -ENAMETOOLONG;
This is not a big deal of a problem, but, it is still the correct approach.
--- drivers/net/netconsole.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/netconsole.c +7 -0
@@ -694,6 +694,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, size_t count) {struct netconsole_target *nt =to_target (item); +size_t len = count; + +/* Account for a trailing newline appended by tools like echo */ +if (len && buf[len -1 ] =='\n' ) + len--; +if (len >=IFNAMSIZ ) +return -ENAMETOOLONG ;mutex_lock (&dynamic_netconsole_mutex);if (nt->enabled) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 824/957 ALSA: hda/conexant: Fix missing error check for jack detection
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: wangdicheng <[email protected]>
[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ]
In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() is ignored. This function returns a pointer, and if it fails (e.g., due to memory allocation failure), it returns an error pointer which must be checked using IS_ERR().
If the registration fails, the driver continues to probe, but the jack detection callback will not be registered. This can lead to a kernel crash later when the driver attempts to handle jack events or accesses the uninitialized structure.
Check the return value using IS_ERR() and propagate the error via PTR_ERR() to the probe caller.
--- sound/hda/codecs/conexant.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
sound/hda/codecs/conexant.c +7 -1
@@ -1183,6 +1183,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)static int cx_probe (struct hda_codec *codec,const struct hda_device_id *id) {struct conexant_spec *spec; +struct hda_jack_callback *callback;int err;codec_info (codec,"%s: BIOS auto-probing.\n" , codec->core.chip_name);
@@ -1198,7 +1199,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)case 0x14f11f86 :case 0x14f11f87 : spec->is_cx11880_sn6140 = true; -snd_hda_jack_detect_enable_callback (codec,0x19 , cx_update_headset_mic_vref); + callback =snd_hda_jack_detect_enable_callback (codec,0x19 , + cx_update_headset_mic_vref); +if (IS_ERR (callback)) { + err =PTR_ERR (callback); + goto error; + }break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 825/957 ALSA: hda: cs35l56: Fix uninitialized value in cs35l56_hda_read_acpi()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ]
Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a system-specific quirk overrides processing of the dev-index property. The value is now stored in a new 'num_amps' member of struct cs35l56_hda so that the quirk handler can set the value.
The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would then skip reading the property. But this left the 'nval' local variable uninitialized when it is later passed to cirrus_scodec_get_speaker_id().
--- sound/hda/codecs/side-codecs/cs35l56_hda.c | 12 +++++++----- sound/hda/codecs/side-codecs/cs35l56_hda.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-)
sound/hda/codecs/side-codecs/cs35l56_hda.c +7 -5
@@ -884,6 +884,7 @@ static int cs35l56_hda_system_resume(struct device *dev)static int cs35l56_hda_fixup_yoga9 (struct cs35l56_hda *cs35l56,int *bus_addr) {/* The cirrus,dev-index property has the wrong values */ + cs35l56->num_amps =2 ;switch (*bus_addr) {case 0x30 : cs35l56->index =1 ;
@@ -933,7 +934,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)char hid_string[8 ];struct acpi_device *adev;const char *property, *sub; -size_t nval;int i, ret;/*
@@ -969,13 +969,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) ret = -EINVAL ; goto err; } - nval = ret; + cs35l56->num_amps = ret; - ret =device_property_read_u32_array (cs35l56->base.dev, property, values, nval); + ret =device_property_read_u32_array (cs35l56->base.dev, property, values, + cs35l56->num_amps);if (ret) goto err; -for (i =0 ; i < nval; i++) { +for (i =0 ; i < cs35l56->num_amps; i++) {if (values[i] == id) { cs35l56->index = i;break ;
@@ -998,7 +999,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)"Read ACPI _SUB failed(%ld): fallback to generic firmware\n" , PTR_ERR(sub)); }else { - ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, nval,-1 ); + ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, + cs35l56->num_amps,-1 );if (ret == -ENOENT ) { cs35l56->system_name = sub; }else if (ret >=0 ) {
sound/hda/codecs/side-codecs/cs35l56_hda.h +1 -0
@@ -25,6 +25,7 @@ struct cs35l56_hda {struct work_struct dsp_work;int index; +int num_amps;const char *system_name;const char *amp_name;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 826/957 ALSA: hda/tas2781: Fix incorrect bit update for non-book-zero or book 0 pages >1
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shenghao Ding <[email protected]>
[ Upstream commit e052a1f7199260eda4d6ca08a59c3b98738f8491 ]
In TAS2781 SPI mode, when accessing non-book-zero or page numbers greater than 1 in book 0, an additional byte must be read. The first byte in such cases is a dummy byte and should be ignored.
--- sound/hda/codecs/side-codecs/tas2781_hda_spi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
sound/hda/codecs/side-codecs/tas2781_hda_spi.c +11 -3
@@ -135,10 +135,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,int ret, val;/* -* In our TAS2781 SPI mode, read/write was masked in last bit of -* address, it cause regmap_update_bits() not work as expected. +* In TAS2781 SPI mode, when accessing non-book-zero or page numbers +* greater than 1 in book 0, an additional byte must be read. The +* first byte in such cases is a dummy byte and should be ignored. */ - ret =tasdevice_dev_read (tas_priv, chn, reg, &val); +if ((TASDEVICE_BOOK_ID (reg) >0 ) || (TASDEVICE_PAGE_ID (reg) >1 )) { +unsigned char buf[2 ]; + + ret =tasdevice_dev_bulk_read (tas_priv, chn, reg, buf,2 ); + val = buf[1 ]; + }else { + ret =tasdevice_dev_read (tas_priv, chn, reg, &val); + }if (ret <0 ) {dev_err (tas_priv->dev,"%s, E=%d\n" , __func__, ret);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 827/957 futex: Prevent lockup in requeue-PI during signal/ timeout wakeup
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ]
During wait-requeue-pi (task A) and requeue-PI (task B) the following race can happen:
Task A Task B
futex_wait_requeue_pi()
futex_setup_timer()
futex_do_wait()
futex_requeue()
CLASS(hb, hb1)(&key1);
CLASS(hb, hb2)(&key2);
*timeout*
futex_requeue_pi_wakeup_sync()
requeue_state = Q_REQUEUE_PI_IGNORE
*blocks on hb->lock*
futex_proxy_trylock_atomic()
futex_requeue_pi_prepare()
Q_REQUEUE_PI_IGNORE => -EAGAIN
double_unlock_hb(hb1, hb2)
*retry*Task B acquires both hb locks and attempts to acquire the PI-lock of the top most waiter (task B). Task A is leaving early due to a signal/ timeout and started removing itself from the queue. It updates its requeue_state but can not remove it from the list because this requires the hb lock which is owned by task B.
Usually task A is able to swoop the lock after task B unlocked it. However if task B is of higher priority then task A may not be able to wake up in time and acquire the lock before task B gets it again. Especially on a UP system where A is never scheduled.
As a result task A blocks on the lock and task B busy loops, trying to make progress but live locks the system instead. Tragic.
This can be fixed by removing the top most waiter from the list in this case. This allows task B to grab the next top waiter (if any) in the next iteration and make progress.
Remove the top most waiter if futex_requeue_pi_prepare() fails. Let the waiter conditionally remove itself from the list in handle_early_requeue_pi_wakeup().
--- kernel/futex/requeue.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/futex/requeue.c +9 -4
@@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,return -EINVAL ;/* Ensure that this does not race against an early wakeup */ -if (!futex_requeue_pi_prepare (top_waiter,NULL )) +if (!futex_requeue_pi_prepare (top_waiter,NULL )) { +plist_del (&top_waiter->list, &hb1->chain); +futex_hb_waiters_dec (hb1);return -EAGAIN ; + }/* * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit
@@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,/* * We were woken prior to requeue by a timeout or a signal. -* Unqueue the futex_q and determine which it was. +* Conditionally unqueue the futex_q and determine which it was. */ -plist_del (&q->list, &hb->chain); -futex_hb_waiters_dec (hb); +if (!plist_node_empty (&q->list)) { +plist_del (&q->list, &hb->chain); +futex_hb_waiters_dec (hb); + }/* Handle spurious wakeups gracefully */ ret = -EWOULDBLOCK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 828/957 drm/amd/display: Allow DCE link encoder without AUX registers
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ]
Allow constructing the DCE link encoder without DDC, which means the AUX registers array will be NULL.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +3 -1
@@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init(ASSERT (result ==BP_RESULT_OK ); } -aux_initialize (enc110); + +if (enc110->aux_regs) +aux_initialize (enc110);/* reinitialize HPD. * hpd_initialize() will pass DIG_FE id to HW context.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 829/957 drm/amd/display: Allow constructing DCE6 link encoder without DDC
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 880498a1943f865529819f778df3b9945ca57262 ]
When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, pass NULL to the AUX regs array.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +2 -1
@@ -728,7 +728,8 @@ static struct link_encoder *dce60_link_encoder_create( enc_init_data, &link_enc_feature, &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel -1 ], + enc_init_data->channel ==CHANNEL_ID_UNKNOWN ? +NULL : &link_enc_aux_regs[enc_init_data->channel -1 ], enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 830/957 drm/amd/display: Allow constructing DCE8 link encoder without DDC
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 60af4605ef35ecb7ad649a8534b83a2f7c69576d ]
When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, pass NULL to the AUX regs array.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +2 -1
@@ -734,7 +734,8 @@ static struct link_encoder *dce80_link_encoder_create( enc_init_data, &link_enc_feature, &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel -1 ], + enc_init_data->channel ==CHANNEL_ID_UNKNOWN ? +NULL : &link_enc_aux_regs[enc_init_data->channel -1 ], enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 831/957 drm/amd/display: Read EDID from VBIOS embedded panel info
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ]
Some board manufacturers hardcode the EDID for the embedded panel in the VBIOS. This EDID should be used when the panel doesn't have a DDC.
For reference, see the legacy non-DC display code:amdgpu_atombios_encoder_get_lcd_info()
This is necessary to support embedded connectors without DDC.
--- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ .../display/include/grph_object_ctrl_defs.h | 4 ++ 2 files changed, 66 insertions(+)
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +62 -0
@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(return BP_RESULT_FAILURE ; } +static enum bp_result get_embedded_panel_extra_info ( +struct bios_parser *bp, +struct embedded_panel_info *info, +const uint32_t table_offset) +{ +uint8_t *record =bios_get_image (&bp->base, table_offset,1 ); +ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; +ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; + +while (*record !=ATOM_RECORD_END_TYPE ) { +switch (*record) { +case LCD_MODE_PATCH_RECORD_MODE_TYPE : + record +=sizeof (ATOM_PATCH_RECORD_MODE ); +break ; +case LCD_RTS_RECORD_TYPE : + record +=sizeof (ATOM_LCD_RTS_RECORD ); +break ; +case LCD_CAP_RECORD_TYPE : + record +=sizeof (ATOM_LCD_MODE_CONTROL_CAP ); +break ; +case LCD_FAKE_EDID_PATCH_RECORD_TYPE : + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; +if (fake_edid_record->ucFakeEDIDLength) { +if (fake_edid_record->ucFakeEDIDLength ==128 ) + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength; +else + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength *128 ; + + info->fake_edid = fake_edid_record->ucFakeEDIDString; + + record +=struct_size (fake_edid_record, + ucFakeEDIDString, + info->fake_edid_size); + }else { +/* empty fake edid record must be 3 bytes long */ + record +=sizeof (ATOM_FAKE_EDID_PATCH_RECORD ) +1 ; + } +break ; +case LCD_PANEL_RESOLUTION_RECORD_TYPE : + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; + info->panel_width_mm = panel_res_record->usHSize; + info->panel_height_mm = panel_res_record->usVSize; + record +=sizeof (ATOM_PANEL_RESOLUTION_PATCH_RECORD ); +break ; +default : +return BP_RESULT_BADBIOSTABLE ; + } + } + +return BP_RESULT_OK ; +} +static enum bp_result get_embedded_panel_info_v1_2 (struct bios_parser *bp,struct embedded_panel_info *info)
@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2(if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) info->lcd_timing.misc_info.API_ENABLED = true; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( (uint32_t ) (ATOM_PANEL_MISC_V13_GREY_LEVEL & lvds->ucLCD_Misc) >>ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT ; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +4 -0
@@ -153,6 +153,10 @@ struct embedded_panel_info {uint32_t drr_enabled;uint32_t min_drr_refresh_rate;bool realtek_eDPToLVDS; +uint16_t panel_width_mm; +uint16_t panel_height_mm; +uint16_t fake_edid_size; +const uint8_t *fake_edid; };struct dc_firmware_info {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 832/957 drm/xe/debugfs: Correct printing of register whitelist ranges
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Roper <[email protected]>
[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ]
The register-save-restore debugfs prints whitelist entries as offset ranges. E.g.,
REG[0x39319c-0x39319f]: allow read access
for a single dword-sized register. However the GENMASK value used to set the lower bits to '1' for the upper bound of the whitelist range incorrectly included one more bit than it should have, causing the whitelist ranges to sometimes appear twice as large as they really were. For example,
REG[0x6210-0x6217]: allow rw access
was also intended to be a single dword-sized register whitelist (with a range 0x6210-0x6213) but was printed incorrectly as a qword-sized range because one too many bits was flipped on. Similar 'off by one' logic was applied when printing 4-dword register ranges and 64-dword register ranges as well.
Correct the GENMASK logic to print these ranges in debugfs correctly. No impact outside of correcting the misleading debugfs output.
--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_reg_whitelist.c +1 -1
@@ -174,7 +174,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, } range_start = reg ®_GENMASK (25 , range_bit); - range_end = range_start |REG_GENMASK (range_bit,0 ); + range_end = range_start |REG_GENMASK (range_bit -1 ,0 );switch (val &RING_FORCE_TO_NONPRIV_ACCESS_MASK ) {case RING_FORCE_TO_NONPRIV_ACCESS_RW :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 833/957 drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ]
Two error handling issues exist in xe_exec_queue_create_ioctl():
1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in preempt fence mode, xe_vm_add_compute_exec_queue() has already added the queue to the VM's compute exec queue list. Skipping the kill leaves the queue on that list, leading to a dangling pointer after the queue is freed.
2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has succeeded, the error path does not call xe_hw_engine_group_del_exec_queue() to remove the queue from the hw engine group list. The queue is then freed while still linked into the hw engine group, causing a use-after-free.
Fix both by:
- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump to kill_exec_queue so that xe_exec_queue_kill() properly removes the queue from the VM's compute list.
- Adding a del_hw_engine_group label before kill_exec_queue for the xa_alloc() failure path, which removes the queue from the hw engine group before proceeding with the rest of the cleanup.
--- drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_exec_queue.c +5 -2
@@ -789,7 +789,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,if (q->vm && q->hwe->hw_engine_group) { err =xe_hw_engine_group_add_exec_queue (q->hwe->hw_engine_group, q);if (err) - goto put_exec_queue; + goto kill_exec_queue; } }
@@ -798,12 +798,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,/* user id alloc must always be last in ioctl to prevent UAF */ err =xa_alloc (&xef->exec_queue.xa, &id, q, xa_limit_32b,GFP_KERNEL );if (err) - goto kill_exec_queue; + goto del_hw_engine_group; args->exec_queue_id = id;return 0 ; +del_hw_engine_group: +if (q->vm && q->hwe && q->hwe->hw_engine_group) +xe_hw_engine_group_del_exec_queue (q->hwe->hw_engine_group, q); kill_exec_queue:xe_exec_queue_kill (q); put_exec_queue:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 834/957 drm/xe/eustall: Fix drm_dev_put called before stream disable in close
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit dc2d9842c67d883d3200ae33b9c3859dd9492408 ]
In xe_eu_stall_stream_close(), drm_dev_put() is called before the stream is disabled and its resources are freed. If this drops the last reference, the device structures could be freed while the subsequent cleanup code still accesses them, leading to a use-after-free.
Fix this by moving drm_dev_put() after all device accesses are complete. This matches the ordering in xe_oa_release().
--- drivers/gpu/drm/xe/xe_eu_stall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_eu_stall.c +2 -2
@@ -845,14 +845,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)struct xe_eu_stall_data_stream *stream = file->private_data;struct xe_gt *gt = stream->gt; -drm_dev_put (>->tile->xe->drm); -mutex_lock (>->eu_stall->stream_lock);xe_eu_stall_disable_locked (stream);xe_eu_stall_data_buf_destroy (stream);xe_eu_stall_stream_free (stream);mutex_unlock (>->eu_stall->stream_lock); +drm_dev_put (>->tile->xe->drm); +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 835/957 drm/xe/gsc: Fix BO leak on error in query_compatibility_version()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ]
When xe_gsc_read_out_header() fails, query_compatibility_version() returns directly instead of jumping to the out_bo label. This skips the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped with no remaining reference to free it.
Fix by using goto out_bo so the error path properly cleans up the BO, consistent with the other error handling in the same function.
--- drivers/gpu/drm/xe/xe_gsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_gsc.c +1 -1
@@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) &rd_offset);if (err) {xe_gt_err (gt,"HuC: invalid GSC reply for version query (err=%d)\n" , err); -return err; + goto out_bo; } compat->major =version_query_rd (xe, &bo->vmap, rd_offset, proj_major);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 836/957 net: airoha: fix BQL imbalance in TX path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 2d9f5a118205da2683ffcec78b9347f1f01a820e ]
Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight packets are accounted only for the AIROHA_NUM_TX_RING netdev TX queues. The queue index is computed as:
qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx)
txq = netdev_get_tx_queue(dev, qid);However, airoha_qdma_tx_napi_poll() accounts completions across all netdev TX queues (num_tx_queues), leading to inconsistent BQL accounting.
Also reset all netdev TX queues in the ndo_stop callback.
Stable-dep-of: 4ca01292ea2f ("net: airoha: Do not return err in ndo_stop() callback")
--- drivers/net/ethernet/airoha/airoha_eth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +3 -4
@@ -971,10 +971,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) q->queued--;if (skb) { -u16 queue =skb_get_queue_mapping (skb);struct netdev_queue *txq; - txq =netdev_get_tx_queue (skb->dev, queue); + txq =skb_get_tx_queue (skb->dev, skb);netdev_tx_completed_queue (txq,1 , skb->len);dev_kfree_skb_any (skb); }
@@ -1777,7 +1776,7 @@ static int airoha_dev_stop(struct net_device *dev)if (err)return err; -for (i =0 ; i <ARRAY_SIZE (qdma->q_tx); i++) +for (i =0 ; i < dev->num_tx_queues; i++)netdev_tx_reset_subqueue (dev, i);if (atomic_dec_and_test (&qdma->users)) {
@@ -2066,7 +2065,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,spin_lock_bh (&q->lock); - txq =netdev_get_tx_queue (dev, qid); + txq =skb_get_tx_queue (dev, skb); nr_frags =1 +skb_shinfo (skb)->nr_frags;if (q->queued + nr_frags >= q->ndesc) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 837/957 net: airoha: Do not return err in ndo_stop() callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 4ca01292ea2f2363660610a65ba0285d7c3309ed ]
Always complete the airoha_dev_stop() routine regardless of the airoha_set_vip_for_gdm_port() return value, since errors from ndo_stop() are ignored by the networking stack and the interface is always considered down after the call.
--- drivers/net/ethernet/airoha/airoha_eth.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +2 -5
@@ -1769,13 +1769,10 @@ static int airoha_dev_stop(struct net_device *dev) {struct airoha_gdm_port *port =netdev_priv (dev);struct airoha_qdma *qdma = port->qdma; -int i, err; +int i;netif_tx_disable (dev); - err =airoha_set_vip_for_gdm_port (port, false); -if (err) -return err; - +airoha_set_vip_for_gdm_port (port, false);for (i =0 ; i < dev->num_tx_queues; i++)netdev_tx_reset_subqueue (dev, i);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 838/957 bonding: print churn state via netlink
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu <[email protected]>
[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ]
Currently, the churn state is printed only in sysfs. Add netlink support so users could get the state via netlink.
Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator")
--- drivers/net/bonding/bond_netlink.c | 9 +++++++++ include/uapi/linux/if_link.h | 2 ++ 2 files changed, 11 insertions(+)
drivers/net/bonding/bond_netlink.c +9 -0
@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev,nla_total_size (sizeof (u16)) +/* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ nla_total_size (sizeof (s32)) +/* IFLA_BOND_SLAVE_PRIO */ nla_total_size (sizeof (u16)) +/* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ +nla_total_size (sizeof (u8)) +/* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ +nla_total_size (sizeof (u8)) +/* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ 0 ; }
@@ -77,6 +79,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, ad_port->partner_oper.port_state)) goto nla_put_failure; + +if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , + ad_port->sm_churn_actor_state)) + goto nla_put_failure; +if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , + ad_port->sm_churn_partner_state)) + goto nla_put_failure; } if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
include/uapi/linux/if_link.h +2 -0
@@ -1567,6 +1567,8 @@ enum {IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE ,IFLA_BOND_SLAVE_PRIO ,IFLA_BOND_SLAVE_ACTOR_PORT_PRIO , +IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , +IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , __IFLA_BOND_SLAVE_MAX, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 839/957 bonding: 3ad: implement proper RCU rules for port->aggregator
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ]
syzbot found a data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler [1] which hints at lack of proper RCU implementation.
Add __rcu qualifier to port->aggregator, and add proper RCU API.
[1]
BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler
write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0:
ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 process_one_work kernel/workqueue.c:3302 [inline] process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 worker_thread+0x58a/0x780 kernel/workqueue.c:3466 kthread+0x22a/0x280 kernel/kthread.c:436 ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1:
__bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 netif_change_flags+0xac/0xd0 net/core/dev.c:9823 do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] __rtnl_newlink net/core/rtnetlink.c:3981 [inline] rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 sock_sendmsg_nosec net/socket.c:787 [inline] __sock_sendmsg net/socket.c:802 [inline] ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 __sys_sendmsg net/socket.c:2784 [inline] __do_sys_sendmsg net/socket.c:2789 [inline] __se_sys_sendmsg net/socket.c:2787 [inline] __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x0000000000000000 -> 0xffff88813cf5c400
Reported by Kernel Concurrency Sanitizer on:
CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) Tainted: [W]=WARN Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
--- drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- drivers/net/bonding/bond_main.c | 8 +- drivers/net/bonding/bond_netlink.c | 16 ++-- drivers/net/bonding/bond_procfs.c | 3 +- drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- include/net/bond_3ad.h | 2 +- 6 files changed, 89 insertions(+), 66 deletions(-)
drivers/net/bonding/bond_3ad.c +60 -49
@@ -1014,6 +1014,7 @@ static void ad_cond_set_peer_notif(struct port *port)static void ad_mux_machine (struct port *port,bool *update_slave_arr) {struct bonding *bond =__get_bond_by_port (port); +struct aggregator *aggregator;mux_states_t last_state;/* keep current State Machine state to compare later if it was
@@ -1021,6 +1022,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)*/ last_state = port->sm_mux_state; + aggregator =rcu_dereference (port->aggregator);if (port->sm_vars &AD_PORT_BEGIN ) { port->sm_mux_state =AD_MUX_DETACHED ; }else {
@@ -1040,7 +1042,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* cycle to update ready variable, we check * READY_N and update READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); port->sm_mux_state =AD_MUX_DETACHED ;break ; }
@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* update ready variable, we check READY_N and update * READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator));/* if the wait_while_timer expired, and the port is * in READY state, move to ATTACHED state
@@ -1071,7 +1073,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)if ((port->sm_vars &AD_PORT_SELECTED ) && (port->partner_oper.port_state &LACP_STATE_SYNCHRONIZATION ) && !__check_agg_selection_timer (port)) { -if (port->aggregator->is_active) { +if (aggregator->is_active) {int state =AD_MUX_COLLECTING_DISTRIBUTING ;if (!bond->params.coupled_control)
@@ -1087,9 +1089,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* cycle to update ready variable, we check * READY_N and update READY here */ -__set_agg_ports_ready (port->aggregator,__agg_ports_are_ready (port->aggregator)); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); port->sm_mux_state =AD_MUX_DETACHED ; - }else if (port->aggregator->is_active) { + }else if (aggregator->is_active) { port->actor_oper_port_state |=LACP_STATE_SYNCHRONIZATION ; }
@@ -1100,7 +1102,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* sure that a collecting distributing * port in an active aggregator is enabled */ -if (port->aggregator->is_active && +if (aggregator->is_active && !__port_is_collecting_distributing (port)) {__enable_port (port); *update_slave_arr = true;
@@ -1119,7 +1121,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)*/ struct slave *slave = port->slave; -if (port->aggregator->is_active && +if (aggregator->is_active &&bond_is_slave_rx_disabled (slave)) {ad_enable_collecting (port); *update_slave_arr = true;
@@ -1139,8 +1141,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)* sure that a collecting distributing * port in an active aggregator is enabled */ -if (port->aggregator && - port->aggregator->is_active && +if (aggregator && + aggregator->is_active && !__port_is_collecting_distributing (port)) {__enable_port (port); *update_slave_arr = true;
@@ -1172,7 +1174,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) port->sm_mux_timer_counter =__ad_timer_to_ticks (AD_WAIT_WHILE_TIMER ,0 );break ;case AD_MUX_ATTACHED : -if (port->aggregator->is_active) +if (aggregator->is_active) port->actor_oper_port_state |=LACP_STATE_SYNCHRONIZATION ;else
@@ -1546,9 +1548,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) bond =__get_bond_by_port (port);/* if the port is connected to other aggregator, detach it */ -if (port->aggregator) { + temp_aggregator =rcu_dereference (port->aggregator); +if (temp_aggregator) {/* detach the port from its former aggregator */ - temp_aggregator = port->aggregator;for (curr_port = temp_aggregator->lag_ports; curr_port; last_port = curr_port, curr_port = curr_port->next_port_in_aggregator) {
@@ -1571,7 +1573,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)/* clear the port's relations to this * aggregator */ - port->aggregator =NULL ; +RCU_INIT_POINTER (port->aggregator,NULL ); port->next_port_in_aggregator =NULL ; port->actor_port_aggregator_identifier =0 ;
@@ -1594,7 +1596,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) port->slave->bond->dev->name, port->slave->dev->name, port->actor_port_number, - port->aggregator->aggregator_identifier); + temp_aggregator->aggregator_identifier); } }/* search on all aggregators for a suitable aggregator for this port */
@@ -1618,15 +1620,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) ) ) {/* attach to the founded aggregator */ - port->aggregator = aggregator; +rcu_assign_pointer (port->aggregator, aggregator); port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + aggregator->aggregator_identifier; port->next_port_in_aggregator = aggregator->lag_ports; - port->aggregator->num_of_ports++; + aggregator->num_of_ports++; aggregator->lag_ports = port;slave_dbg (bond->dev, slave->dev,"Port %d joined LAG %d (existing LAG)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);/* mark this port as selected */ port->sm_vars |=AD_PORT_SELECTED ;
@@ -1641,39 +1643,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)if (!found) {if (free_aggregator) {/* assign port a new aggregator */ - port->aggregator = free_aggregator; port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + free_aggregator->aggregator_identifier;/* update the new aggregator's parameters * if port was responsed from the end-user */ if (port->actor_oper_port_key &AD_DUPLEX_KEY_MASKS )/* if port is full duplex */ - port->aggregator->is_individual = false; + free_aggregator->is_individual = false;else - port->aggregator->is_individual = true; + free_aggregator->is_individual = true; - port->aggregator->actor_admin_aggregator_key = + free_aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; - port->aggregator->actor_oper_aggregator_key = + free_aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system = + free_aggregator->partner_system = port->partner_oper.system; - port->aggregator->partner_system_priority = + free_aggregator->partner_system_priority = port->partner_oper.system_priority; - port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; - port->aggregator->receive_state =1 ; - port->aggregator->transmit_state =1 ; - port->aggregator->lag_ports = port; - port->aggregator->num_of_ports++; + free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; + free_aggregator->receive_state =1 ; + free_aggregator->transmit_state =1 ; + free_aggregator->lag_ports = port; + free_aggregator->num_of_ports++; + +rcu_assign_pointer (port->aggregator, free_aggregator);/* mark this port as selected */ port->sm_vars |=AD_PORT_SELECTED ;slave_dbg (bond->dev, port->slave->dev,"Port %d joined LAG %d (new LAG)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + free_aggregator->aggregator_identifier); }else { slave_err(bond->dev, port->slave->dev, "Port %d did not find a suitable aggregator\n",
@@ -1685,13 +1688,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)* in all aggregator's ports, else set ready=FALSE in all * aggregator's ports */ -__set_agg_ports_ready (port->aggregator, -__agg_ports_are_ready (port->aggregator)); + aggregator =rcu_dereference (port->aggregator); +__set_agg_ports_ready (aggregator,__agg_ports_are_ready (aggregator)); - aggregator =__get_first_agg (port); -ad_agg_selection_logic (aggregator, update_slave_arr); +ad_agg_selection_logic (__get_first_agg (port), update_slave_arr); -if (!port->aggregator->is_active) +if (!aggregator->is_active) port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION ; }
@@ -2060,13 +2062,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond*/ static void ad_enable_collecting (struct port *port) { -if (port->aggregator->is_active) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator->is_active) {struct slave *slave = port->slave;slave_dbg (slave->bond->dev, slave->dev,"Enabling collecting on port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__enable_collecting_port (port); } }
@@ -2078,11 +2082,13 @@ static void ad_enable_collecting(struct port *port)*/ static void ad_disable_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator &&__agg_has_partner (port->aggregator)) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator &&__agg_has_partner (aggregator)) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Disabling distributing on port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__disable_distributing_port (port);/* Slave array needs an update */ *update_slave_arr = true;
@@ -2099,11 +2105,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr)static void ad_enable_collecting_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator->is_active) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator->is_active) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Enabling port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__enable_port (port);/* Slave array needs update */ *update_slave_arr = true;
@@ -2120,11 +2128,13 @@ static void ad_enable_collecting_distributing(struct port *port,static void ad_disable_collecting_distributing (struct port *port,bool *update_slave_arr) { -if (port->aggregator &&__agg_has_partner (port->aggregator)) { +struct aggregator *aggregator =rcu_dereference (port->aggregator); + +if (aggregator &&__agg_has_partner (aggregator)) {slave_dbg (port->slave->bond->dev, port->slave->dev,"Disabling port %d (LAG %d)\n" , port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier);__disable_port (port);/* Slave array needs an update */ *update_slave_arr = true;
@@ -2364,7 +2374,7 @@ void bond_3ad_unbind_slave(struct slave *slave)*/ for (temp_port = aggregator->lag_ports; temp_port; temp_port = temp_port->next_port_in_aggregator) { - temp_port->aggregator = new_aggregator; +rcu_assign_pointer (temp_port->aggregator, new_aggregator); temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; }
@@ -2833,15 +2843,16 @@ int bond_3ad_set_carrier(struct bonding *bond)int __bond_3ad_get_active_agg_info (struct bonding *bond,struct ad_info *ad_info) { -struct aggregator *aggregator =NULL ; +struct aggregator *aggregator =NULL , *tmp;struct list_head *iter;struct slave *slave;struct port *port;bond_for_each_slave_rcu (bond, slave, iter) { port = &(SLAVE_AD_INFO (slave)->port); -if (port->aggregator && port->aggregator->is_active) { - aggregator = port->aggregator; + tmp =rcu_dereference (port->aggregator); +if (tmp && tmp->is_active) { + aggregator = tmp;break ; } }
drivers/net/bonding/bond_main.c +5 -3
@@ -1402,7 +1402,7 @@ static void bond_poll_controller(struct net_device *bond_dev)if (BOND_MODE (bond) ==BOND_MODE_8023AD ) {struct aggregator *agg = -SLAVE_AD_INFO (slave)->port.aggregator; +rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (agg && agg->aggregator_identifier != ad_info.aggregator_id)
@@ -5155,15 +5155,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)spin_unlock_bh (&bond->mode_lock); agg_id = ad_info.aggregator_id; } +rcu_read_lock ();bond_for_each_slave (bond, slave, iter) {if (skipslave == slave)continue ; all_slaves->arr[all_slaves->count++] = slave;if (BOND_MODE (bond) ==BOND_MODE_8023AD ) { -struct aggregator *agg; +const struct aggregator *agg; - agg =SLAVE_AD_INFO (slave)->port.aggregator; + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (!agg || agg->aggregator_identifier != agg_id)continue ; }
@@ -5175,6 +5176,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) usable_slaves->arr[usable_slaves->count++] = slave; } +rcu_read_unlock ();bond_set_slave_arr (bond, usable_slaves, all_slaves);return ret;
drivers/net/bonding/bond_netlink.c +10 -6
@@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb,const struct port *ad_port; ad_port = &SLAVE_AD_INFO (slave)->port; - agg =SLAVE_AD_INFO (slave)->port.aggregator; +rcu_read_lock (); + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator);if (agg) {if (nla_put_u16 (skb,IFLA_BOND_SLAVE_AD_AGGREGATOR_ID , agg->aggregator_identifier)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE , ad_port->actor_oper_port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u16 (skb,IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE , ad_port->partner_oper.port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE , ad_port->sm_churn_actor_state)) - goto nla_put_failure; + goto nla_put_failure_rcu;if (nla_put_u8 (skb,IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE , ad_port->sm_churn_partner_state)) - goto nla_put_failure; + goto nla_put_failure_rcu; } +rcu_read_unlock ();if (nla_put_u16 (skb,IFLA_BOND_SLAVE_ACTOR_PORT_PRIO ,SLAVE_AD_INFO (slave)->port_priority))
@@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb,return 0 ; +nla_put_failure_rcu: +rcu_read_unlock (); nla_put_failure:return -EMSGSIZE ; }
drivers/net/bonding/bond_procfs.c +2 -1
@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) } } +/* Note: runs under rcu_read_lock() */ static void bond_info_show_slave (struct seq_file *seq,const struct slave *slave) {
@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq,if (BOND_MODE (bond) ==BOND_MODE_8023AD ) {const struct port *port = &SLAVE_AD_INFO (slave)->port; -const struct aggregator *agg = port->aggregator; +const struct aggregator *agg =rcu_dereference (port->aggregator);if (agg) { seq_printf(seq, "Aggregator ID: %d\n",
drivers/net/bonding/bond_sysfs_slave.c +11 -6
@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)const struct aggregator *agg;if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { - agg =SLAVE_AD_INFO (slave)->port.aggregator; -if (agg) -return sysfs_emit (buf,"%d\n" , - agg->aggregator_identifier); +rcu_read_lock (); + agg =rcu_dereference (SLAVE_AD_INFO (slave)->port.aggregator); +if (agg) { +ssize_t res =sysfs_emit (buf,"%d\n" , + agg->aggregator_identifier); +rcu_read_unlock (); +return res; + } +rcu_read_unlock (); }return sysfs_emit (buf,"N/A\n" );
@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { ad_port = &SLAVE_AD_INFO (slave)->port; -if (ad_port->aggregator) +if (rcu_access_pointer (ad_port->aggregator))return sysfs_emit (buf,"%u\n" , ad_port->actor_oper_port_state); }
@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)if (BOND_MODE (slave->bond) ==BOND_MODE_8023AD ) { ad_port = &SLAVE_AD_INFO (slave)->port; -if (ad_port->aggregator) +if (rcu_access_pointer (ad_port->aggregator))return sysfs_emit (buf,"%u\n" , ad_port->partner_oper.port_state); }
include/net/bond_3ad.h +1 -1
@@ -243,7 +243,7 @@ typedef struct port {churn_state_t sm_churn_actor_state;churn_state_t sm_churn_partner_state;struct slave *slave;/* pointer to the bond slave that this port belongs to */ -struct aggregator *aggregator;/* pointer to an aggregator that this port related to */ +struct aggregator __rcu *aggregator;/* pointer to an aggregator that this port related to */ struct port *next_port_in_aggregator;/* Next port on the linked list of the parent aggregator */ u32 transaction_id;/* continuous number for identification of Marker PDU's; */ struct lacpdu lacpdu;/* the lacpdu that will be sent for this port */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 840/957 page_pool: fix memory-provider leak in page_pool_create_percpu() error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hasan Basbunar <[email protected]>
[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ]
When page_pool_create_percpu() fails on page_pool_list(), it falls through to its err_uninit: label, which calls page_pool_uninit(). At that point page_pool_init() has already taken two references when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM:
pool->mp_ops->init(pool) static_branch_inc(&page_pool_mem_providers);
Neither is undone by page_pool_uninit(); both are only undone by __page_pool_destroy() (success-side teardown). The error path therefore leaks the per-provider reference taken by mp_ops->init (io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf binding refcount in the devmem provider) plus one increment of the page_pool_mem_providers static branch on every failure of xa_alloc_cyclic() inside page_pool_list().
The leaked io_zcrx_ifq->refs in turn pins everything io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), ifq->mm_account (mmdrop), ifq->dev (device refcount), ifq->netdev_tracker (netdev refcount), and the rbuf region. The leaked static branch increment forces all subsequent page_pool_alloc_netmems() and page_pool_return_page() callers to take the slow mp_ops branch for the lifetime of the kernel.
Reachable via the io_uring zcrx path:
io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ -> __io_uring_register -> io_register_zcrx -> zcrx_register_netdev -> netif_mp_open_rxq -> driver ndo_queue_mem_alloc -> page_pool_create_percpu -> page_pool_init succeeds (mp_ops->init runs, branch++) -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) -> goto err_uninit <-- leak
The same shape applies to the devmem dmabuf provider via mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy().
Restore the cleanup symmetry by moving the mp_ops->destroy() and static_branch_dec() calls out of __page_pool_destroy() and into page_pool_uninit(), so page_pool_uninit() is again the strict inverse of page_pool_init(). page_pool_uninit() has only two callers (the err_uninit: path and __page_pool_destroy()), so this preserves the single-call invariant on the success path while fixing the err path. The error path of page_pool_init() itself still skips the mp_ops cleanup correctly: mp_ops->init is the last action that takes a reference before page_pool_init() returns 0, so when it returns an error neither the refcount nor the static branch has been touched.
Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, which under normal GFP_KERNEL retry behaviour is rare. It is deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / xa fault injection, or under sustained memory pressure. The leak is silent: there is no warning, and the released kernel build continues running with a permanently-incremented static branch.
--- net/core/page_pool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/page_pool.c +5 -5
@@ -323,6 +323,11 @@ static void page_pool_uninit(struct page_pool *pool)if (!pool->system)free_percpu (pool->recycle_stats);#endif + +if (pool->mp_ops) { + pool->mp_ops->destroy (pool); +static_branch_dec (&page_pool_mem_providers); + } }/**
@@ -1122,11 +1127,6 @@ static void __page_pool_destroy(struct page_pool *pool)page_pool_unlist (pool);page_pool_uninit (pool); -if (pool->mp_ops) { - pool->mp_ops->destroy (pool); -static_branch_dec (&page_pool_mem_providers); - } -kfree (pool); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 841/957 iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ]
Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better describe what the state represents: an ADD request has been sent to the PF and is waiting for a response.
This is a pure rename with no behavioral change, preparing for a cleanup of the VLAN filter state machine.
Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down")
--- drivers/net/ethernet/intel/iavf/iavf.h | 2 +- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -1
@@ -158,7 +158,7 @@ struct iavf_vlan {enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ -IAVF_VLAN_IS_NEW ,/* filter is new, wait for PF answer */ +IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -4
@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) { +if (f->state ==IAVF_VLAN_ADDING ) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--;
@@ -811,7 +811,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)if (f->state ==IAVF_VLAN_ADD ) { vvfl->vlan_id[i] = f->vlan.vid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ;if (i == count)break ; }
@@ -872,7 +872,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vlan->tpid = f->vlan.tpid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ; } }
@@ -2906,7 +2906,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) +if (f->state ==IAVF_VLAN_ADDING ) f->state =IAVF_VLAN_ACTIVE ; }spin_unlock_bh (&adapter->mac_vlan_list_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 842/957 iavf: stop removing VLAN filters from PF on interface down
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ]
When a VF goes down, the driver currently sends DEL_VLAN to the PF for every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> ACTIVE). This round-trip is unnecessary because:
1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, which already prevents all RX/TX traffic regardless of VLAN filter state.
2. The VLAN filters remaining in PF HW while the VF is down is harmless - packets matching those filters have nowhere to go with queues disabled.
3. The DEL+ADD cycle during down/up creates race windows where the VLAN filter list is incomplete. With spoofcheck enabled, the PF enables TX VLAN filtering on the first non-zero VLAN add, blocking traffic for any VLANs not yet re-added.
Remove the entire DISABLE/INACTIVE state machinery:
- Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values
- Remove iavf_restore_filters() and its call from iavf_open()
- Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), rename it to iavf_clear_mac_filters()
- Remove DEL_VLAN_FILTER scheduling from iavf_down()
- Remove all DISABLE/INACTIVE handling from iavf_del_vlans()
VLAN filters now stay ACTIVE across down/up cycles. Only explicit user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN filter deletion/re-addition.
--- drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- 3 files changed, 12 insertions(+), 66 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +2 -4
@@ -159,10 +159,8 @@ enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ -IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ -IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ -IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */ - IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ +IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +4 -35
@@ -801,27 +801,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)spin_unlock_bh (&adapter->mac_vlan_list_lock); } -/** -* iavf_restore_filters -* @adapter: board private structure -* -* Restore existing non MAC filters when VF netdev comes back up -**/ -static void iavf_restore_filters (struct iavf_adapter *adapter) -{ -struct iavf_vlan_filter *f; - -/* re-add all VLAN filters */ -spin_lock_bh (&adapter->mac_vlan_list_lock); - -list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_INACTIVE ) - f->state =IAVF_VLAN_ADD ; - } - -spin_unlock_bh (&adapter->mac_vlan_list_lock); - adapter->aq_required |=IAVF_FLAG_AQ_ADD_VLAN_FILTER ; -}/** * iavf_get_num_vlans_added - get number of VLANs added
@@ -1240,13 +1219,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) }/** -* iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF -* yet and mark other to be removed. +* iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark +* others to be removed. * @adapter: board private structure **/ -static void iavf_clear_mac_vlan_filters (struct iavf_adapter *adapter) +static void iavf_clear_mac_filters (struct iavf_adapter *adapter) { -struct iavf_vlan_filter *vlf, *vlftmp;struct iavf_mac_filter *f, *ftmp;spin_lock_bh (&adapter->mac_vlan_list_lock);
@@ -1265,11 +1243,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) } } -/* disable all VLAN filters */ -list_for_each_entry_safe (vlf, vlftmp, &adapter->vlan_filter_list, - list) - vlf->state =IAVF_VLAN_DISABLE ; -spin_unlock_bh (&adapter->mac_vlan_list_lock); }
@@ -1365,7 +1338,7 @@ void iavf_down(struct iavf_adapter *adapter)iavf_napi_disable_all (adapter);iavf_irq_disable (adapter); -iavf_clear_mac_vlan_filters (adapter); +iavf_clear_mac_filters (adapter);iavf_clear_cloud_filters (adapter);iavf_clear_fdir_filters (adapter);iavf_clear_adv_rss_conf (adapter);
@@ -1382,8 +1355,6 @@ void iavf_down(struct iavf_adapter *adapter)*/ if (!list_empty (&adapter->mac_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_MAC_FILTER ; -if (!list_empty (&adapter->vlan_filter_list)) - adapter->aq_required |=IAVF_FLAG_AQ_DEL_VLAN_FILTER ;if (!list_empty (&adapter->cloud_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_CLOUD_FILTER ;if (!list_empty (&adapter->fdir_list_head))
@@ -4492,8 +4463,6 @@ static int iavf_open(struct net_device *netdev)iavf_add_filter (adapter, adapter->hw.mac.addr);spin_unlock_bh (&adapter->mac_vlan_list_lock); -/* Restore filters that were removed with IFF_DOWN */ -iavf_restore_filters (adapter);iavf_restore_fdir_filters (adapter);iavf_configure (adapter);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +6 -27
@@ -909,22 +909,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -/* since VLAN capabilities are not allowed, we dont want to send -* a VLAN delete request because it will most likely fail and -* create unnecessary errors/noise, so just free the VLAN -* filters marked for removal to enable bailing out before -* sending a virtchnl message -*/ if (f->state ==IAVF_VLAN_REMOVE && !VLAN_FILTERING_ALLOWED (adapter)) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else if (f->state ==IAVF_VLAN_DISABLE && - !VLAN_FILTERING_ALLOWED (adapter)) { - f->state =IAVF_VLAN_INACTIVE ; - }else if (f->state ==IAVF_VLAN_REMOVE || - f->state ==IAVF_VLAN_DISABLE ) { + }else if (f->state ==IAVF_VLAN_REMOVE ) { count++; } }
@@ -956,13 +946,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE ) { - vvfl->vlan_id[i] = f->vlan.vid; - f->state =IAVF_VLAN_INACTIVE ; - i++; -if (i == count) -break ; - }else if (f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid;list_del (&f->list);kfree (f);
@@ -1003,8 +987,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE || - f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;struct virtchnl_vlan *vlan;
@@ -1018,13 +1001,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -if (f->state ==IAVF_VLAN_DISABLE ) { - f->state =IAVF_VLAN_INACTIVE ; - }else { -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; - } +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; i++;if (i == count)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 843/957 iavf: wait for PF confirmation before removing VLAN filters
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ]
The VLAN filter DELETE path was asymmetric with the ADD path: ADD waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE immediately frees the filter struct after sending the DEL message without waiting for the PF response.
This is problematic because:
- If the PF rejects the DEL, the filter remains in HW but the driver has already freed the tracking structure, losing sync.
- Race conditions between DEL pending and other operations (add, reset) cannot be properly resolved if the filter struct is already gone.
Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric:
REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree
-> PF rejects -> ACTIVE
In iavf_del_vlans(), transition filters from REMOVE to REMOVING instead of immediately freeing them. The new DEL completion handler in iavf_virtchnl_completion() frees filters on success or reverts them to ACTIVE on error.
Update iavf_add_vlan() to handle the REMOVING state: if a DEL is pending and the user re-adds the same VLAN, queue it for ADD so it gets re-programmed after the PF processes the DEL.
The !VLAN_FILTERING_ALLOWED early-exit path still frees filters directly since no PF message is sent in that case.
Also update iavf_del_vlan() to skip filters already in REMOVING
state: DEL has been sent to PF and the completion handler will free the filter when PF confirms. Without this guard, the sequence DEL(pending) -> user-del -> second DEL could cause the PF to return an error for the second DEL (filter already gone), causing the completion handler to incorrectly revert a deleted filter back to ACTIVE.
--- drivers/net/ethernet/intel/iavf/iavf.h | 1 + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ 3 files changed, 34 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -0
@@ -161,6 +161,7 @@ enum iavf_vlan_state_t {IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ IAVF_VLAN_REMOVE ,/* filter queued for DEL from PF */ + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +8 -5
@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, adapter->num_vlan_filters++;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER ); }else if (f->state ==IAVF_VLAN_REMOVE ) { -/* Re-add the filter since we cannot tell whether the -* pending delete has already been processed by the PF. -* A duplicate add is harmless. -*/ +/* DEL not yet sent to PF, cancel it */ + f->state =IAVF_VLAN_ACTIVE ; + }else if (f->state ==IAVF_VLAN_REMOVING ) { +/* DEL already sent to PF, re-add after completion */ f->state =IAVF_VLAN_ADD ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER );
@@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else { + }else if (f->state !=IAVF_VLAN_REMOVING ) { f->state =IAVF_VLAN_REMOVE ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_DEL_VLAN_FILTER ); } +/* If REMOVING, DEL is already sent to PF; completion +* handler will free the filter when PF confirms. +*/ }spin_unlock_bh (&adapter->mac_vlan_list_lock);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +25 -12
@@ -945,12 +945,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -986,7 +984,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;
@@ -1001,9 +999,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -2366,10 +2362,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,ether_addr_copy (adapter->hw.mac.addr, netdev->dev_addr);wake_up (&adapter->vc_waitqueue);break ; -case VIRTCHNL_OP_DEL_VLAN : -dev_err (&adapter->pdev->dev,"Failed to delete VLAN filter, error %s\n" , -iavf_stat_str (&adapter->hw, v_retval)); -break ;case VIRTCHNL_OP_DEL_ETH_ADDR :dev_err (&adapter->pdev->dev,"Failed to delete MAC filter, error %s\n" ,iavf_stat_str (&adapter->hw, v_retval));
@@ -2891,6 +2883,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->mac_vlan_list_lock); }break ; +case VIRTCHNL_OP_DEL_VLAN : +case VIRTCHNL_OP_DEL_VLAN_V2 : { +struct iavf_vlan_filter *f, *ftmp; + +spin_lock_bh (&adapter->mac_vlan_list_lock); +list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, + list) { +if (f->state ==IAVF_VLAN_REMOVING ) { +if (v_retval) { +/* PF rejected DEL, keep filter */ + f->state =IAVF_VLAN_ACTIVE ; + }else { +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; + } + } + } +spin_unlock_bh (&adapter->mac_vlan_list_lock); + } +break ;case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING :/* PF enabled vlan strip on this VF. * Update netdev->features if needed to be in sync with ethtool.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 844/957 iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ]
The V1 ADD_VLAN opcode had no success handler; filters sent via V1 stayed in ADDING state permanently. Add a fallthrough case so V1 filters also transition ADDING -> ACTIVE on PF confirmation.
Critically, add an if (v_retval) break guard: the error switch in iavf_virtchnl_completion() does NOT return after handling errors, it falls through to the success switch. Without this guard, a PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, creating a driver/HW mismatch where the driver believes the filter is installed but the PF never accepted it.
For V2, this is harmless: iavf_vlan_add_reject() in the error block already kfree'd all ADDING filters, so the success handler finds nothing to transition.
--- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -0
@@ -2872,9 +2872,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->adv_rss_lock); }break ; +case VIRTCHNL_OP_ADD_VLAN :case VIRTCHNL_OP_ADD_VLAN_V2 : {struct iavf_vlan_filter *f; +if (v_retval) +break ; +spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_ADDING )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 845/957 ice: fix NULL pointer dereference in ice_reset_all_vfs()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ]
ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). When the VSI rebuild fails (e.g. during NVM firmware update via nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, leaving txq_map and rxq_map as NULL. The subsequent unconditional call to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0].
The single-VF reset path in ice_reset_vf() already handles this correctly by checking the return value of ice_vf_reconfig_vsi() and skipping ice_vf_post_vsi_rebuild() on failure.
Apply the same pattern to ice_reset_all_vfs(): check the return value of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and ice_eswitch_attach_vf() on failure. The VF is left safely disabled (ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can be recovered via a VFLR triggered by a PCI reset of the VF (sysfs reset or driver rebind).
Note that this patch does not prevent the VF VSI rebuild from failing during NVM update — the underlying cause is firmware being in a transitional state while the EMP reset is processed, which can cause Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This patch only prevents the subsequent NULL pointer dereference that crashes the kernel when the rebuild does fail.
crash> bt
PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5"
#0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee
#1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba
#2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540
#3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda
#4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997
#5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595
#6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2
[exception RIP: ice_ena_vf_q_mappings+0x79]
RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206
RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000
RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040
R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000
R13: 0000000000000010 R14: R15:
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice]
#8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice]
#9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice]
#10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4
#11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de
#12 [ff72159bcfe5bf18] kthread at ffffffffaa946663
#13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 The panic occurs attempting to dereference the NULL pointer in RDX at ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi).
The faulting VSI is an allocated slab object but not fully initialized after a failed ice_vsi_rebuild():
crash> struct ice_vsi 0xff34c9efc27d4828
netdev = 0x0,
rx_rings = 0x0,
tx_rings = 0x0,
q_vectors = 0x0,
txq_map = 0x0,
rxq_map = 0x0,
alloc_txq = 0x10,
num_txq = 0x10,
alloc_rxq = 0x10,
num_rxq = 0x10,The nvmupdate64e process was performing NVM firmware update:
crash> bt 0xff34c9edd1a30000
PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e"
#0 [ff72159bcd617618] __schedule at ffffffffab5333f8
#4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice]
dmesg:
ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it
may result in a downgrade. continuing anyways
ice 0000:13:00.1: ice_init_nvm failed -5
ice 0000:13:00.1: Rebuild failed, unload and reload driver
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +6 -1
@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf)ice_vf_ctrl_invalidate_vsi (vf);ice_vf_pre_vsi_rebuild (vf); -ice_vf_rebuild_vsi (vf); +if (ice_vf_rebuild_vsi (vf)) { +dev_err (dev,"VF %u VSI rebuild failed, leaving VF disabled\n" , + vf->vf_id); +mutex_unlock (&vf->cfg_lock); +continue ; + }ice_vf_post_vsi_rebuild (vf);ice_eswitch_attach_vf (pf, vf);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 846/957 ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 70ad216411e030f67b1743774e245601194aee6a ]
On certain E810 configurations where firmware supports Tx scheduler topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo() may need to apply a new 5-layer or 9-layer topology from the DDP package. If the AQ command to set the topology fails (e.g. due to invalid DDP data or firmware limitations), the global configuration lock must still be cleared via a CORER reset.
Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx scheduler config fails") correctly fixed this by refactoring ice_cfg_tx_topo() to always trigger CORER after acquiring the global lock and re-initialize hardware via ice_init_hw() afterwards.
However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(), breaking the reinit path introduced by 86aae43f21cf. This creates an infinite recursive call chain:
ice_init_hw()
ice_init_dev_hw()
ice_cfg_tx_topo() # topology change needed
ice_deinit_hw()
ice_init_hw() # reinit after CORER
ice_init_dev_hw() # recurse
ice_cfg_tx_topo()
... # stack overflow
Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling it explicitly from ice_probe() and ice_devlink_reinit_up(). The third caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw() during its reinit, it only needs the core HW reinitialization. This breaks the recursion cleanly without adding flags or guards.
The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod are preserved, only the init-side placement of ice_init_dev_hw() is reverted.
--- drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 ++ drivers/net/ethernet/intel/ice/ice_common.c | 2 -- drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/devlink/devlink.c +2 -0
@@ -1243,6 +1243,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)return err; } +ice_init_dev_hw (pf); +/* load MSI-X values */ ice_set_min_max_msix (pf);
drivers/net/ethernet/intel/ice/ice_common.c +0 -2
@@ -1162,8 +1162,6 @@ int ice_init_hw(struct ice_hw *hw)if (status) goto err_unroll_fltr_mgmt_struct; -ice_init_dev_hw (hw->back); -mutex_init (&hw->tnl_lock);ice_init_chk_recipe_reuse_support (hw);
drivers/net/ethernet/intel/ice/ice_main.c +2 -0
@@ -5321,6 +5321,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)return err; } +ice_init_dev_hw (pf); + adapter =ice_adapter_get (pdev);if (IS_ERR (adapter)) { err =PTR_ERR (adapter);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 847/957 ice: fix missing SMA pin initialization in DPLL subsystem
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 56a643aed0f0af5c29ebb4593d4917b78344dd48 ]
The DPLL SMA/U.FL pin redesign introduced ice_dpll_sw_pin_frequency_get() which gates frequency reporting on the pin's active flag. This flag is determined by ice_dpll_sw_pins_update() from the PCA9575 GPIO expander state. Before the redesign, SMA pins were exposed as direct HW input/output pins and ice_dpll_frequency_get() returned the CGU frequency unconditionally — the PCA9575 state was never consulted.
The PCA9575 powers on with all outputs high, setting ICE_SMA1_DIR_EN, ICE_SMA1_TX_EN, ICE_SMA2_DIR_EN and ICE_SMA2_TX_EN. Nothing in the driver writes the register during initialization, so ice_dpll_sw_pins_update() sees all pins as inactive and ice_dpll_sw_pin_frequency_get() permanently returns 0 Hz for every SW pin.
Fix this by writing a default SMA configuration in ice_dpll_init_info_sw_pins(): clear all SMA bits, then set SMA1 and SMA2 as active inputs (DIR_EN=0) with U.FL1 output and U.FL2 input disabled. Each SMA/U.FL pair shares a physical signal path so only one pin per pair can be active at a time. U.FL pins still report frequency 0 after this fix: U.FL1 (output-only) is disabled by ICE_SMA1_TX_EN which keeps the TX output buffer off, and U.FL2 (input-only) is disabled by ICE_SMA2_UFL2_RX_DIS. They can be activated by changing the corresponding SMA pin direction via dpll netlink.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/net/ethernet/intel/ice/ice_dpll.c +17 -0
@@ -3545,6 +3545,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)struct ice_dpll_pin *pin;u32 phase_adj_max, caps;int i, ret; +u8 data;if (pf->hw.device_id ==ICE_DEV_ID_E810C_QSFP ) input_idx_offset =ICE_E810_RCLK_PINS_NUM ;
@@ -3604,6 +3605,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) }ice_dpll_phase_range_set (&pin->prop.phase_range, phase_adj_max); } + +/* Initialize the SMA control register to a known-good default state. +* Without this write the PCA9575 GPIO expander retains its power-on +* default (all outputs high) which makes all SW pins appear inactive. +* Set SMA1 and SMA2 as active inputs, disable U.FL1 output and +* U.FL2 input. +*/ + ret =ice_read_sma_ctrl (&pf->hw, &data); +if (ret) +return ret; + data &= ~ICE_ALL_SMA_MASK ; + data |=ICE_SMA1_TX_EN |ICE_SMA2_TX_EN |ICE_SMA2_UFL2_RX_DIS ; + ret =ice_write_sma_ctrl (&pf->hw, data); +if (ret) +return ret; + ret =ice_dpll_pin_state_update (pf, pin,ICE_DPLL_PIN_TYPE_SOFTWARE ,NULL );if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 848/957 ice: fix SMA and U.FL pin state changes affecting paired pin
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 6f9d8393c9f50fbc68b9c9e99f78ca5a7b43ff44 ]
SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and SMA2/U.FL2) controlled by the PCA9575 GPIO expander. Each pair can only have one active pin at a time: SMA1 output and U.FL1 output share the same CGU output, SMA2 input and U.FL2 input share the same CGU input. The PCA9575 register bits determine which connector in each pair owns the signal path.
The driver does not account for this pairing in two places:
ice_dpll_ufl_pin_state_set() modifies PCA9575 bits and disables the backing CGU pin without checking whether the U.FL pin is currently active. Disconnecting an already inactive U.FL pin flips bits that the paired SMA pin relies on, breaking its connection.
ice_dpll_sma_direction_set() does not propagate direction changes to the paired U.FL pin. For SMA2/U.FL2 the ICE_SMA2_UFL2_RX_DIS bit is never managed, so U.FL2 stays disconnected after SMA2 switches to output. For both pairs the backing CGU pin of the U.FL side is never enabled when a direction change activates it, so userspace sees the pin as disconnected even though the routing is correct.
Fix by guarding the U.FL disconnect path against inactive pins and by updating the paired U.FL pin fully on SMA direction changes: manage ICE_SMA2_UFL2_RX_DIS for the SMA2/U.FL2 pair and enable the backing CGU pin whenever the peer becomes active.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 50 ++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_dpll.c +49 -1
@@ -1090,6 +1090,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,enum dpll_pin_direction direction, struct netlink_ext_ack *extack) { + struct ice_dplls *d = &p->pf->dplls; +struct ice_dpll_pin *peer;u8 data;int ret;
@@ -1108,8 +1110,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,case ICE_DPLL_PIN_SW_2_IDX :if (direction ==DPLL_PIN_DIRECTION_INPUT ) { data &= ~ICE_SMA2_DIR_EN ; + data |=ICE_SMA2_UFL2_RX_DIS ; }else { - data &= ~ICE_SMA2_TX_EN ; + data &= ~(ICE_SMA2_TX_EN |ICE_SMA2_UFL2_RX_DIS ); data |=ICE_SMA2_DIR_EN ; }break ;
@@ -1121,6 +1124,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, ret =ice_dpll_pin_state_update (p->pf, p,ICE_DPLL_PIN_TYPE_SOFTWARE , extack); +if (ret) +return ret; + +/* When a direction change activates the paired U.FL pin, enable +* its backing CGU pin so the pin reports as connected. Without +* this the U.FL routing is correct but the CGU pin stays disabled +* and userspace sees the pin as disconnected. Do not disable the +* backing pin when U.FL becomes inactive because the SMA pin may +* still be using it. +*/ + peer = &d->ufl[p->idx]; +if (peer->active) { +struct ice_dpll_pin *target; +enum ice_dpll_pin_type type; + +if (peer->output) { + target = peer->output; + type =ICE_DPLL_PIN_TYPE_OUTPUT ; + }else { + target = peer->input; + type =ICE_DPLL_PIN_TYPE_INPUT ; + } + ret =ice_dpll_pin_enable (&p->pf->hw, target, + d->eec.dpll_idx, type, extack); +if (!ret) + ret =ice_dpll_pin_state_update (p->pf, target, + type, extack); + }return ret; }
@@ -1172,6 +1203,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA1_MASK ; enable = true; }else if (state ==DPLL_PIN_STATE_DISCONNECTED ) { +/* Skip if U.FL1 is not active, setting TX_EN +* while DIR_EN is set would also deactivate +* the paired SMA1 output. +*/ +if (data & (ICE_SMA1_DIR_EN |ICE_SMA1_TX_EN )) { + ret =0 ; + goto unlock; + } data |=ICE_SMA1_TX_EN ; enable = false; }else {
@@ -1186,6 +1225,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA2_UFL2_RX_DIS ; enable = true; }else if (state ==DPLL_PIN_STATE_DISCONNECTED ) { +/* Skip if U.FL2 is not active, setting +* UFL2_RX_DIS could also disable the paired +* SMA2 input. +*/ +if (!(data &ICE_SMA2_DIR_EN ) || + (data &ICE_SMA2_UFL2_RX_DIS )) { + ret =0 ; + goto unlock; + } data |=ICE_SMA2_UFL2_RX_DIS ; enable = false; }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 849/957 ice: fix missing dpll notifications for SW pins
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 1a41b58fd4dc80dca16c717e6e77c88b9d4e83a7 ]
The SMA/U.FL pin redesign (commit 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control")) introduced software-controlled pins that wrap backing CGU input/output pins, but never updated the notification and data paths to propagate pin events to these SW wrappers.
The periodic work sends dpll_pin_change_ntf() only for direct CGU input pins. SW pins that wrap these inputs never receive change or phase offset notifications, so userspace consumers such as synce4l monitoring SMA pins via dpll netlink never learn about state transitions or phase offset updates. Similarly, ice_dpll_phase_offset_get() reads the SW pin's own phase_offset field which is never updated; the PPS monitor writes to the backing CGU input's field instead.
Fix by introducing ice_dpll_pin_ntf(), a wrapper around dpll_pin_change_ntf() that also notifies any registered SMA/U.FL pin whose backing CGU input matches. Replace all direct dpll_pin_change_ntf() calls in the periodic notification paths with this wrapper. Fix ice_dpll_phase_offset_get() to return the backing CGU input's phase_offset for input-direction SW pins.
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 47 +++++++++++++++++------ 1 file changed, 36 insertions(+), 11 deletions(-)
drivers/net/ethernet/intel/ice/ice_dpll.c +36 -11
@@ -1882,7 +1882,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, d->active_input == p->input->pin)) *phase_offset = d->phase_offset *ICE_DPLL_PHASE_OFFSET_FACTOR ; else if (d->phase_offset_monitor_period) - *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + *phase_offset = (p->input && + p->direction ==DPLL_PIN_DIRECTION_INPUT ? + p->input->phase_offset : + p->phase_offset) *ICE_DPLL_PHASE_OFFSET_FACTOR ; else *phase_offset =0 ;mutex_unlock (&pf->dplls.lock);
@@ -2510,6 +2513,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)return pci_get_dsn (pf->pdev); } +/** +* ice_dpll_pin_ntf - notify pin change including any SW pin wrappers +* @dplls: pointer to dplls struct +* @pin: the dpll_pin that changed +* +* Send a change notification for @pin and for any registered SMA/U.FL pin +* whose backing CGU input matches @pin. +*/ +static void ice_dpll_pin_ntf (struct ice_dplls *dplls,struct dpll_pin *pin) +{ +dpll_pin_change_ntf (pin); +for (int i =0 ; i <ICE_DPLL_PIN_SW_NUM ; i++) { +if (dplls->sma[i].pin && dplls->sma[i].input && + dplls->sma[i].input->pin == pin) +dpll_pin_change_ntf (dplls->sma[i].pin); +if (dplls->ufl[i].pin && dplls->ufl[i].input && + dplls->ufl[i].input->pin == pin) +dpll_pin_change_ntf (dplls->ufl[i].pin); + } +} +/** * ice_dpll_notify_changes - notify dpll subsystem about changes * @d: pointer do dpll
@@ -2518,6 +2542,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)*/ static void ice_dpll_notify_changes (struct ice_dpll *d) { +struct ice_dplls *dplls = &d->pf->dplls;bool pin_notified = false;if (d->prev_dpll_state != d->dpll_state) {
@@ -2526,17 +2551,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) }if (d->prev_input != d->active_input) {if (d->prev_input) -dpll_pin_change_ntf (d->prev_input); +ice_dpll_pin_ntf (dplls, d->prev_input); d->prev_input = d->active_input;if (d->active_input) { -dpll_pin_change_ntf (d->active_input); +ice_dpll_pin_ntf (dplls, d->active_input); pin_notified = true; } }if (d->prev_phase_offset != d->phase_offset) { d->prev_phase_offset = d->phase_offset;if (!pin_notified && d->active_input) -dpll_pin_change_ntf (d->active_input); +ice_dpll_pin_ntf (dplls, d->active_input); } }
@@ -2565,6 +2590,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)/** * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes +* @dplls: pointer to dplls struct * @pins: array of ice_dpll_pin pointers registered within dpll subsystem * @pin_num: number of pins * @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2574,15 +2600,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)* * Context: Must be called while pf->dplls.lock is released. */ -static void ice_dpll_pins_notify_mask (struct ice_dpll_pin *pins, +static void ice_dpll_pins_notify_mask (struct ice_dplls *dplls, +struct ice_dpll_pin *pins,u8 pin_num,u32 phase_offset_ntf_mask) { -int i =0 ; - -for (i =0 ; i < pin_num; i++) -if (phase_offset_ntf_mask & (1 << i)) -dpll_pin_change_ntf (pins[i].pin); +for (int i =0 ; i < pin_num; i++) +if (phase_offset_ntf_mask &BIT (i)) +ice_dpll_pin_ntf (dplls, pins[i].pin); }/**
@@ -2758,7 +2783,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)ice_dpll_notify_changes (de);ice_dpll_notify_changes (dp);if (phase_offset_ntf) -ice_dpll_pins_notify_mask (d->inputs, d->num_inputs, +ice_dpll_pins_notify_mask (d, d->inputs, d->num_inputs, phase_offset_ntf); resched:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 850/957 dpll: Allow associating dpll pin with a firmware node
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Vecera <[email protected]>
[ Upstream commit d0f4771e2befbe8de3a16a564c6bbd1d5502cec3 ]
Extend the DPLL core to support associating a DPLL pin with a firmware node. This association is required to allow other subsystems (such as network drivers) to locate and request specific DPLL pins defined in the Device Tree or ACPI.
* Add a .fwnode field to the struct dpll_pin
* Introduce dpll_pin_fwnode_set() helper to allow the provider driver to associate a pin with a fwnode after the pin has been allocated
* Introduce fwnode_dpll_pin_find() helper to allow consumers to search for a registered DPLL pin using its associated fwnode handle
* Ensure the fwnode reference is properly released in dpll_pin_put()
Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins")
--- drivers/dpll/dpll_core.c | 49 ++++++++++++++++++++++++++++++++++++++++ drivers/dpll/dpll_core.h | 2 ++ include/linux/dpll.h | 11 +++++++++ 3 files changed, 62 insertions(+)
drivers/dpll/dpll_core.c +49 -0
@@ -10,6 +10,7 @@#include <linux/device.h> #include <linux/err.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/string.h>
@@ -595,12 +596,60 @@ void dpll_pin_put(struct dpll_pin *pin)xa_destroy (&pin->parent_refs);xa_destroy (&pin->ref_sync_pins);dpll_pin_prop_free (&pin->prop); +fwnode_handle_put (pin->fwnode);kfree_rcu (pin, rcu); }mutex_unlock (&dpll_lock); }EXPORT_SYMBOL_GPL (dpll_pin_put); +/** +* dpll_pin_fwnode_set - set dpll pin firmware node reference +* @pin: pointer to a dpll pin +* @fwnode: firmware node handle +* +* Set firmware node handle for the given dpll pin. +*/ +void dpll_pin_fwnode_set (struct dpll_pin *pin,struct fwnode_handle *fwnode) +{ +mutex_lock (&dpll_lock); +fwnode_handle_put (pin->fwnode);/* Drop fwnode previously set */ + pin->fwnode =fwnode_handle_get (fwnode); +mutex_unlock (&dpll_lock); +} +EXPORT_SYMBOL_GPL (dpll_pin_fwnode_set); + +/** +* fwnode_dpll_pin_find - find dpll pin by firmware node reference +* @fwnode: reference to firmware node +* +* Get existing object of a pin that is associated with given firmware node +* reference. +* +* Context: Acquires a lock (dpll_lock) +* Return: +* * valid dpll_pin pointer on success +* * NULL when no such pin exists +*/ +struct dpll_pin *fwnode_dpll_pin_find (struct fwnode_handle *fwnode) +{ +struct dpll_pin *pin, *ret =NULL ; +unsigned long index; + +mutex_lock (&dpll_lock); +xa_for_each (&dpll_pin_xa, index, pin) { +if (pin->fwnode == fwnode) { + ret = pin; +refcount_inc (&ret->refcount); +break ; + } + } +mutex_unlock (&dpll_lock); + +return ret; +} +EXPORT_SYMBOL_GPL (fwnode_dpll_pin_find); +static int __dpll_pin_register (struct dpll_device *dpll,struct dpll_pin *pin,const struct dpll_pin_ops *ops,void *priv,void *cookie)
drivers/dpll/dpll_core.h +2 -0
@@ -42,6 +42,7 @@ struct dpll_device {* @pin_idx: index of a pin given by dev driver * @clock_id: clock_id of creator * @module: module of creator +* @fwnode: optional reference to firmware node * @dpll_refs: hold referencees to dplls pin was registered with * @parent_refs: hold references to parent pins pin was registered with * @ref_sync_pins: hold references to pins for Reference SYNC feature
@@ -54,6 +55,7 @@ struct dpll_pin {u32 pin_idx;u64 clock_id;struct module *module; +struct fwnode_handle *fwnode;struct xarray dpll_refs;struct xarray parent_refs;struct xarray ref_sync_pins;
include/linux/dpll.h +11 -0
@@ -16,6 +16,7 @@struct dpll_device ;struct dpll_pin ;struct dpll_pin_esync ; +struct fwnode_handle ;struct dpll_device_ops { int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
@@ -173,6 +174,8 @@ void dpll_netdev_pin_clear(struct net_device *dev);size_t dpll_netdev_pin_handle_size (const struct net_device *dev);int dpll_netdev_add_pin_handle (struct sk_buff *msg,const struct net_device *dev); + +struct dpll_pin *fwnode_dpll_pin_find (struct fwnode_handle *fwnode);#else static inline void dpll_netdev_pin_set (struct net_device *dev,struct dpll_pin *dpll_pin) { }
@@ -188,6 +191,12 @@ dpll_netdev_add_pin_handle(struct sk_buff *msg, const struct net_device *dev) {return 0 ; } + +static inline struct dpll_pin * +fwnode_dpll_pin_find (struct fwnode_handle *fwnode) +{ +return NULL ; +}#endif struct dpll_device *
@@ -213,6 +222,8 @@ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,void dpll_pin_put (struct dpll_pin *pin); +void dpll_pin_fwnode_set (struct dpll_pin *pin,struct fwnode_handle *fwnode); +int dpll_pin_on_pin_register (struct dpll_pin *parent,struct dpll_pin *pin,const struct dpll_pin_ops *ops,void *priv);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 851/957 dpll: Add notifier chain for dpll events
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 2be467588d6bc6ec5988fc254e62a44b865912a0 ]
Currently, the DPLL subsystem reports events (creation, deletion, changes) to userspace via Netlink. However, there is no mechanism for other kernel components to be notified of these events directly.
Add a raw notifier chain to the DPLL core protected by dpll_lock. This allows other kernel subsystems or drivers to register callbacks and receive notifications when DPLL devices or pins are created, deleted, or modified.
Define the following:
- Registration helpers: {,un}register_dpll_notifier()
- Event types: DPLL_DEVICE_CREATED, DPLL_PIN_CREATED, etc.
- Context structures: dpll_{device,pin}_notifier_info to pass relevant data to the listeners.
The notification chain is invoked alongside the existing Netlink event generation to ensure in-kernel listeners are kept in sync with the subsystem state.
Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins")
--- drivers/dpll/dpll_core.c | 57 +++++++++++++++++++++++++++++++++++++ drivers/dpll/dpll_core.h | 4 +++ drivers/dpll/dpll_netlink.c | 6 ++++ include/linux/dpll.h | 29 +++++++++++++++++++ 4 files changed, 96 insertions(+)
drivers/dpll/dpll_core.c +57 -0
@@ -23,6 +23,8 @@ DEFINE_MUTEX(dpll_lock);DEFINE_XARRAY_FLAGS (dpll_device_xa,XA_FLAGS_ALLOC );DEFINE_XARRAY_FLAGS (dpll_pin_xa,XA_FLAGS_ALLOC ); +static RAW_NOTIFIER_HEAD (dpll_notifier_chain); +static u32 dpll_device_xa_id;static u32 dpll_pin_xa_id;
@@ -46,6 +48,39 @@ struct dpll_pin_registration {void *cookie; }; +static int call_dpll_notifiers (unsigned long action,void *info) +{ +lockdep_assert_held (&dpll_lock); +return raw_notifier_call_chain (&dpll_notifier_chain, action, info); +} + +void dpll_device_notify (struct dpll_device *dpll,unsigned long action) +{ +struct dpll_device_notifier_info info = { + .dpll = dpll, + .id = dpll->id, + .idx = dpll->device_idx, + .clock_id = dpll->clock_id, + .type = dpll->type, + }; + +call_dpll_notifiers (action, &info); +} + +void dpll_pin_notify (struct dpll_pin *pin,unsigned long action) +{ +struct dpll_pin_notifier_info info = { + .pin = pin, + .id = pin->id, + .idx = pin->pin_idx, + .clock_id = pin->clock_id, + .fwnode = pin->fwnode, + .prop = &pin->prop, + }; + +call_dpll_notifiers (action, &info); +} +struct dpll_device *dpll_device_get_by_id (int id) {if (xa_get_mark (&dpll_device_xa, id,DPLL_REGISTERED ))
@@ -539,6 +574,28 @@ void dpll_netdev_pin_clear(struct net_device *dev) }EXPORT_SYMBOL (dpll_netdev_pin_clear); +int register_dpll_notifier (struct notifier_block *nb) +{ +int ret; + +mutex_lock (&dpll_lock); + ret =raw_notifier_chain_register (&dpll_notifier_chain, nb); +mutex_unlock (&dpll_lock); +return ret; +} +EXPORT_SYMBOL_GPL (register_dpll_notifier); + +int unregister_dpll_notifier (struct notifier_block *nb) +{ +int ret; + +mutex_lock (&dpll_lock); + ret =raw_notifier_chain_unregister (&dpll_notifier_chain, nb); +mutex_unlock (&dpll_lock); +return ret; +} +EXPORT_SYMBOL_GPL (unregister_dpll_notifier); +/** * dpll_pin_get - find existing or create new dpll pin * @clock_id: clock_id of creator
drivers/dpll/dpll_core.h +4 -0
@@ -91,4 +91,8 @@ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);extern struct xarray dpll_device_xa;extern struct xarray dpll_pin_xa;extern struct mutex dpll_lock; + +void dpll_device_notify (struct dpll_device *dpll,unsigned long action); +void dpll_pin_notify (struct dpll_pin *pin,unsigned long action); +#endif
drivers/dpll/dpll_netlink.c +6 -0
@@ -742,17 +742,20 @@ dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll)int dpll_device_create_ntf (struct dpll_device *dpll) { +dpll_device_notify (dpll,DPLL_DEVICE_CREATED );return dpll_device_event_send (DPLL_CMD_DEVICE_CREATE_NTF , dpll); }int dpll_device_delete_ntf (struct dpll_device *dpll) { +dpll_device_notify (dpll,DPLL_DEVICE_DELETED );return dpll_device_event_send (DPLL_CMD_DEVICE_DELETE_NTF , dpll); }static int __dpll_device_change_ntf (struct dpll_device *dpll) { +dpll_device_notify (dpll,DPLL_DEVICE_CHANGED );return dpll_device_event_send (DPLL_CMD_DEVICE_CHANGE_NTF , dpll); }
@@ -810,16 +813,19 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)int dpll_pin_create_ntf (struct dpll_pin *pin) { +dpll_pin_notify (pin,DPLL_PIN_CREATED );return dpll_pin_event_send (DPLL_CMD_PIN_CREATE_NTF , pin); }int dpll_pin_delete_ntf (struct dpll_pin *pin) { +dpll_pin_notify (pin,DPLL_PIN_DELETED );return dpll_pin_event_send (DPLL_CMD_PIN_DELETE_NTF , pin); }int __dpll_pin_change_ntf (struct dpll_pin *pin) { +dpll_pin_notify (pin,DPLL_PIN_CHANGED );return dpll_pin_event_send (DPLL_CMD_PIN_CHANGE_NTF , pin); }
include/linux/dpll.h +29 -0
@@ -11,6 +11,7 @@#include <linux/device.h> #include <linux/netlink.h> #include <linux/netdevice.h> +#include <linux/notifier.h> #include <linux/rtnetlink.h> struct dpll_device ;
@@ -167,6 +168,30 @@ struct dpll_pin_properties {u32 phase_gran; }; +#define DPLL_DEVICE_CREATED 1 +#define DPLL_DEVICE_DELETED 2 +#define DPLL_DEVICE_CHANGED 3 +#define DPLL_PIN_CREATED 4 +#define DPLL_PIN_DELETED 5 +#define DPLL_PIN_CHANGED 6 + +struct dpll_device_notifier_info { +struct dpll_device *dpll; +u32 id; +u32 idx; +u64 clock_id; +enum dpll_type type; +}; + +struct dpll_pin_notifier_info { +struct dpll_pin *pin; +u32 id; +u32 idx; +u64 clock_id; +const struct fwnode_handle *fwnode; +const struct dpll_pin_properties *prop; +}; +#if IS_ENABLED (CONFIG_DPLL )void dpll_netdev_pin_set (struct net_device *dev,struct dpll_pin *dpll_pin);void dpll_netdev_pin_clear (struct net_device *dev);
@@ -237,4 +262,8 @@ int dpll_device_change_ntf(struct dpll_device *dpll);int dpll_pin_change_ntf (struct dpll_pin *pin); +int register_dpll_notifier (struct notifier_block *nb); + +int unregister_dpll_notifier (struct notifier_block *nb); +#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 852/957 dpll: export __dpll_pin_change_ntf() for use under dpll_lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Vecera <[email protected]>
[ Upstream commit 620055cb1036a6125fd912e7a14b47a6572b809b ]
Export __dpll_pin_change_ntf() so that drivers can send pin change notifications from within pin callbacks, which are already called under dpll_lock. Using dpll_pin_change_ntf() in that context would deadlock.
Add lockdep_assert_held() to catch misuse without the lock held.
Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins")
--- drivers/dpll/dpll_netlink.c | 10 ++++++++++ drivers/dpll/dpll_netlink.h | 2 -- include/linux/dpll.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-)
drivers/dpll/dpll_netlink.c +10 -0
@@ -823,11 +823,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin)return dpll_pin_event_send (DPLL_CMD_PIN_DELETE_NTF , pin); } +/** +* __dpll_pin_change_ntf - notify that the pin has been changed +* @pin: registered pin pointer +* +* Context: caller must hold dpll_lock. Suitable for use inside pin +* callbacks which are already invoked under dpll_lock. +* Return: 0 if succeeds, error code otherwise. +*/ int __dpll_pin_change_ntf (struct dpll_pin *pin) { +lockdep_assert_held (&dpll_lock);dpll_pin_notify (pin,DPLL_PIN_CHANGED );return dpll_pin_event_send (DPLL_CMD_PIN_CHANGE_NTF , pin); } +EXPORT_SYMBOL_GPL (__dpll_pin_change_ntf);/** * dpll_pin_change_ntf - notify that the pin has been changed
drivers/dpll/dpll_netlink.h +0 -2
@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll);int dpll_pin_create_ntf (struct dpll_pin *pin);int dpll_pin_delete_ntf (struct dpll_pin *pin); - -int __dpll_pin_change_ntf (struct dpll_pin *pin);
include/linux/dpll.h +1 -0
@@ -260,6 +260,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,int dpll_device_change_ntf (struct dpll_device *dpll); +int __dpll_pin_change_ntf (struct dpll_pin *pin);int dpll_pin_change_ntf (struct dpll_pin *pin);int register_dpll_notifier (struct notifier_block *nb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 853/957 ice: add dpll peer notification for paired SMA and U.FL pins
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 9e5dead140af10e8b5f975b8f04e46197d48d274 ]
SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and SMA2/U.FL2). When one pin's state changes via a PCA9575 GPIO write, the paired pin's state also changes, but no notification is sent for the peer pin. Userspace consumers monitoring the peer via dpll netlink subscribe never learn about the update.
Add ice_dpll_sw_pin_notify_peer() which sends a change notification for the paired SW pin. Call it from ice_dpll_pin_sma_direction_set(), ice_dpll_sma_pin_state_set(), and ice_dpll_ufl_pin_state_set() after pf->dplls.lock is released. Use __dpll_pin_change_ntf() because dpll_lock is still held by the dpll netlink layer (dpll_pin_pre_doit).
--- drivers/net/ethernet/intel/ice/ice_dpll.c | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+)
drivers/net/ethernet/intel/ice/ice_dpll.c +32 -0
@@ -1073,6 +1073,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, extack, ICE_DPLL_PIN_TYPE_INPUT); } +/** +* ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change +* @d: pointer to dplls struct +* @changed: the SW pin that was explicitly changed (already notified by dpll core) +* +* SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +* SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO +* expander, the paired pin's state may also change. Send a change +* notification for the peer pin so userspace consumers monitoring the +* peer via dpll netlink learn about the update. +* +* Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is +* released. Uses __dpll_pin_change_ntf() because dpll_lock is +* still held by the dpll netlink layer. +*/ +static void ice_dpll_sw_pin_notify_peer (struct ice_dplls *d, +struct ice_dpll_pin *changed) +{ +struct ice_dpll_pin *peer; + + peer = (changed >= d->sma && changed < d->sma +ICE_DPLL_PIN_SW_NUM ) ? + &d->ufl[changed->idx] : &d->sma[changed->idx]; +if (peer->pin) +__dpll_pin_change_ntf (peer->pin); +} +/** * ice_dpll_sma_direction_set - set direction of SMA pin * @p: pointer to a pin
@@ -1263,6 +1289,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock:mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, p);return ret; }
@@ -1381,6 +1409,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock:mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, sma);return ret; }
@@ -1576,6 +1606,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv,mutex_lock (&pf->dplls.lock); ret =ice_dpll_sma_direction_set (p, direction, extack);mutex_unlock (&pf->dplls.lock); +if (!ret) +ice_dpll_sw_pin_notify_peer (&pf->dplls, p);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 854/957 net: tls: fix strparser anchor skb leak on offload RX setup failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ]
When tls_set_device_offload_rx() fails at tls_dev_add(), the error path calls tls_sw_free_resources_rx() to clean up the SW context that was initialized by tls_set_sw_offload(). This function calls tls_sw_release_resources_rx() (which stops the strparser via tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), but never frees the anchor skb that was allocated by alloc_skb(0) in tls_strp_init().
Note that tls_sw_free_resources_rx() is exclusively used for this "failed to start offload" code path, there's no other caller.
The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use the standard strparser"), because the standard strparser doesn't try to pre-allocate an skb.
The normal close path in tls_sk_proto_close() handles cleanup by calling tls_sw_strparser_done() (which calls tls_strp_done()) after dropping the socket lock, because tls_strp_done() does cancel_work_sync() and the strparser work handler takes the socket lock.
--- net/tls/tls.h | 1 + net/tls/tls_strp.c | 6 ++++++ net/tls/tls_sw.c | 4 ++++ 3 files changed, 11 insertions(+)
net/tls/tls.h +1 -0
@@ -188,6 +188,7 @@ int tls_strp_dev_init(void);void tls_strp_dev_exit (void );void tls_strp_done (struct tls_strparser *strp); +void __tls_strp_done (struct tls_strparser *strp);void tls_strp_stop (struct tls_strparser *strp);int tls_strp_init (struct tls_strparser *strp,struct sock *sk);void tls_strp_data_ready (struct tls_strparser *strp);
net/tls/tls_strp.c +6 -0
@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp)WARN_ON (!strp->stopped);cancel_work_sync (&strp->work); +__tls_strp_done (strp); +} + +/* For setup error paths where the strparser was initialized but never armed. */ +void __tls_strp_done (struct tls_strparser *strp) +{tls_strp_anchor_free (strp); }
net/tls/tls_sw.c +4 -0
@@ -2625,8 +2625,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)void tls_sw_free_resources_rx (struct sock *sk) {struct tls_context *tls_ctx =tls_get_ctx (sk); +struct tls_sw_context_rx *ctx; + + ctx =tls_sw_ctx_rx (tls_ctx);tls_sw_release_resources_rx (sk); +__tls_strp_done (&ctx->strp);tls_sw_free_ctx_rx (tls_ctx); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 855/957 sfc: fix error code in efx_devlink_info_running_versions()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ]
Return -EIO if efx_mcdi_rpc() doesn't return enough space.
--- drivers/net/ethernet/sfc/efx_devlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/sfc/efx_devlink.c +1 -1
@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx,if (rc || outlength <MC_CMD_GET_VERSION_OUT_LEN ) {netif_err (efx, drv, efx->net_dev,"mcdi MC_CMD_GET_VERSION failed\n" ); -return rc; +return rc ?: -EIO ; }/* Handle previous output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 856/957 net/sched: cls_flower: revert unintended changes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ]
While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check length before marking flow active"), I unintentionally included unrelated and unacceptable changes.
Revert them.
--- net/sched/cls_flower.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/sched/cls_flower.c +1 -3
@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); -struct fl_flow_mask *mask; *last = false;
@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - mask = f->mask; + *last =fl_mask_put (head, f->mask);if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); - *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 857/957 kselftest/arm64: Include <asm/ptrace.h> for user_gcs definition
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit bb7235e226888607e6aac1288062fcb1ac105589 ]
kselftest includes kernel uAPI headers with option:
-isystem $(top_srcdir)/usr/include
Include <asm/ptrace.h> in libc-gcs.c for the definition of struct user_gcs from the uAPI headers, and remove the redundant definition in gcs-util.h. This fixes a compilation error on systems where the toolchain defines NT_ARM_GCS.
--- tools/testing/selftests/arm64/gcs/gcs-util.h | 6 ------ tools/testing/selftests/arm64/gcs/libc-gcs.c | 1 + 2 files changed, 1 insertion(+), 6 deletions(-)
tools/testing/selftests/arm64/gcs/gcs-util.h +0 -6
@@ -18,12 +18,6 @@#ifndef NT_ARM_GCS #define NT_ARM_GCS 0x410 - -struct user_gcs { -__u64 features_enabled; -__u64 features_locked; -__u64 gcspr_el0; -};#endif /* Shadow Stack/Guarded Control Stack interface */
tools/testing/selftests/arm64/gcs/libc-gcs.c +1 -0
@@ -16,6 +16,7 @@#include <asm/hwcap.h> #include <asm/mman.h> +#include <asm/ptrace.h> #include <linux/compiler.h>
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 858/957 arm64: Reserve an extra page for early kernel mapping
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaoyang Huang <[email protected]>
[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ]
The final part of [data, end) segment may overflow into the next page of init_pg_end[1] which is the gap page before early_init_stack[2]:
[1]
crash_arm64_v9.0.1> vtop ffffffed00601000
VIRTUAL PHYSICALffffffed00601000 83401000
PAGE DIRECTORY: ffffffecffd62000
PGD: ffffffecffd62da0 => 10000000833fb003
PMD: ffffff80033fb018 => 10000000833fe003
PTE: ffffff80033fe008 => 68000083401f03
PAGE: 83401000
PTE PHYSICAL FLAGS 68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN)
PAGE PHYSICAL MAPPING INDEX CNT FLAGSfffffffec00d0040 83401000 0 0 1 4000 reserved
[2]ffffffed002c8000 (r) __pi__dataffffffed0054e000 (d) __pi___bss_startffffffed005f5000 (b) __pi_init_pg_dirffffffed005fe000 (b) __pi_init_pg_endffffffed005ff000 (B) early_init_stackffffffed00608000 (b) __pi__end
For 4K pages, the early kernel mapping may use 2MB block entries but the kernel segments are only 64KB aligned. Segment boundaries that fall within a 2MB block therefore require a PTE table so that different attributes can be applied on either side of the boundary.
KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel VMAs registered by declare_kernel_vmas(). However, since commit 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only"), the early mapper also maps [_text, _stext) separately from [_stext, _etext). This adds one more early-only split and can require one more page-table page than the existing EARLY_SEGMENT_EXTRA_PAGES allowance reserves.
Increase the 4K-page early mapping allowance by one page to cover that additional split.
--- arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kernel-pgtable.h +6 -1
@@ -68,7 +68,12 @@#define KERNEL_SEGMENT_COUNT 5#if SWAPPER_BLOCK_SIZE >SEGMENT_ALIGN -#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) +/* +* KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping +* has one additional split, [_text, _stext). Reserve one more page for the +* SWAPPER_BLOCK_SIZE-unaligned boundaries. +*/ +#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2)/* * The initial ID map consists of the kernel image, mapped as two separate * segments, and may appear misaligned wrt the swapper block size. This means
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 859/957 futex: Drop CLONE_THREAD requirement for private default hash alloc
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
[ Upstream commit ee9dce44362b2d8132c32964656ab6dff7dfbc6a ]
Currently need_futex_hash_allocate_default() depends on strict pthread semantics, abusing CLONE_THREAD. This breaks the non-concurrency assumptions when doing the mm->futex_ref pcpu allocations, leading to bugs[0] when sharing the mm in other ways; ie:
BUG: KASAN: slab-use-after-free in futex_hash_put
... where the +1 bias can end up on a percpu counter that mm->futex_ref no longer points at.
Loosen the check to cover any CLONE_VM clone, except vfork(). Excluding vfork keeps the existing paths untouched (no overhead), and we can't race in the first place: either the parent is suspended and the child runs alone, or mm->futex_ref is already allocated from an earlier CLONE_VM.
--- kernel/fork.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
kernel/fork.c +5 -7
@@ -1911,9 +1911,11 @@ static void rv_task_fork(struct task_struct *p)static bool need_futex_hash_allocate_default (u64 clone_flags) { -if ((clone_flags & (CLONE_THREAD |CLONE_VM )) != (CLONE_THREAD |CLONE_VM )) -return false; -return true; +/* +* Allocate a default futex hash for any sibling that will +* share the parent's mm, except vfork. +*/ +return (clone_flags & (CLONE_VM |CLONE_VFORK )) ==CLONE_VM ; }/*
@@ -2296,10 +2298,6 @@ __latent_entropy struct task_struct *copy_process(if (retval) goto bad_fork_cancel_cgroup; -/* -* Allocate a default futex hash for the user process once the first -* thread spawns. -*/ if (need_futex_hash_allocate_default (clone_flags)) { retval =futex_hash_allocate_default ();if (retval)
Signature · 1 line
2.53.0