6.6.157-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 1126/1424 Bluetooth: virtio_bt: avoid OOB read of build info string
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 502adc06ba76dee19c292ae4a07d74d202fe734d ]
The virtbt_setup_zephyr() sends the Zephyr vendor command 0xfc08 (Read Build Information) and hands the response to bt_dev_info() and hci_set_fw_info() as a "%s" string starting at skb->data + 1, without checking the length. A backend that answers with status only leaves that pointer past the end of the received data, so the walk reads adjacent slab memory until it meets a NUL. Those bytes reach the kernel log and the firmware-info debugfs file.
To fix this, print the string with a bounded "%.*s" limited to skb->len - 1. A short or unterminated response then prints as much as arrived instead of failing setup.
This mirrors commit dd068ef04412 ("Bluetooth: bpa10x: avoid OOB read of revision string in bpa10x_setup()"), which fixed the identical pattern.
--- drivers/bluetooth/virtio_bt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/bluetooth/virtio_bt.c +6 -2
@@ -120,9 +120,13 @@ static int virtbt_setup_zephyr(struct hci_dev *hdev)if (IS_ERR (skb))return PTR_ERR (skb); -bt_dev_info (hdev,"%s" , (char *)(skb->data +1 )); +/* Bounded print: the backend controls skb->len. */ +if (skb->len >1 ) { +int len = skb->len -1 ; -hci_set_fw_info (hdev,"%s" , skb->data +1 ); +bt_dev_info (hdev,"%.*s" , len, (char *)(skb->data +1 )); +hci_set_fw_info (hdev,"%.*s" , len, skb->data +1 ); + }kfree_skb (skb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1127/1424 Bluetooth: btintel: Fix diagnostics event detection
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit ad0e7ac7da9a9a0095570bd6add3e27f259de104 ]
For a diagnostics VSE, diagnostics_hdr[] sits at the start of the event payload, skb->data[2], but btintel_recv_event() wrongly guards its memcmp with @len, which is measured from skb->data[3] for the earlier INTEL_BOOTLOADER check.
Fix by using (@len + 1) instead, which ==
(skb->len - HCI_EVENT_HDR_SIZE) exactly.
--- drivers/bluetooth/btintel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/btintel.c +1 -1
@@ -2983,7 +2983,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)/* Handle all diagnostics events separately. May still call * hci_recv_frame. */ -if (len >=sizeof (diagnostics_hdr) && +if (len +1 >=sizeof (diagnostics_hdr) &&memcmp (&skb->data[2 ], diagnostics_hdr,sizeof (diagnostics_hdr)) ==0 ) {return btintel_diagnostics (hdev, skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1128/1424 Bluetooth: hci_conn: fix the SCO setup context lifetime
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 42de40abe25db9211107af8896d0fd741f10648d ]
hci_setup_sync() queues a conn_handle_t with a NULL destroy callback, so the context is only freed if hci_enhanced_setup_sync() actually runs. An entry that is cancelled instead is leaked, as _hci_cmd_sync_cancel_entry() does not release entry->data when there is no destroy callback, and hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered.
The context also stores a bare hci_conn pointer, so the connection can be freed while the work is queued. The dequeue in hci_conn_del() does not cover it either, as it matches on entry->data == conn and entry->data is the wrapper here. Same problem as commit 2f5d635ad590 ("Bluetooth:hci_sync: hold conn in hci_connect_acl/le_sync() callbacks").
Hold the connection and release both from a destroy callback. The submission failure path drops both, since hci_cmd_sync_submit() does not call the destroy callback when it fails to queue.
--- net/bluetooth/hci_conn.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
net/bluetooth/hci_conn.c +15 -5
@@ -288,8 +288,6 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)struct hci_cp_enhanced_setup_sync_conn cp;const struct sco_param *param; -kfree (conn_handle); -if (!hci_conn_valid (hdev, conn))return -ECANCELED ;
@@ -458,6 +456,15 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)return true; } +static void hci_enhanced_setup_sync_destroy (struct hci_dev *hdev,void *data, +int err) +{ +struct conn_handle_t *conn_handle = data; + +hci_conn_put (conn_handle->conn); +kfree (conn_handle); +} +bool hci_setup_sync (struct hci_conn *conn,__u16 handle) {int result;
@@ -469,12 +476,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)if (!conn_handle)return false; - conn_handle->conn = conn; + conn_handle->conn =hci_conn_get (conn); conn_handle->handle = handle; result =hci_cmd_sync_queue (conn->hdev, hci_enhanced_setup_sync, - conn_handle,NULL ); -if (result <0 ) + conn_handle, + hci_enhanced_setup_sync_destroy); +if (result <0 ) { +hci_conn_put (conn);kfree (conn_handle); + }return result ==0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1129/1424 Bluetooth: hci_sync: free the advertising instance on the failure and cancel paths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 120d8dc042e3d45073bb6e50ee7b058a0b182627 ]
adv_timeout_expire() hands a kmalloc()ed instance byte to hci_cmd_sync_queue() with a NULL destroy callback, and only adv_timeout_expire_sync() frees it. That leaks on two paths:
- the return value is not checked, and hci_cmd_sync_queue() does not take ownership when it fails (-ENETDOWN, -ENODEV, -ENOMEM);
- a cancelled entry is not released, as _hci_cmd_sync_cancel_entry() does not free entry->data when there is no destroy callback. hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered.
Free the buffer from a destroy callback, and in the caller when the entry could not be queued at all.
--- net/bluetooth/hci_sync.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +9 -3
@@ -611,8 +611,6 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data) {u8 instance = *(u8 *)data; -kfree (data); -hci_clear_adv_instance_sync (hdev,NULL , instance, false);if (list_empty (&hdev->adv_instances))
@@ -621,6 +619,12 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data)return 0 ; } +static void adv_timeout_expire_destroy (struct hci_dev *hdev,void *data, +int err) +{ +kfree (data); +} +static void adv_timeout_expire (struct work_struct *work) {u8 *inst_ptr;
@@ -641,7 +645,9 @@ static void adv_timeout_expire(struct work_struct *work) goto unlock; *inst_ptr = hdev->cur_adv_instance; -hci_cmd_sync_queue (hdev, adv_timeout_expire_sync, inst_ptr,NULL ); +if (hci_cmd_sync_queue (hdev, adv_timeout_expire_sync, inst_ptr, + adv_timeout_expire_destroy) <0 ) +kfree (inst_ptr); unlock:hci_dev_unlock (hdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1130/1424 Bluetooth: MGMT: free the mesh send cancel command when it is cancelled
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 3c742feda8fcabf741a17bcf668b63c8f606f9c5 ]
mesh_send_cancel() queues the pending command with a NULL destroy callback, so it is only freed if send_cancel() runs. A cancelled entry is leaked, as _hci_cmd_sync_cancel_entry() does not release entry->data when there is no destroy callback, and hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered. Nothing else reclaims it either: mgmt_pending_new() does not put the command on hdev->mgmt_pending.
The leak also pins the socket reference taken by mgmt_pending_new(), so the mgmt socket is never released.
Free the command from a destroy callback.
--- net/bluetooth/mgmt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
net/bluetooth/mgmt.c +7 -2
@@ -2404,11 +2404,15 @@ static int send_cancel(struct hci_dev *hdev, void *data)mgmt_cmd_complete (cmd->sk, hdev->id,MGMT_OP_MESH_SEND_CANCEL ,0 ,NULL ,0 ); -mgmt_pending_free (cmd);return 0 ; } +static void send_cancel_destroy (struct hci_dev *hdev,void *data,int err) +{ +mgmt_pending_free (data); +} +static int mesh_send_cancel (struct sock *sk,struct hci_dev *hdev,void *data,u16 len) {
@@ -2429,7 +2433,8 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,if (!cmd) err = -ENOMEM ;else - err =hci_cmd_sync_queue (hdev, send_cancel, cmd,NULL ); + err =hci_cmd_sync_queue (hdev, send_cancel, cmd, + send_cancel_destroy);if (err <0 ) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1131/1424 Bluetooth: MSFT: validate evt_prefix_len against the response length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
[ Upstream commit 0079e1a944634ab2dc1c7cdec1144486d096407e ]
read_supported_features() only checks that the response covers the fixed part of struct msft_rp_read_supported_features, which is 11 bytes:
if (skb->len < sizeof(*rp)) {
bt_dev_err(hdev, "MSFT supported features length mismatch");
goto failed;
}evt_prefix[] is a flexible array member and rp->evt_prefix_len is an unvalidated u8 taken straight out of that response, so
msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, GFP_KERNEL);
copies up to 255 bytes from a reply that may have carried none of them. What is copied is data the controller never sent, and it is then used to match incoming vendor events in msft_vendor_evt().
This is not an out-of-bounds access. An skb data allocation always has at least SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) bytes past the payload, which is more than the 255 byte maximum, so the read stays inside the allocation and KASAN does not report it. It is still a read of bytes the host was never given, with the length fully controlled by the controller.
Reject a response that is too short for the prefix it declares.
Verified with an emulated controller over /dev/vhci on a KASAN kernel, with vhci made to advertise an MSFT opcode the way btintel, btqca, btmtk and btrtl do unconditionally. A reply of exactly 11 bytes declaring evt_prefix_len = 255 reaches kmemdup and copies 255 bytes ("skb->len=11 evt_prefix_len=255", with the copied buffer dumped); since the reply ends at the fixed part, all 255 come from past the end of the response. No KASAN report is produced, as expected from the allocation slack described above. With this patch the response is rejected with "MSFT event prefix length mismatch" and msft->evt_prefix is left unset.
--- net/bluetooth/msft.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/msft.c +5 -0
@@ -166,6 +166,11 @@ static bool read_supported_features(struct hci_dev *hdev,if (rp->sub_opcode !=MSFT_OP_READ_SUPPORTED_FEATURES ) goto failed; +if (skb->len <sizeof (*rp) + rp->evt_prefix_len) { +bt_dev_err (hdev,"MSFT event prefix length mismatch" ); + goto failed; + } +if (rp->evt_prefix_len >0 ) { msft->evt_prefix =kmemdup (rp->evt_prefix, rp->evt_prefix_len,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1132/1424 iio: light: gp2ap002: Fix unbalanced runtime PM on repeated event writes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
[ Upstream commit 579c049b4cb6fc72ce2c505fc5334540be0efcd3 ]
The IIO core does not filter duplicate writes to the event enable attribute, so writing the same value twice invokes write_event_config() twice. Enabling twice leaks a runtime PM reference, preventing the device from ever suspending again; disabling twice underflows the usage count and triggers a "Runtime PM usage count underflow" warning.
Bail out early when the requested state matches the current state. While at it, switch to pm_runtime_resume_and_get() so a failed resume is propagated to userspace instead of silently marking the event enabled.
--- drivers/iio/light/gp2ap002.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/iio/light/gp2ap002.c +10 -3
@@ -343,6 +343,10 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev, int state) {struct gp2ap002 *gp2ap002 =iio_priv (indio_dev); +int ret; + +if (state == gp2ap002->enabled) +return 0 ;if (state) {/*
@@ -350,14 +354,17 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,* already) and reintialize the sensor by using runtime_pm * callbacks. */ -pm_runtime_get_sync (gp2ap002->dev); - gp2ap002->enabled = true; + ret =pm_runtime_resume_and_get (gp2ap002->dev); +if (ret) +return ret; + }else {pm_runtime_mark_last_busy (gp2ap002->dev);pm_runtime_put_autosuspend (gp2ap002->dev); - gp2ap002->enabled = false; } + gp2ap002->enabled = state; +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1133/1424 iio: light: gp2ap002: re-enable irq if runtime suspend fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
[ Upstream commit 5d89e7cbac40057f5241a0832a86ce0fe97e4818 ]
gp2ap002_runtime_suspend() disables the irq before writing OPMOD. If the write fails, the callback returns an error with the irq still disabled while the PM core marks the device active again.
re-enable the irq before returning the error so the irq state matches the active state the PM core restores.
--- drivers/iio/light/gp2ap002.c | 1 + 1 file changed, 1 insertion(+)
drivers/iio/light/gp2ap002.c +1 -0
@@ -651,6 +651,7 @@ static int gp2ap002_runtime_suspend(struct device *dev)/* Disable chip and IRQ, everything off */ ret =regmap_write (gp2ap002->map,GP2AP002_OPMOD ,0x00 );if (ret) { +enable_irq (gp2ap002->irq);dev_err (gp2ap002->dev,"error setting up operation mode\n" );return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1134/1424 net/sched: cls_api: fix teardown of an adopted proto on insert-race loss
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit d4e359b3608a0e184bbe8d61a5c3b50d0831c44a ]
In tc_new_tfilter() the create branch sets tp_created = 1 before calling tcf_chain_tp_insert_unique(). When the caller loses the race (another request inserted a proto at the same chain/prio first), insert_unique() destroys the caller's own tp_new and returns the winner's proto with an extra reference. tp_created was never cleared, so the loser's errout path treated the winner's live proto as its own and called tcf_chain_tp_delete_empty() on it, silently unlinking an active classifier that the winning request already advertised via RTM_NEWTFILTER.
Track the outcome of the insert step in a single tri-state variable so each errout path reacts correctly:
- TP_NOT_CREATED: no proto created; pursue the old path.
- TP_CREATED: proto inserted successfully; same code path as before.
- TP_NOT_OWNED: New - lost the insert race; tp is another request's proto (chain ref already released by tp_new's destroy)
Both errout reactions are single expressions derived from the state.
This fix is motivated by the Sashiko's automated review of Patch (net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers) [1][2]. The review identified the silent-unlink behaviour of an adopted proto's teardown when a request loses the tcf_chain_tp_insert_unique() race.
[1] https://sashiko.dev/#/patchset/20260801125632.360365-1-jhs%40mojatatu.com
[2] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260801125632.360365-1-jhs%40mojatatu.com
--- net/sched/cls_api.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
net/sched/cls_api.c +13 -5
@@ -2220,6 +2220,12 @@ static bool is_ingress_or_clsact(struct tcf_block *block, struct Qdisc *q)return tcf_block_shared (block) || (q && !!(q->flags &TCQ_F_INGRESS )); } +enum tcf_tp_insert_state { +TP_NOT_CREATED =0 ,/* did not create and insert a new tp */ +TP_CREATED ,/* created and inserted a new tp */ +TP_NOT_OWNED ,/* created a proto but failed to insert */ +}; +static int tc_new_tfilter (struct sk_buff *skb,struct nlmsghdr *n,struct netlink_ext_ack *extack) {
@@ -2240,12 +2246,12 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,unsigned long cl;void *fh;int err; -int tp_created; +enum tcf_tp_insert_state tp_state;bool rtnl_held = false;u32 flags; replay: - tp_created =0 ; + tp_state =TP_NOT_CREATED ; err =nlmsg_parse_deprecated (n,sizeof (*t), tca,TCA_MAX , rtm_tca_policy, extack);
@@ -2368,13 +2374,15 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, goto errout_tp; } - tp_created =1 ; + tp_state =TP_CREATED ; tp =tcf_chain_tp_insert_unique (chain, tp_new, protocol, prio, rtnl_held);if (IS_ERR (tp)) { err =PTR_ERR (tp); goto errout_tp; } +if (tp != tp_new) + tp_state =TP_NOT_OWNED ; }else {mutex_unlock (&chain->filter_chain_lock); }
@@ -2428,13 +2436,13 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, } errout: -if (err && tp_created) +if (err && tp_state ==TP_CREATED )tcf_chain_tp_delete_empty (chain, tp, rtnl_held,NULL ); errout_tp:if (chain) {if (tp && !IS_ERR (tp))tcf_proto_put (tp, rtnl_held,NULL ); -if (!tp_created) +if (tp_state ==TP_NOT_CREATED )tcf_chain_put (chain); }tcf_block_release (q, block, rtnl_held);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1135/1424 riscv: cpufeature: Clarify ISA spec version for canonical order
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guodong Xu <[email protected]>
[ Upstream commit fdef048705daa3d4ed1fa212ee071bcbdac02d80 ]
Specify that chapter 27 refers to version 20191213 of the RISC-V ISA Unprivileged Architecture. The chapter numbering differs across specification versions - for example, in version 20250508, the ISA Extension Naming Conventions is chapter 36, not chapter 27.
Historical versions of the RISC-V specification can be found via Link [1].
--- arch/riscv/kernel/cpufeature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/riscv/kernel/cpufeature.c +2 -1
@@ -114,7 +114,8 @@ static bool riscv_isa_extension_check(int id)/* * The canonical order of ISA extension names in the ISA string is defined in -* chapter 27 of the unprivileged specification. +* Chapter 27 of the RISC-V Instruction Set Manual Volume I Unprivileged ISA +* (Document Version 20191213). * * Ordinarily, for in-kernel data structures, this order is unimportant but * isa_ext_arr defines the order of the ISA string in /proc/cpuinfo.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1136/1424 arm64: dts: turris-mox: fix usb3 phys
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomáš Macholda <[email protected]>
[ Upstream commit 0c2a8eed95160e41b367a1fa605a2c1b24a9639a ]
After commit 00e6d608fe80b0f6 ("arm64: dts: marvell: armada-37xx: swap PHYs' order in USB3 controller node") swapped USB3 PHY order, USB initialization breaks on Turris MOX.
This regression was exposed by commit 91ddf6f722084383 ("phy: marvell:
mvebu-a3700-utmi: fix incorrect USB2_PHY_CTRL register access") which made USB2 devices not work at all.
Fix the issue by explicitly adding all USB3 PHYs and PHY names to Turris MOX device-tree.
--- arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +2 -1
@@ -292,7 +292,8 @@ connector { &usb3 { status = "okay"; - phys = <&comphy2 0>; + phys = <&usb2_utmi_otg_phy>, <&comphy2 0>; + phy-names = "usb2-phy", "usb3-phy"; }; &mdio {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1137/1424 ARM: dts: helios4: add vcc-supply to EEPROM
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit ef65cf08bd1aa723de2854d02fb8eb8cca273c90 ]
The at24 driver requests a 'vcc' supply for the EEPROM, producing 'supply vcc not found, using dummy regulator' at boot when the property is missing.
The EEPROM sits on the Helios 4 and is powered by the same always-on 3.3V rail used by other on-board I2C devices. Add vcc-supply = <®_3p3v> to silence the warning.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +4 -0
@@ -201,6 +201,10 @@ temp_sensor: temp@4c { reg = <0x4c>; vcc-supply = <®_3p3v>; }; + + eeprom@53 { + vcc-supply = <®_3p3v>; + }; }; i2c@11100 {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1138/1424 ARM: dts: helios4: add vcc-supply to GPIO expander
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit c23988f84496e937dd255564cb30bec67608dcc6 ]
The pca953x driver requests a 'vcc' supply, producing:
pca953x 0-0020: supply vcc not found, using dummy regulator
The PCA9655 (PCA9555-compatible) expander is powered by the same always-on 3.3V rail as the other I2C devices on the bus. Add vcc-supply = <®_3p3v> to silence the warning.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 1 + 1 file changed, 1 insertion(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +1 -0
@@ -169,6 +169,7 @@ expander0: gpio-expander@20 { gpio-controller; #gpio-cells = <2>; reg = <0x20>; + vcc-supply = <®_3p3v>; pinctrl-names = "default"; pinctrl-0 = <&pca0_pins>; interrupt-parent = <&gpio0>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1139/1424 ARM: dts: helios4: add SATA regulator supplies
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit 7a90520e8c9a8f48fe6f3e741cf34d8c2b6dbc61 ]
The ahci-mvebu driver and libahci_platform request three supplies on SATA controller and port nodes:
- ahci-supply (controller power)
- phy-supply (PHY power)
- target-supply (disk power per port)
Without them the regulator core prints notices at boot, e.g.:
supply ahci not found, using dummy regulator supply phy not found, using dummy regulator supply target not found, using dummy regulator
The SATA controller and PHY inside the Armada 388 SoC are powered by the 3.3V I/O rail; the four disk bays are powered by the 5V HDD rail. Wire the existing fixed regulators accordingly.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +8 -0
@@ -222,13 +222,17 @@ sata@a8000 { status = "okay"; #address-cells = <1>; #size-cells = <0>; + ahci-supply = <®_3p3v>; + phy-supply = <®_3p3v>; sata0: sata-port@0 { reg = <0>; + target-supply = <®_5p0v_hdd>; }; sata1: sata-port@1 { reg = <1>; + target-supply = <®_5p0v_hdd>; }; };
@@ -236,13 +240,17 @@ sata@e0000 { status = "okay"; #address-cells = <1>; #size-cells = <0>; + ahci-supply = <®_3p3v>; + phy-supply = <®_3p3v>; sata2: sata-port@0 { reg = <0>; + target-supply = <®_5p0v_hdd>; }; sata3: sata-port@1 { reg = <1>; + target-supply = <®_5p0v_hdd>; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1140/1424 perf stat: Fix evsel_list leak in cmd_stat
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 340641a4b5fff4f4b12261c9d92169f6e2ea11f4 ]
Fix a memory leak in cmd_stat() where evsel_list is leaked if an error occurs while opening the output file.
--- tools/perf/builtin-stat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +6 -3
@@ -2596,7 +2596,8 @@ int cmd_stat(int argc, const char **argv) output =fopen (output_name, mode);if (!output) {perror ("failed to create output file" ); -return -1 ; + status =-1 ; + goto out; }if (!stat_config.json_output) {clock_gettime (CLOCK_REALTIME , &tm);
@@ -2607,7 +2608,8 @@ int cmd_stat(int argc, const char **argv) output =fdopen (output_fd, mode);if (!output) {perror ("Failed opening logfd" ); -return -errno; + status = -errno; + goto out; } }
@@ -2616,7 +2618,8 @@ int cmd_stat(int argc, const char **argv)parse_options_usage (stat_usage, stat_options,"o" ,1 );parse_options_usage (NULL , stat_options,"log-fd" ,0 );parse_options_usage (NULL , stat_options,"interval-clear" ,0 ); -return -1 ; + status =-1 ; + goto out; } stat_config.output = output;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1141/1424 perf synthetic-events: Fix uninitialized pthread_join
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 54ba44db4dddc4ca06b49bae0f9d6c5861430b18 ]
In perf_event__synthesize_threads(), fix an uninitialized pthread_join() call when thread creation fails by only joining the successfully created threads.
--- tools/perf/util/synthetic-events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/synthetic-events.c +2 -2
@@ -1075,8 +1075,8 @@ int perf_event__synthesize_threads(struct perf_tool *tool, } err =0 ; out_join: -for (i =0 ; i < thread_nr; i++) -pthread_join (synthesize_threads[i],NULL ); +for (j =0 ; j < i; j++) +pthread_join (synthesize_threads[j],NULL );free (args); free_threads:free (synthesize_threads);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1142/1424 perf synthetic-events: Fix divide by zero in perf_event__synthesize_threads
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 16a12a54e9a1151a37aab74914a51b86f7f58d0e ]
If scandir() finds no matching tasks in /proc, n is 0. If thread_nr is > 1, we bypass the single-thread fast path and then clamp thread_nr to n, making it 0. This results in a divide by zero when calculating num_per_thread.
Handle n <= 1 early to use the single-thread fast path and prevent the crash.
--- tools/perf/util/synthetic-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/synthetic-events.c +1 -1
@@ -1029,7 +1029,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,else thread_nr = nr_threads_synthesize; -if (thread_nr <=1 ) { +if (thread_nr <=1 || n <=1 ) { err = __perf_event__synthesize_threads(tool, process, machine, needs_mmap, mmap_data,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1143/1424 fbdev: tdfxfb: fix PCI enable cleanup with pcim_enable_device()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit 95a627143a696f70e17be5ed3b1e733bb6724b46 ]
tdfxfb_probe() enables the PCI device with pci_enable_device(), but several failure paths after that point return without disabling it. The framebuffer_alloc() failure path returns -ENOMEM directly, and the later shared out_err path releases the framebuffer and returns -ENXIO without balancing the PCI enable state.
The successful probe path has the same imbalance because tdfxfb_remove() releases the framebuffer, mappings and regions, but never calls pci_disable_device().
Use pcim_enable_device() so the PCI device is disabled automatically on probe failure and driver detach.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/video/fbdev/tdfxfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/video/fbdev/tdfxfb.c +1 -1
@@ -1384,7 +1384,7 @@ static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)if (err)return err; - err =pci_enable_device (pdev); + err =pcim_enable_device (pdev);if (err) {printk (KERN_ERR "tdfxfb: Can't enable pdev: %d\n" , err);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1144/1424 fbdev: kyro: Validate overlay viewport coordinates
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danila Chernetsov <[email protected]>
[ Upstream commit 7b5c7bc55e13e7f5ac7b1eaf5c6d690389ea5ee3 ]
The overlay viewport end coordinates are computed from the viewport origin and dimensions using 32-bit unsigned arithmetic. Large input values can cause these calculations to wrap around before the resulting coordinates are passed to SetOverlayViewPort().
SetOverlayViewPort() packs the viewport coordinates into 16-bit register fields. The X coordinates are additionally adjusted by +2 and +1 before being written. Validate the coordinate calculations for 32-bit wraparound and ensure that the adjusted coordinates fit within their 16-bit register fields before calling SetOverlayViewPort().
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/video/fbdev/kyro/fbdev.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
drivers/video/fbdev/kyro/fbdev.c +23 -1
@@ -369,6 +369,9 @@ static int kyro_dev_overlay_create(u32 ulWidth,static int kyro_dev_overlay_viewport_set (u32 x,u32 y,u32 ulWidth,u32 ulHeight) { +u32 right; +u32 bottom; +if (deviceInfo.ulOverlayOffset ==0 )/* probably haven't called CreateOverlay yet */ return -EINVAL ;
@@ -378,11 +381,30 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight (x < 2 && ulWidth + 2 == 0))return -EINVAL ; +/* +* SetOverlayViewPort() adjusts X coordinates by +2 (left) and +1 +* (right) before packing them into 16-bit register fields. +*/ +if (x >U16_MAX -2 || y >U16_MAX ) +return -EINVAL ; + + right = x + ulWidth; + bottom = y + ulHeight; + +if (right < x || bottom < y) +return -EINVAL ; + + right--; + bottom--; + +if (right >U16_MAX -1 || bottom >U16_MAX ) +return -EINVAL ; +/* Stop Ramdac Output */ DisableRamdacOutput (deviceInfo.pSTGReg);SetOverlayViewPort (deviceInfo.pSTGReg, - x, y, x + ulWidth -1 , y + ulHeight -1 ); + x, y, right, bottom);EnableOverlayPlane (deviceInfo.pSTGReg);/* Start Ramdac Output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1145/1424 iommu/vt-d: Fix UCTP context table slot when copying root entries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Desnes Nunes <[email protected]>
[ Upstream commit c6e63fc8e8fcefa5c32145dc0a3c82975b0ce152 ]
When translation is already enabled at boot (e.g. kdump), the vt-d driver copies context tables from the previous kernel's root table. In scalable mode, buses that only populate the upper root half (UCTP, devfn >= 0x80) should be written to ctxt_tbls[tbl_idx + 1] through copy_context_table(). However, the current copy path always uses tbl[tbl_idx + 0] in this situa- tion. Since idx wraps to 0 at devfn 0x80 due to a zeroed LCTP, new_ce for LCTP will be NULL and keep pos equals to 0. Thus, UCTP entries will be co- pied into tbl[tbl_idx + 0] instead of tbl[tbl_idx + 1], and written after- wards to root_entry[bus].lo instead of .hi in copy_translation_tables().
In short, devices on bus 0x80 with devfn >= 0x80 fail DMA with fault 0x39, which will break drivers running in kernels with translation pre-enabled. This fixes NO_PASID DMAR faults for UCTP-only buses such as:
DMAR: [DMA Read NO_PASID] Request device [80:14.0] fault addr 0xe81759000
[fault reason 0x39] SM: Present bit in Root Entry is clear
For instance, this fault yielded to locking issues between systemd and xHCI, blocking a system's reboot after a vmcore was captured with kdump:
systemd-udevd[246]: usb3: Worker [255] processing SEQNUM=2193 is taking a long time dracut-initqueue[277]: Timed out while waiting for udev queue to empty. systemd-udevd[246]: usb3: Worker [255] processing SEQNUM=2193 killed systemd-udevd[246]: usb3: Worker [255] terminated by signal 9 (KILL).
...
kdump[569]: saving vmcore complete
...
systemd-shutdown[1]: Rebooting.
INFO: task kworker/0:1:11 blocked for more than 122 seconds.
Not tainted 7.0.0-clean #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208160 flags:0x00080000
Workqueue: usb_hub_wq hub_event
Call Trace:
<TASK>
__schedule+0x299/0x5c0
schedule+0x27/0x80
schedule_timeout+0xbd/0x100
__wait_for_common+0x97/0x1b0
? __pfx_schedule_timeout+0x10/0x10
xhci_alloc_dev+0x9e/0x2b0
usb_alloc_dev+0x7a/0x3b0
hub_port_connect+0x285/0x960
hub_port_connect_change+0x94/0x290
port_event+0x4bb/0x840
hub_event+0x141/0x460
process_one_work+0x196/0x390
worker_thread+0x1af/0x320
? __pfx_worker_thread+0x10/0x10
kthread+0xe3/0x120
? __pfx_kthread+0x10/0x10
ret_from_fork+0x199/0x260
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
INFO: task systemd-shutdow:1 blocked for more than 122 seconds.
Not tainted 7.0.0-clean #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:systemd-shutdow state:D stack:0 pid:1 tgid:1 ppid:0 task_flags:0x400100 flags:0x00080000
Call Trace:
<TASK>
__schedule+0x299/0x5c0
schedule+0x27/0x80
schedule_preempt_disabled+0x15/0x30
__mutex_lock.constprop.0+0x547/0xac0
device_shutdown+0xac/0x1b0
kernel_restart+0x3a/0x70
__do_sys_reboot+0x147/0x240
do_syscall_64+0x11b/0x6a0
? handle_mm_fault+0x110/0x350
? do_user_addr_fault+0x206/0x680
? irqentry_exit+0x7a/0x4d0
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7fe2958da917
RSP: 002b:00007ffc5c458618 EFLAGS: 00000206 ORIG_RAX: 00000000000000a9
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fe2958da917
RDX: 0000000001234567 RSI: 0000000028121969 RDI: 00000000fee1dead
RBP: 00007ffc5c458790 R08: 0000000000000069 R09: 00000000ffffffff
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 0000000000000000 R14: 00007ffc5c4588b8 R15: 0000000000000000
</TASK>
INFO: task systemd-shutdow:1 is blocked on a mutex likely owned by task kworker/0:1:11.--- drivers/iommu/intel/iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iommu/intel/iommu.c +6 -4
@@ -2607,7 +2607,7 @@ static int copy_context_table(struct intel_iommu *iommu,struct context_entry **tbl, int bus, bool ext) { - int tbl_idx, pos = 0, idx, devfn, ret = 0, did; + int tbl_idx, tbl_slot = 0, idx, devfn, ret = 0, did;struct context_entry *new_ce =NULL , ce;struct context_entry *old_ce =NULL ;struct root_entry re;
@@ -2623,10 +2623,9 @@ static int copy_context_table(struct intel_iommu *iommu,if (idx ==0 ) {/* First save what we may have and clean up */ if (new_ce) { - tbl[tbl_idx] = new_ce; + tbl[tbl_idx + tbl_slot] = new_ce;__iommu_flush_cache (iommu, new_ce,VTD_PAGE_SIZE ); - pos =1 ; }if (old_ce)
@@ -2648,6 +2647,9 @@ static int copy_context_table(struct intel_iommu *iommu, } } +/* Track if saving UCTP or LCTP entries in scalable mode */ + tbl_slot = ext && devfn >=0x80 ?1 :0 ; + ret = -ENOMEM ; old_ce =memremap (old_ce_phys,PAGE_SIZE ,MEMREMAP_WB );
@@ -2675,7 +2677,7 @@ static int copy_context_table(struct intel_iommu *iommu, new_ce[idx] = ce; } - tbl[tbl_idx + pos] = new_ce; + tbl[tbl_idx + tbl_slot] = new_ce;__iommu_flush_cache (iommu, new_ce,VTD_PAGE_SIZE );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1146/1424 m68k: Fix backtraces for non-running tasks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 09f71dbeb287e367beea56d9ac8a3d356ef5e02a ]
When no stack pointer is supplied, show_stack() starts at thread.esp0. This is the saved userspace register frame, not where a task was switched out. For kernel threads it points to the zeroed frame created by copy_thread(), so sched_show_task() prints no useful backtrace.
Use thread.ksp for non-current tasks. It is saved by switch_to() and is already used by __get_wchan(). For current, start at the current stack frame, as is already done when no task is supplied.
Tested on qemu-system-m68k -M virt using SysRq-t. All task dumps contained resolved frames.
--- arch/m68k/kernel/traps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/m68k/kernel/traps.c +2 -2
@@ -937,8 +937,8 @@ void show_stack(struct task_struct *task, unsigned long *stack,int i;if (!stack) { -if (task) - stack = (unsigned long *)task->thread.esp0; +if (task && task != current) + stack = (unsigned long *)task->thread.ksp;else stack = (unsigned long *)&stack; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1147/1424 arm64: Disable KCSAN instrumentation in delay.o
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Elver <[email protected]>
[ Upstream commit 5eaec4cf41a8f5ac1a0c69a607cdc5035a797f73 ]
KCSAN relies on udelay() for injecting delays. To avoid recursively triggering a watchpoint, where KCSAN sets up watchpoint on an address that is accessed by udelay() in the same thread, disable instrumentation in arm64's delay implementation.
Paul found a manifestation of this as follows:
| BUG: KCSAN: data-race in __delay / set_need_resched_current | | read (marked) to 0xffff000005899b48 of 8 bytes by interrupt on cpu 8: | __delay+0xb0/0x378 | __udelay+0x4c/0x60 | kcsan_setup_watchpoint+0x3b4/0x820 | __tsan_unaligned_write4+0x228/0x26c | set_need_resched_current+0x138/0x1a8 | rcu_exp_handler+0x418/0x4a0 | __flush_smp_call_function_queue+0x36c/0x4a0 | generic_smp_call_function_single_interrupt+0x20/0x30 | ipi_handler+0xec/0x558 | handle_percpu_devid_irq+0x220/0x2a0 | generic_handle_domain_irq+0x84/0xb4 | gic_handle_irq+0x64/0x144 | call_on_irq_stack+0x30/0x48 | do_interrupt_handler+0x80/0xb8 | el1_interrupt+0x3c/0x60 | el1h_64_irq_handler+0x18/0x24 | el1h_64_irq+0x6c/0x70 | smp_call_function_single+0x18c/0x25c | sync_rcu_exp_select_node_cpus+0x534/0x8bc | rcu_exp_sel_wait_wake+0x358/0xef4 | wait_rcu_exp_gp+0x30/0x44 | kthread_worker_fn+0x1b4/0x5dc | kthread+0x1d8/0x204 | ret_from_fork+0x10/0x20 | | write to 0xffff000005899b4c of 4 bytes by interrupt on cpu 8: | set_need_resched_current+0x138/0x1a8 | [...]
This matches what is already done in arch/x86/lib/Makefile.
--- arch/arm64/lib/Makefile | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/lib/Makefile +4 -0
@@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 + +# KCSAN uses udelay for introducing watchpoint delay; avoid recursion. +KCSAN_SANITIZE_delay.o := n + lib-y := clear_user.o delay.o copy_from_user.o \ copy_to_user.o copy_page.o \ clear_page.o csum.o insn.o memchr.o memcpy.o \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1148/1424 SUNRPC: check rpc_sockaddr2uaddr() return value in rpcb_register_inet4/6
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit fd22370226a0d8109045d0831fd5aaadee921693 ]
rpcb_register_inet4() and rpcb_register_inet6() store the result of rpc_sockaddr2uaddr() into map->r_addr without checking it for NULL. rpc_sockaddr2uaddr() returns NULL when its final kstrdup() fails, and the unchecked NULL is then carried into the synchronous RPCBPROC_SET encode path: rpcb_register_call() -> rpc_call_sync() -> rpcb_enc_getaddr() -> encode_rpcb_string(), whose first statement is strlen(string), dereferencing NULL and oopsing the kernel.
The crash reproduces under failslab on v6.12; with KASAN the NULL dereference surfaces as a fault on the shadow of address zero:
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000000 [#1] PREEMPT SMP KASAN
RIP: 0010:strlen (lib/string.c:409)
Call Trace:
encode_rpcb_string (net/sunrpc/rpcb_clnt.c:890)
rpcb_enc_getaddr (net/sunrpc/rpcb_clnt.c:910)
rpcauth_wrap_req_encode (net/sunrpc/auth.c:745)
call_encode (net/sunrpc/clnt.c:1966)
__rpc_execute (net/sunrpc/sched.c:952)
rpc_run_task (net/sunrpc/clnt.c:1243)
rpc_call_sync (net/sunrpc/clnt.c:1272)
rpcb_v4_register (net/sunrpc/rpcb_clnt.c:500)
svc_generic_rpcbind_set
nfsd_rpcbind_set
svc_register
svc_setup_socket
svc_addsock
write_ports
nfsctl_transaction_write
vfs_writeThe crash is reachable when an in-kernel RPC service (nfsd, lockd, nfs-callback) registers with the local rpcbind under enough memory pressure for the small GFP_KERNEL kstrdup() in rpc_sockaddr2uaddr() to fail. The asynchronous getport path already handles this exact failure mode by returning -ENOMEM; only the two register helpers omit the check.
Mirror that handling: bail out with -ENOMEM when rpc_sockaddr2uaddr() returns NULL, before the address is fed into the encoder.
--- net/sunrpc/rpcb_clnt.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sunrpc/rpcb_clnt.c +4 -0
@@ -490,6 +490,8 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,int result; map->r_addr =rpc_sockaddr2uaddr (sap,GFP_KERNEL ); +if (!map->r_addr) +return -ENOMEM ; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET ];if (port !=0 ) {
@@ -516,6 +518,8 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,int result; map->r_addr =rpc_sockaddr2uaddr (sap,GFP_KERNEL ); +if (!map->r_addr) +return -ENOMEM ; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET ];if (port !=0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1149/1424 sunrpc: xprtsock: annotate shared socket callbacks with READ_ONCE/WRITE_ONCE
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 33930840b5f0a79f826e7c69dc6cd78f72a67481 ]
xprtsock replaces and restores sk->sk_data_ready and sk->sk_write_space on live sockets with plain stores, and xs_udp_do_set_buffer_size() invokes sk->sk_write_space via a plain load. These callback pointers are shared with generic socket and protocol paths that may read or invoke them concurrently, so xprtsock needs the same READ_ONCE()/WRITE_ONCE() callback visibility contract that the validated 4022 family applied elsewhere.
When SUNRPC takes over an AF_LOCAL, UDP, or TCP socket and later restores the lower-socket callbacks during teardown, another CPU may still hold an earlier callback snapshot. The plain replace/restore pattern leaves the same visibility hole as the validated 4022 family, so a stale snapshot can still invoke xs_data_ready() or xs_udp_write_space() after the live callback fields have already been restored to the lower-socket handlers.
Use WRITE_ONCE() for the shared sk_data_ready and sk_write_space stores in xs_local_finish_connecting(), xs_udp_finish_connecting(), xs_tcp_finish_connecting(), and xs_restore_old_callbacks(). Use READ_ONCE() for the direct sk_write_space invocation in xs_udp_do_set_buffer_size(). This matches the required callback visibility contract while leaving adjacent sk_state_change and sk_error_report handling unchanged.
--- net/sunrpc/xprtsock.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
net/sunrpc/xprtsock.c +11 -9
@@ -1191,9 +1191,9 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk)static void xs_restore_old_callbacks (struct sock_xprt *transport,struct sock *sk) { - sk->sk_data_ready = transport->old_data_ready; +WRITE_ONCE (sk->sk_data_ready, transport->old_data_ready); sk->sk_state_change = transport->old_state_change; - sk->sk_write_space = transport->old_write_space; +WRITE_ONCE (sk->sk_write_space, transport->old_write_space); sk->sk_error_report = transport->old_error_report; }
@@ -1649,6 +1649,7 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);struct sock *sk = transport->inet; +void (*write_space)(struct sock *sock);if (transport->rcvsize) { sk->sk_userlocks |=SOCK_RCVBUF_LOCK ;
@@ -1657,7 +1658,8 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)if (transport->sndsize) { sk->sk_userlocks |=SOCK_SNDBUF_LOCK ; sk->sk_sndbuf = transport->sndsize * xprt->max_reqs *2 ; - sk->sk_write_space (sk); + write_space =READ_ONCE (sk->sk_write_space); +write_space (sk); } }
@@ -1968,8 +1970,8 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; - sk->sk_write_space = xs_udp_write_space; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); +WRITE_ONCE (sk->sk_write_space, xs_udp_write_space); sk->sk_state_change = xs_local_state_change; sk->sk_error_report = xs_error_report; sk->sk_use_task_frag = false;
@@ -2171,8 +2173,8 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; - sk->sk_write_space = xs_udp_write_space; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); +WRITE_ONCE (sk->sk_write_space, xs_udp_write_space); sk->sk_use_task_frag = false;xprt_set_connected (xprt);
@@ -2358,9 +2360,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); sk->sk_state_change = xs_tcp_state_change; - sk->sk_write_space = xs_tcp_write_space; +WRITE_ONCE (sk->sk_write_space, xs_tcp_write_space); sk->sk_error_report = xs_error_report; sk->sk_use_task_frag = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1150/1424 powerpc/configs: enable CONFIG_RAS to fix EDAC support
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 3921cfc2e8155a767235801be88cbd0e4c73508d ]
Before commit e3c4ff6d8c94 ("EDAC: Remove EDAC_MM_EDAC") EDAC_MM_EDAC selected RAS, after that commit, EDAC depends on RAS, but nobody enables it. Enable it in the config again.
--- arch/powerpc/configs/85xx-hw.config | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/configs/85xx-hw.config +1 -0
@@ -90,6 +90,7 @@ CONFIG_PPC_EPAPR_HV_BYTECHAN=y CONFIG_QE_GPIO=y CONFIG_QUICC_ENGINE=y CONFIG_RAPIDIO=y +CONFIG_RAS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_DS1307=y
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1151/1424 phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Esteban Urrutia <[email protected]>
[ Upstream commit 481807f939077059db278edd0467e7e609b6c9a7 ]
Comparing sm8350 and sm8450 tables, this seems to be a typo.
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +1 -1
@@ -1257,7 +1257,7 @@ static const u8 qmp_dp_v4_pre_emphasis_hbr3_hbr2[4][4] = {static const u8 qmp_dp_v4_pre_emphasis_hbr_rbr[4 ][4 ] = { {0x00 ,0x0d ,0x14 ,0x1a }, {0x00 ,0x0e ,0x15 ,0xff }, - {0x00 ,0x0d ,0xff ,0xff }, + {0x00 ,0x0e ,0xff ,0xff }, {0x03 ,0xff ,0xff ,0xff } };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1152/1424 spi: sprd-adi: Fix probe succeeding without registering the controller
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Babanpreet Singh <[email protected]>
[ Upstream commit f092e1c935015ee0a0fea1a0374f4cab7b71953c ]
With CONFIG_HWSPINLOCK=n the of_hwspin_lock_get_id() stub returns 0 unconditionally. In sprd_adi_probe() the guard
if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0))
is false for that 0, so it takes the else branch, where the switch has no case for 0 and lands in
default: return dev_err_probe(&pdev->dev, ret, "failed to find hwlock id\n");
dev_err_probe() returns its err argument unchanged, so probe logs "failed to find hwlock id" and then returns 0, reporting success. sprd_adi_hw_init(), the restart handler and devm_spi_register_controller() are all skipped: the device binds but no SPI controller is ever registered.
The hardware spinlock is optional for this controller and the -ENOENT arm already covers "no hardware spinlock supplied". Treat the stub's 0 the same way and continue without a lock; all four users of sadi->hwlock already test it for NULL.
This is not reachable on production kernels. Kconfig has
depends on HWSPINLOCK || (COMPILE_TEST && !HWSPINLOCK)
so the affected configuration exists only under COMPILE_TEST, where no real hardware is present.
Found by smatch:drivers/spi/spi-sprd-adi.c:560 sprd_adi_probe() warn: passing zero to 'dev_err_probe'
--- drivers/spi/spi-sprd-adi.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/spi/spi-sprd-adi.c +6 -0
@@ -553,6 +553,12 @@ static int sprd_adi_probe(struct platform_device *pdev)return -ENXIO ; }else {switch (ret) { +case 0 : +/* +* Only reachable with CONFIG_HWSPINLOCK=n, where the +* of_hwspin_lock_get_id() stub returns 0. +*/ + fallthrough;case -ENOENT :dev_info (&pdev->dev,"no hardware spinlock supplied\n" );break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1153/1424 ASoC: qcom: q6apm: keep the graph start count in sync with the DSP
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jorijn van der Graaf <[email protected]>
[ Upstream commit daa7ffd765ae67a83e77dae32c66ce2d6d995d19 ]
q6apm_graph_start() increments start_count even when APM_CMD_GRAPH_START fails, leaving the graph counted as running while the DSP never started it. A later start - a retried prepare, or a resume after a failed start - then finds a non-zero count, skips the command and returns success with no data flowing.
Count the graph only once the DSP has accepted the start. The count then stays at zero for a graph that never started, so also stop decrementing below zero in q6apm_graph_stop(): the compressed free path stops unconditionally, and a negative count would make the next start skip the command in the same way.
--- sound/soc/qcom/qdsp6/q6apm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
sound/soc/qcom/qdsp6/q6apm.c +9 -3
@@ -697,14 +697,17 @@ EXPORT_SYMBOL_GPL(q6apm_graph_prepare);int q6apm_graph_start (struct q6apm_graph *graph) {struct audioreach_graph *ar_graph = graph->ar_graph; -int ret =0 ; +int ret; -if (ar_graph->start_count ==0 ) +if (ar_graph->start_count ==0 ) { ret =audioreach_graph_mgmt_cmd (ar_graph,APM_CMD_GRAPH_START ); +if (ret) +return ret; + } ar_graph->start_count++; -return ret; +return 0 ; }EXPORT_SYMBOL_GPL (q6apm_graph_start);
@@ -712,6 +715,9 @@ int q6apm_graph_stop(struct q6apm_graph *graph) {struct audioreach_graph *ar_graph = graph->ar_graph; +if (ar_graph->start_count ==0 ) +return 0 ; +if (--ar_graph->start_count >0 )return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1154/1424 nvme: add reservation commands defines
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 1900e1a4495b7376cb9b4e58f1d846660f4c9c4b ]
This is a preparation patch for NVMeOF target reservation commands implantation.
Add the defines of reservation command, such as reservation log and sub operations.
Stable-dep-of: 5bb96cc21883 ("nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()")
--- include/linux/nvme.h | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
include/linux/nvme.h +68 -0
@@ -2024,4 +2024,72 @@ struct nvme_completion {#define NVME_MINOR (ver) (((ver) >> 8) & 0xff)#define NVME_TERTIARY (ver) ((ver) & 0xff) +enum { +NVME_AEN_RESV_LOG_PAGE_AVALIABLE =0x00 , +}; + +enum { +NVME_PR_LOG_EMPTY_LOG_PAGE =0x00 , +NVME_PR_LOG_REGISTRATION_PREEMPTED =0x01 , +NVME_PR_LOG_RESERVATION_RELEASED =0x02 , +NVME_PR_LOG_RESERVATOPM_PREEMPTED =0x03 , +}; + +enum { +NVME_PR_NOTIFY_BIT_REG_PREEMPTED =1 , +NVME_PR_NOTIFY_BIT_RESV_RELEASED =2 , +NVME_PR_NOTIFY_BIT_RESV_PREEMPTED =3 , +}; + +struct nvme_pr_log { +__le64 count; +__u8 type; +__u8 nr_pages; +__u8 rsvd1[2 ]; +__le32 nsid; +__u8 rsvd2[48 ]; +}; + +struct nvmet_pr_register_data { +__le64 crkey; +__le64 nrkey; +}; + +struct nvmet_pr_acquire_data { +__le64 crkey; +__le64 prkey; +}; + +struct nvmet_pr_release_data { +__le64 crkey; +}; + +enum nvme_pr_capabilities { +NVME_PR_SUPPORT_PTPL =1 , +NVME_PR_SUPPORT_WRITE_EXCLUSIVE =1 <<1 , +NVME_PR_SUPPORT_EXCLUSIVE_ACCESS =1 <<2 , +NVME_PR_SUPPORT_WRITE_EXCLUSIVE_REG_ONLY =1 <<3 , +NVME_PR_SUPPORT_EXCLUSIVE_ACCESS_REG_ONLY =1 <<4 , +NVME_PR_SUPPORT_WRITE_EXCLUSIVE_ALL_REGS =1 <<5 , +NVME_PR_SUPPORT_EXCLUSIVE_ACCESS_ALL_REGS =1 <<6 , +NVME_PR_SUPPORT_IEKEY_VER_1_3_DEF =1 <<7 , +}; + +enum nvme_pr_register_action { +NVME_PR_REGISTER_ACT_REG =0 , +NVME_PR_REGISTER_ACT_UNREG =1 , +NVME_PR_REGISTER_ACT_REPLACE =1 <<1 , +}; + +enum nvme_pr_acquire_action { +NVME_PR_ACQUIRE_ACT_ACQUIRE =0 , +NVME_PR_ACQUIRE_ACT_PREEMPT =1 , +NVME_PR_ACQUIRE_ACT_PREEMPT_AND_ABORT =1 <<1 , +}; + +enum nvme_pr_release_action { +NVME_PR_RELEASE_ACT_RELEASE =0 , +NVME_PR_RELEASE_ACT_CLEAR =1 , +}; +#endif /* _LINUX_NVME_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1155/1424 nvme: introduce change ptpl and iekey definition
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 7d2f9f870f26798699585f96fa7a2a2cab38dc02 ]
This is for the next tuning pr code more readble patch, make linux/nvme.h's changes separately.
Stable-dep-of: 5bb96cc21883 ("nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()")
--- include/linux/nvme.h | 9 +++++++++ 1 file changed, 9 insertions(+)
include/linux/nvme.h +9 -0
@@ -2092,4 +2092,13 @@ enum nvme_pr_release_action { NVME_PR_RELEASE_ACT_CLEAR = 1, }; +enum nvme_pr_change_ptpl { +NVME_PR_CPTPL_NO_CHANGE =0 , +NVME_PR_CPTPL_RESV =1 <<30 , +NVME_PR_CPTPL_CLEARED =2 <<30 , +NVME_PR_CPTPL_PERSIST =3 <<30 , +}; + +#define NVME_PR_IGNORE_KEY (1 << 3) +#endif /* _LINUX_NVME_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1156/1424 nvme: Add the DHCHAP maximum HD IDs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alistair Francis <[email protected]>
[ Upstream commit 09e8f0f93491c6be867f32d4edc0b16fb5da785e ]
In preperation for using DHCHAP length in upcoming host and target patches let's add the hash and diffie-hellman ID length macros.
Stable-dep-of: 5bb96cc21883 ("nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()")
--- include/linux/nvme.h | 4 ++++ 1 file changed, 4 insertions(+)
include/linux/nvme.h +4 -0
@@ -2101,4 +2101,8 @@ enum nvme_pr_change_ptpl {#define NVME_PR_IGNORE_KEY (1 << 3) +/* Section 8.3.4.5.2 of the NVMe 2.1 */ +#define NVME_AUTH_DHCHAP_MAX_HASH_IDS 30 +#define NVME_AUTH_DHCHAP_MAX_DH_IDS 30 +#endif /* _LINUX_NVME_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1157/1424 nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 5bb96cc218835769ab74ec7f3ea2bf81fbffe955 ]
nvmet_execute_auth_send() allocates the DH-HMAC-CHAP message buffer with the host-supplied transfer length (tl) and hands it to nvmet_auth_negotiate() without passing tl along. nvmet_auth_negotiate() then reads the negotiate header and, for each of the halen hash identifiers and dhlen DH group identifiers, indexes into the fixed idlist[60] array (hashes at idlist[0..halen), groups at idlist[30..]).
Neither the transfer length nor halen/dhlen is validated. A malicious or non-conformant host can report a tl smaller than the negotiate structure, or a halen/dhlen larger than the array (both are u8, up to 255), making the loops read past the end of the allocated buffer (heap out-of-bounds read). The sibling nvmet_auth_reply() already validates tl against the structure size; the negotiate path did not.
Pass tl into nvmet_auth_negotiate(), reject a tl that does not cover the negotiate data plus one full protocol descriptor, and reject halen/dhlen larger than NVME_AUTH_DHCHAP_MAX_DH_IDS.
--- drivers/nvme/target/fabrics-cmd-auth.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/nvme/target/fabrics-cmd-auth.c +10 -2
@@ -31,12 +31,16 @@ void nvmet_auth_sq_init(struct nvmet_sq *sq) sq->dhchap_step =NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE ; } -static u8 nvmet_auth_negotiate (struct nvmet_req *req,void *d) +static u8 nvmet_auth_negotiate (struct nvmet_req *req,void *d,u32 tl) {struct nvmet_ctrl *ctrl = req->sq->ctrl;struct nvmf_auth_dhchap_negotiate_data *data = d;int i, hash_id =0 , fallback_hash_id =0 , dhgid, fallback_dhgid; +if (tl <sizeof (*data) + +sizeof (struct nvmf_auth_dhchap_protocol_descriptor )) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; + pr_debug("%s: ctrl %d qid %d: data sc_d %d napd %d authid %d halen %d dhlen %d\n", __func__, ctrl->cntlid, req->sq->qid, data->sc_c, data->napd, data->auth_protocol[0].dhchap.authid,
@@ -53,6 +57,10 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d) NVME_AUTH_DHCHAP_AUTH_ID)return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; +if (data->auth_protocol[0 ].dhchap.dhlen >NVME_AUTH_DHCHAP_MAX_DH_IDS || + data->auth_protocol[0 ].dhchap.halen >NVME_AUTH_DHCHAP_MAX_HASH_IDS ) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; +for (i =0 ; i < data->auth_protocol[0 ].dhchap.halen; i++) {u8 host_hmac_id = data->auth_protocol[0 ].dhchap.idlist[i];
@@ -265,7 +273,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) }else if (data->auth_id != req->sq->dhchap_step) goto done_failure1;/* Validate negotiation parameters */ - dhchap_status =nvmet_auth_negotiate (req, d); + dhchap_status =nvmet_auth_negotiate (req, d, tl);if (dhchap_status ==0 ) req->sq->dhchap_step =NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1158/1424 nvme-apple: Destroy the admin queue on removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Peter <[email protected]>
[ Upstream commit 87d5b9864c8118d26f54de4b66d2bddf2c659272 ]
The admin queue is allocated with blk_mq_alloc_queue() but never destroyed. nvme_free_ctrl() only drops the last reference and blk_mq_exit_queue() and blk_sync_queue() never run: the hctx is never moved to q->unused_hctx_list and the timeout timer and work stay armed on a queue that is about to be freed which will eventually oops inside blk_mq_timeout_work().
This can only be triggered when the controller fails to come up and is then immediately torn down again which is why no one ever ran into this before.
Let's just copy what the pcie driver does: unquiesce and destroy the admin queue before nvme_uninit_ctrl().
With this the following WARN followed by a panic no longer happens:
WARNING: block/blk-mq.c:4390 at blk_mq_release+0x194/0x238, CPU#4: kworker/u34:4/119
CPU: 4 UID: 0 PID: 119 Comm: kworker/u34:4 Not tainted 7.2.0-rc1-dirty #248 PREEMPT
Hardware name: Apple Mac mini (M1, 2020) (DT)
Workqueue: nvme-wq apple_nvme_remove_dead_ctrl_work
pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
pc : blk_mq_release+0x194/0x238
lr : blk_mq_release+0x58/0x238
sp : ffffc000833a3b50
x29: ffffc000833a3b50 x28: ffff80001d0450f8 x27: ffff800020c95200
x26: 0000000000000088 x25: 0000000000000000 x24: ffff800020f36805
x23: 0000000000000000 x22: ffffc00081a86878 x21: ffff800020be9c60
x20: 0000000000000000 x19: ffff800022501698 x18: 000000000000000a
x17: 7365757165722066 x16: 666f7265776f7020 x15: 0000000000000000
x14: 0000000000000028 x13: 0000000000004def x12: 0000000000000003
x11: 0000000000000000 x10: 0000000000000000 x9 : ffffc000805b4fc8
x8 : ffffc00081915820 x7 : ffffc00081c4f3c8 x6 : 0000000000000001
x5 : 0000000000000004 x4 : ffff800022498d80 x3 : ffffc000833a3b14
x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff800022501698
Call trace:
blk_mq_release+0x194/0x238 (P)
blk_put_queue+0x8c/0xf0
nvme_free_ctrl+0x4c/0x260
device_release+0x44/0x128
kobject_put+0xa0/0x120
put_device+0x1c/0x40
nvme_uninit_ctrl+0x48/0x60
apple_nvme_remove+0x54/0xb0
platform_remove+0x28/0x40
device_remove+0x54/0x98
device_release_driver_internal+
device_release_driver+0x20/0x38
apple_nvme_remove_dead_ctrl_wor
process_one_work+0x1f4/0x770
worker_thread+0x1b8/0x360
kthread+0x140/0x160
ret_from_fork+0x10/0x20
irq event stamp: 448
hardirqs last enabled at (447):in_unlock_irqrestore+0x74/0x80
hardirqs last disabled at (448): [<ffffc000811cf5c0>] el1_brk64+0x20/0x60
softirqs last enabled at (0): [ess+0xb28/0x2698
softirqs last disabled at (0): [<0000000000000000>] 0x0
---[ end trace 0000000000000000
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
Mem abort info:
ESR = 0x0000000096000005
EC = 0x25: DABT (current EL),
SET = 0, FnV = 0
EA = 0, S1PTW = 0
FSC = 0x05: level 1 translation fault
Data abort info:
ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
CM = 0, WnR = 0, TnD = 0, TagA
GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[0000000000000000] user address
Internal error: Oops: 0000000096000005 [#1] SMP
CPU: 7 UID: 0 PID: 54 Comm: kwor 7.2.0-rc1-dirty #248PREEMPT
Tainted: [W]=WARN
Hardware name: Apple Mac mini (M1, 2020) (DT)
Workqueue: kblockd blk_mq_timeou
pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
pc : percpu_ref_tryget_many.cons
lr : percpu_ref_tryget_many.constprop.0+0xc0/0x168
sp : ffffc000829cbce0
x29: ffffc000829cbce0 x28: ffff800020be9f48 x27: ffff800013e503c0
x26: 0000000000000108 x25: 000009c05
x23: 0000000000000000 x22: ffffc000819f5000 x21: ffff800020be9f48
x20: ffff8001deda4808 x19: ffff8000a
x17: 00000000580e1fac x16: ffffc00082bbbb7c x15: 0000000000000000
x14: 0000000000000028 x13: 000000001
x11: 0000000000000000 x10: 0000000000000000 x9 : ffffc000829cbc20
x8 : ffffc00081915820 x7 : ffffc0001
x5 : ffff80001ca77d08 x4 : 0000000000000000 x3 : ffff80001ca77cb8
x2 : 0000000000000000 x1 : 000000007
Call trace:
percpu_ref_tryget_many.constpro
blk_mq_timeout_work+0x48/0x298
process_one_work+0x1f4/0x770
worker_thread+0x1b8/0x360
kthread+0x140/0x160
ret_from_fork+0x10/0x20
Code: 91282000 97ed44b2 17ffffd2
---[ end trace 0000000000000000 ]------ drivers/nvme/host/apple.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/nvme/host/apple.c +9 -0
@@ -1571,6 +1571,15 @@ static int apple_nvme_remove(struct platform_device *pdev)nvme_stop_ctrl (&anv->ctrl);nvme_remove_namespaces (&anv->ctrl);apple_nvme_disable (anv, true); +if (anv->ctrl.admin_q && !blk_queue_dying (anv->ctrl.admin_q)) { +/* +* If the controller was reset during removal, it's possible +* user requests may be waiting on a stopped queue. Start the +* queue to flush these to completion. +*/ +nvme_unquiesce_admin_queue (&anv->ctrl); +blk_mq_destroy_queue (anv->ctrl.admin_q); + }nvme_uninit_ctrl (&anv->ctrl);if (apple_rtkit_is_running (anv->rtk))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1159/1424 nvme-apple: Dont set a DMA direction for commands without a data transfer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Peter <[email protected]>
[ Upstream commit 94dd5804938d6681dbf26f023b1356d511f4fc48 ]
Setting the DMA direction for commands that don't do any transfer likely triggered the PRP NULL check for which we needed a chicken bit. That bit has disappeared starting with macOS 15 so let's just do this correctly instead.
--- drivers/nvme/host/apple.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/nvme/host/apple.c +3 -1
@@ -310,7 +310,9 @@ static void apple_nvme_submit_cmd(struct apple_nvme_queue *q, tcb->length = cmd->rw.length; tcb->command_id = tag; -if (nvme_is_write (cmd)) +if (!cmd->common.dptr.prp1) + tcb->dma_flags =0 ; +else if (nvme_is_write (cmd)) tcb->dma_flags =APPLE_ANS_TCB_DMA_TO_DEVICE ;else tcb->dma_flags =APPLE_ANS_TCB_DMA_FROM_DEVICE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1160/1424 nvme-apple: Never set the opcode in the NVMMU TCB
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Peter <[email protected]>
[ Upstream commit cc0fec9b42cfbc69d70cb4c4b616408a7037b445 ]
macOS always sets this to zero and the firmware starting with macOS 15 has started to complain about what we're doing here.
--- drivers/nvme/host/apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/host/apple.c +1 -1
@@ -304,7 +304,7 @@ static void apple_nvme_submit_cmd(struct apple_nvme_queue *q,u32 tag =nvme_tag_from_cid (cmd->common.command_id);struct apple_nvmmu_tcb *tcb = &q->tcbs[tag]; - tcb->opcode = cmd->common.opcode; + tcb->opcode =0 ; tcb->prp1 = cmd->common.dptr.prp1; tcb->prp2 = cmd->common.dptr.prp2; tcb->length = cmd->rw.length;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1161/1424 nvme: apple: Add Apple A11 support
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nick Chan <[email protected]>
[ Upstream commit 04d8ecf37b5e06d16228a4d37d8548c17cf70461 ]
Add support for ANS2 NVMe on Apple A11 SoC.
This version of ANS2 is less quirky than the one in M1, and does not have NVMMU or Linear SQ. However, it still requires a non-standard 128-byte SQE.
Stable-dep-of: 8ce883fd068b ("nvme-apple: Drop the PRP null check chicken bit")
--- drivers/nvme/host/apple.c | 197 ++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 60 deletions(-)
drivers/nvme/host/apple.c +137 -60
@@ -35,7 +35,6 @@#include "nvme.h" #define APPLE_ANS_BOOT_TIMEOUT USEC_PER_SEC -#define APPLE_ANS_MAX_QUEUE_DEPTH 64#define APPLE_ANS_COPROC_CPU_CONTROL 0x44#define APPLE_ANS_COPROC_CPU_CONTROL_RUN BIT(4)
@@ -75,6 +74,8 @@#define APPLE_NVME_AQ_DEPTH 2#define APPLE_NVME_AQ_MQ_TAG_DEPTH (APPLE_NVME_AQ_DEPTH - 1) +#define APPLE_NVME_IOSQES 7 +/* * These can be higher, but we need to ensure that any command doesn't * require an sg allocation that needs more than a page of data.
@@ -142,6 +143,7 @@ struct apple_nvme_queue {u32 __iomem *sq_db;u32 __iomem *cq_db; +u16 sq_tail;u16 cq_head;u8 cq_phase;
@@ -183,11 +185,17 @@ struct apple_nvme_iod {struct scatterlist *sg; }; +struct apple_nvme_hw { +bool has_lsq_nvmmu; +u32 max_queue_depth; +}; +struct apple_nvme {struct device *dev;void __iomem *mmio_coproc;void __iomem *mmio_nvme; +const struct apple_nvme_hw *hw;struct device **pd_dev;struct device_link **pd_link;
@@ -232,10 +240,12 @@ static inline struct apple_nvme *queue_to_apple_nvme(struct apple_nvme_queue *q)static unsigned int apple_nvme_queue_depth (struct apple_nvme_queue *q) { -if (q->is_adminq) +struct apple_nvme *anv =queue_to_apple_nvme (q); + +if (q->is_adminq && anv->hw->has_lsq_nvmmu)return APPLE_NVME_AQ_DEPTH ; -return APPLE_ANS_MAX_QUEUE_DEPTH ; +return anv->hw->max_queue_depth; }static void apple_nvme_rtkit_crashed (void *cookie)
@@ -297,7 +307,28 @@ static void apple_nvmmu_inval(struct apple_nvme_queue *q, unsigned int tag) "NVMMU TCB invalidation failed\n"); } -static void apple_nvme_submit_cmd (struct apple_nvme_queue *q, +static void apple_nvme_submit_cmd_t8015 (struct apple_nvme_queue *q, +struct nvme_command *cmd) +{ +struct apple_nvme *anv =queue_to_apple_nvme (q); + +spin_lock_irq (&anv->lock); + +if (q->is_adminq) +memcpy (&q->sqes[q->sq_tail], cmd,sizeof (*cmd)); +else +memcpy ((void *)q->sqes + (q->sq_tail <<APPLE_NVME_IOSQES ), + cmd,sizeof (*cmd)); + +if (++q->sq_tail == anv->hw->max_queue_depth) + q->sq_tail =0 ; + +writel (q->sq_tail, q->sq_db); +spin_unlock_irq (&anv->lock); +} + + +static void apple_nvme_submit_cmd_t8103 (struct apple_nvme_queue *q,struct nvme_command *cmd) {struct apple_nvme *anv =queue_to_apple_nvme (q);
@@ -609,7 +640,8 @@ static inline void apple_nvme_handle_cqe(struct apple_nvme_queue *q,__u16 command_id =READ_ONCE (cqe->command_id);struct request *req; -apple_nvmmu_inval (q, command_id); +if (anv->hw->has_lsq_nvmmu) +apple_nvmmu_inval (q, command_id); req =nvme_find_rq (apple_nvme_queue_tagset (anv, q), command_id);if (unlikely (!req)) {
@@ -703,7 +735,7 @@ static int apple_nvme_create_cq(struct apple_nvme *anv) c.create_cq.opcode = nvme_admin_create_cq; c.create_cq.prp1 =cpu_to_le64 (anv->ioq.cq_dma_addr); c.create_cq.cqid =cpu_to_le16 (1 ); - c.create_cq.qsize =cpu_to_le16 (APPLE_ANS_MAX_QUEUE_DEPTH -1 ); + c.create_cq.qsize =cpu_to_le16 (anv->hw->max_queue_depth -1 ); c.create_cq.cq_flags =cpu_to_le16 (NVME_QUEUE_PHYS_CONTIG |NVME_CQ_IRQ_ENABLED ); c.create_cq.irq_vector =cpu_to_le16 (0 );
@@ -731,7 +763,7 @@ static int apple_nvme_create_sq(struct apple_nvme *anv) c.create_sq.opcode = nvme_admin_create_sq; c.create_sq.prp1 =cpu_to_le64 (anv->ioq.sq_dma_addr); c.create_sq.sqid =cpu_to_le16 (1 ); - c.create_sq.qsize =cpu_to_le16 (APPLE_ANS_MAX_QUEUE_DEPTH -1 ); + c.create_sq.qsize =cpu_to_le16 (anv->hw->max_queue_depth -1 ); c.create_sq.sq_flags =cpu_to_le16 (NVME_QUEUE_PHYS_CONTIG ); c.create_sq.cqid =cpu_to_le16 (1 );
@@ -783,7 +815,12 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx, }nvme_start_request (req); -apple_nvme_submit_cmd (q, cmnd); + +if (anv->hw->has_lsq_nvmmu) +apple_nvme_submit_cmd_t8103 (q, cmnd); +else +apple_nvme_submit_cmd_t8015 (q, cmnd); +return BLK_STS_OK ; out_free_cmd:
@@ -987,11 +1024,13 @@ static const struct blk_mq_ops apple_nvme_mq_ops = {static void apple_nvme_init_queue (struct apple_nvme_queue *q) {unsigned int depth =apple_nvme_queue_depth (q); +struct apple_nvme *anv =queue_to_apple_nvme (q); q->cq_head =0 ; q->cq_phase =1 ; -memset (q->tcbs,0 , -APPLE_ANS_MAX_QUEUE_DEPTH *sizeof (struct apple_nvmmu_tcb )); +if (anv->hw->has_lsq_nvmmu) +memset (q->tcbs,0 , anv->hw->max_queue_depth + *sizeof (struct apple_nvmmu_tcb ));memset (q->cqes,0 , depth *sizeof (struct nvme_completion ));apple_nvme_enable_queue (q); }
@@ -1073,49 +1112,55 @@ static void apple_nvme_reset_work(struct work_struct *work)dma_set_max_seg_size (anv->dev,0xffffffff ); -/* -* Enable NVMMU and linear submission queues. -* While we could keep those disabled and pretend this is slightly -* more common NVMe controller we'd still need some quirks (e.g. -* sq entries will be 128 bytes) and Apple might drop support for -* that mode in the future. -*/ -writel (APPLE_ANS_LINEAR_SQ_EN , - anv->mmio_nvme +APPLE_ANS_LINEAR_SQ_CTRL ); +if (anv->hw->has_lsq_nvmmu) { +/* +* Enable NVMMU and linear submission queues which is required +* since T6000. +*/ +writel (APPLE_ANS_LINEAR_SQ_EN , + anv->mmio_nvme +APPLE_ANS_LINEAR_SQ_CTRL ); -/* Allow as many pending command as possible for both queues */ -writel (APPLE_ANS_MAX_QUEUE_DEPTH | (APPLE_ANS_MAX_QUEUE_DEPTH <<16 ), - anv->mmio_nvme +APPLE_ANS_MAX_PEND_CMDS_CTRL ); +/* Allow as many pending command as possible for both queues */ +writel (anv->hw->max_queue_depth + | (anv->hw->max_queue_depth <<16 ), anv->mmio_nvme + +APPLE_ANS_MAX_PEND_CMDS_CTRL ); -/* Setup the NVMMU for the maximum admin and IO queue depth */ -writel (APPLE_ANS_MAX_QUEUE_DEPTH -1 , - anv->mmio_nvme +APPLE_NVMMU_NUM_TCBS ); +/* Setup the NVMMU for the maximum admin and IO queue depth */ +writel (anv->hw->max_queue_depth -1 , + anv->mmio_nvme +APPLE_NVMMU_NUM_TCBS ); -/* -* This is probably a chicken bit: without it all commands where any PRP -* is set to zero (including those that don't use that field) fail and -* the co-processor complains about "completed with err BAD_CMD-" or -* a "NULL_PRP_PTR_ERR" in the syslog -*/ -writel (readl (anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ) & - ~APPLE_ANS_PRP_NULL_CHECK , - anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ); +/* +* This is probably a chicken bit: without it all commands +* where any PRP is set to zero (including those that don't use +* that field) fail and the co-processor complains about +* "completed with err BAD_CMD-" or a "NULL_PRP_PTR_ERR" in the +* syslog +*/ +writel (readl (anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ) & + ~APPLE_ANS_PRP_NULL_CHECK , + anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ); + }/* Setup the admin queue */ - aqa =APPLE_NVME_AQ_DEPTH -1 ; +if (anv->hw->has_lsq_nvmmu) + aqa =APPLE_NVME_AQ_DEPTH -1 ; +else + aqa = anv->hw->max_queue_depth -1 ; aqa |= aqa <<16 ;writel (aqa, anv->mmio_nvme +NVME_REG_AQA );writeq (anv->adminq.sq_dma_addr, anv->mmio_nvme +NVME_REG_ASQ );writeq (anv->adminq.cq_dma_addr, anv->mmio_nvme +NVME_REG_ACQ ); -/* Setup NVMMU for both queues */ -writeq (anv->adminq.tcb_dma_addr, - anv->mmio_nvme +APPLE_NVMMU_ASQ_TCB_BASE ); -writeq (anv->ioq.tcb_dma_addr, - anv->mmio_nvme +APPLE_NVMMU_IOSQ_TCB_BASE ); +if (anv->hw->has_lsq_nvmmu) { +/* Setup NVMMU for both queues */ +writeq (anv->adminq.tcb_dma_addr, + anv->mmio_nvme +APPLE_NVMMU_ASQ_TCB_BASE ); +writeq (anv->ioq.tcb_dma_addr, + anv->mmio_nvme +APPLE_NVMMU_IOSQ_TCB_BASE ); + } anv->ctrl.sqsize = -APPLE_ANS_MAX_QUEUE_DEPTH -1 ;/* 0's based queue depth */ + anv->hw->max_queue_depth -1 ;/* 0's based queue depth */ anv->ctrl.cap =readq (anv->mmio_nvme +NVME_REG_CAP );dev_dbg (anv->dev,"Enabling controller now" );
@@ -1283,8 +1328,9 @@ static int apple_nvme_alloc_tagsets(struct apple_nvme *anv)* both queues. The admin queue gets the first APPLE_NVME_AQ_DEPTH which * must be marked as reserved in the IO queue. */ - anv->tagset.reserved_tags =APPLE_NVME_AQ_DEPTH ; - anv->tagset.queue_depth =APPLE_ANS_MAX_QUEUE_DEPTH -1 ; +if (anv->hw->has_lsq_nvmmu) + anv->tagset.reserved_tags =APPLE_NVME_AQ_DEPTH ; + anv->tagset.queue_depth = anv->hw->max_queue_depth -1 ; anv->tagset.timeout =NVME_IO_TIMEOUT ; anv->tagset.numa_node =NUMA_NO_NODE ; anv->tagset.cmd_size =sizeof (struct apple_nvme_iod );
@@ -1309,6 +1355,7 @@ static int apple_nvme_queue_alloc(struct apple_nvme *anv, struct apple_nvme_queue *q) {unsigned int depth =apple_nvme_queue_depth (q); +size_t iosq_size; q->cqes = dmam_alloc_coherent(anv->dev, depth * sizeof(struct nvme_completion),
@@ -1316,22 +1363,28 @@ static int apple_nvme_queue_alloc(struct apple_nvme *anv,if (!q->cqes)return -ENOMEM ; - q->sqes =dmam_alloc_coherent (anv->dev, - depth *sizeof (struct nvme_command ), +if (anv->hw->has_lsq_nvmmu) + iosq_size = depth *sizeof (struct nvme_command ); +else + iosq_size = depth <<APPLE_NVME_IOSQES ; + + q->sqes =dmam_alloc_coherent (anv->dev, iosq_size, &q->sq_dma_addr,GFP_KERNEL );if (!q->sqes)return -ENOMEM ; -/* -* We need the maximum queue depth here because the NVMMU only has a -* single depth configuration shared between both queues. -*/ - q->tcbs =dmam_alloc_coherent (anv->dev, -APPLE_ANS_MAX_QUEUE_DEPTH * -sizeof (struct apple_nvmmu_tcb ), - &q->tcb_dma_addr,GFP_KERNEL ); -if (!q->tcbs) -return -ENOMEM ; +if (anv->hw->has_lsq_nvmmu) { +/* +* We need the maximum queue depth here because the NVMMU only +* has a single depth configuration shared between both queues. +*/ + q->tcbs =dmam_alloc_coherent (anv->dev, + anv->hw->max_queue_depth * +sizeof (struct apple_nvmmu_tcb ), + &q->tcb_dma_addr,GFP_KERNEL ); +if (!q->tcbs) +return -ENOMEM ; + }/* * initialize phase to make sure the allocated and empty memory
@@ -1415,6 +1468,12 @@ static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev) anv->adminq.is_adminq = true;platform_set_drvdata (pdev, anv); + anv->hw =of_device_get_match_data (&pdev->dev); +if (!anv->hw) { + ret = -ENODEV ; + goto put_dev; + } + ret =apple_nvme_attach_genpd (anv);if (ret <0 ) {dev_err_probe (dev, ret,"Failed to attach power domains" );
@@ -1446,10 +1505,17 @@ static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev) goto put_dev; } - anv->adminq.sq_db = anv->mmio_nvme +APPLE_ANS_LINEAR_ASQ_DB ; - anv->adminq.cq_db = anv->mmio_nvme +APPLE_ANS_ACQ_DB ; - anv->ioq.sq_db = anv->mmio_nvme +APPLE_ANS_LINEAR_IOSQ_DB ; - anv->ioq.cq_db = anv->mmio_nvme +APPLE_ANS_IOCQ_DB ; +if (anv->hw->has_lsq_nvmmu) { + anv->adminq.sq_db = anv->mmio_nvme +APPLE_ANS_LINEAR_ASQ_DB ; + anv->adminq.cq_db = anv->mmio_nvme +APPLE_ANS_ACQ_DB ; + anv->ioq.sq_db = anv->mmio_nvme +APPLE_ANS_LINEAR_IOSQ_DB ; + anv->ioq.cq_db = anv->mmio_nvme +APPLE_ANS_IOCQ_DB ; + }else { + anv->adminq.sq_db = anv->mmio_nvme +NVME_REG_DBS ; + anv->adminq.cq_db = anv->mmio_nvme +APPLE_ANS_ACQ_DB ; + anv->ioq.sq_db = anv->mmio_nvme +NVME_REG_DBS +8 ; + anv->ioq.cq_db = anv->mmio_nvme +APPLE_ANS_IOCQ_DB ; + } anv->sart =devm_apple_sart_get (dev);if (IS_ERR (anv->sart)) {
@@ -1626,8 +1692,19 @@ static int apple_nvme_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(apple_nvme_pm_ops, apple_nvme_suspend, apple_nvme_resume); +static const struct apple_nvme_hw apple_nvme_t8015_hw = { + .has_lsq_nvmmu = false, + .max_queue_depth =16 , +}; + +static const struct apple_nvme_hw apple_nvme_t8103_hw = { + .has_lsq_nvmmu = true, + .max_queue_depth =64 , +}; +static const struct of_device_id apple_nvme_of_match[] = { - { .compatible ="apple,nvme-ans2" }, + { .compatible ="apple,t8015-nvme-ans2" , .data = &apple_nvme_t8015_hw }, + { .compatible ="apple,nvme-ans2" , .data = &apple_nvme_t8103_hw }, {}, };MODULE_DEVICE_TABLE (of, apple_nvme_of_match);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1162/1424 nvme-apple: Drop the PRP null check chicken bit
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Peter <[email protected]>
[ Upstream commit 8ce883fd068b7ba9ab493cd3ecca3a7ea868c375 ]
Now that we program the DMA direction correctly the NULL check that used to make commands fail passes. Another side effect of this bit was that non-align buffers on the admin queue were silently allowed and that's been fixed now as well and we this don't need this chicken bit anymore. More importantly, starting with the firmware installed with macOS 15, which is required for M4 but can also be installed on the previous SoCs, the controller no longer exposes this control register and any access SErrors instead. Just drop the write entirely.
--- drivers/nvme/host/apple.c | 14 -------------- 1 file changed, 14 deletions(-)
drivers/nvme/host/apple.c +0 -14
@@ -47,9 +47,6 @@#define APPLE_ANS_BOOT_STATUS 0x1300#define APPLE_ANS_BOOT_STATUS_OK 0xde71ce55 -#define APPLE_ANS_UNKNOWN_CTRL 0x24008 -#define APPLE_ANS_PRP_NULL_CHECK BIT(11) -#define APPLE_ANS_LINEAR_SQ_CTRL 0x24908#define APPLE_ANS_LINEAR_SQ_EN BIT(0)
@@ -1128,17 +1125,6 @@ static void apple_nvme_reset_work(struct work_struct *work)/* Setup the NVMMU for the maximum admin and IO queue depth */ writel (anv->hw->max_queue_depth -1 , anv->mmio_nvme +APPLE_NVMMU_NUM_TCBS ); - -/* -* This is probably a chicken bit: without it all commands -* where any PRP is set to zero (including those that don't use -* that field) fail and the co-processor complains about -* "completed with err BAD_CMD-" or a "NULL_PRP_PTR_ERR" in the -* syslog -*/ -writel (readl (anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ) & - ~APPLE_ANS_PRP_NULL_CHECK , - anv->mmio_nvme +APPLE_ANS_UNKNOWN_CTRL ); }/* Setup the admin queue */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1163/1424 nvmet: fix NULL pointer dereference in nvmet_execute_identify_ns_zns()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit f594863967d87b7fcbff6e724d51135fd701a13d ]
When a host issues an Identify command with CNS 05h (I/O Command Set specific Identify Namespace) and CSI 02h (ZNS) targeting a file-backed namespace, nvmet_execute_identify_ns_zns() calls bdev_is_zoned() on req->ns->bdev. A file-backed namespace has no block device, so req->ns->bdev is NULL and bdev_is_zoned() dereferences it, oopsing.
The I/O command set is selected by the host-supplied CSI field and the command is routed here whenever CONFIG_BLK_DEV_ZONED is enabled, independent of the namespace backing type, so any file-backed namespace is exposed.
Reject the command with Invalid Field when the namespace is not backed by a block device.
--- drivers/nvme/target/zns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/target/zns.c +1 -1
@@ -124,7 +124,7 @@ void nvmet_execute_identify_ns_zns(struct nvmet_req *req)mutex_unlock (&req->ns->subsys->lock); } -if (!bdev_is_zoned (req->ns->bdev)) { +if (!req->ns->bdev || !bdev_is_zoned (req->ns->bdev)) { status =NVME_SC_INVALID_FIELD |NVME_STATUS_DNR ; req->error_loc = offsetof(struct nvme_identify , nsid); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1164/1424 nvme/ioctl: check SUBMIT_IO with nvme_cmd_allowed()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <[email protected]>
[ Upstream commit b53d495c7f0db46b6748b5ade48371a10dd5d3bc ]
Unlike IO_CMD / IO64_CMD, NVME_IOCTL_SUBMIT_IO never calls nvme_cmd_allowed(). Unprivileged callers can thus issue I/O on a partition device or write through a read-only file descriptor.
Pass flags and open_for_write through and reject disallowed commands with -EACCES.
Stable-dep-of: 1161be71d1ec ("nvme: reject passthrough of driver-managed Set Features")
--- drivers/nvme/host/ioctl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/nvme/host/ioctl.c +6 -2
@@ -269,7 +269,8 @@ static int nvme_submit_user_cmd(struct request_queue *q,return ret; } -static int nvme_submit_io (struct nvme_ns *ns,struct nvme_user_io __user *uio) +static int nvme_submit_io (struct nvme_ns *ns,struct nvme_user_io __user *uio, +unsigned int flags,bool open_for_write) {struct nvme_user_io io;struct nvme_command c;
@@ -327,6 +328,9 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) c.rw.apptag =cpu_to_le16 (io.apptag); c.rw.appmask =cpu_to_le16 (io.appmask); +if (!nvme_cmd_allowed (ns, &c, flags, open_for_write)) +return -EACCES ; +return nvme_submit_user_cmd (ns->queue, &c, io.addr, length, metadata, meta_len,lower_32_bits (io.slba),NULL ,0 ,0 ); }
@@ -702,7 +706,7 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,case NVME_IOCTL_SUBMIT_IO32 :#endif case NVME_IOCTL_SUBMIT_IO : -return nvme_submit_io (ns, argp); +return nvme_submit_io (ns, argp, flags, open_for_write);case NVME_IOCTL_IO64_CMD_VEC : flags |=NVME_IOCTL_VEC ; fallthrough;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1165/1424 nvme: reject passthrough of driver-managed Set Features
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Shi <[email protected]>
[ Upstream commit 1161be71d1ecf7dc785382114c71afed0349531e ]
Since commit b58da2d270db ("nvme: update keep alive interval when kato is modified"), a Set Features (KATO) passthrough command lets userspace start keep-alive on any transport. nvme_keep_alive_work() allocates with BLK_MQ_REQ_RESERVED, but nvme_alloc_admin_tag_set() reserves admin tags only for fabrics, so on other transports the allocation trips WARN_ON_ONCE() in blk_mq_get_tag() and fails:
nvme nvme0: keep-alive failed: -11
Several Set Features change controller state the driver manages itself and cannot react to when set behind its back. Reject these in nvme_admin_cmd_allowed():
- KATO on non-fabrics (keep-alive is only armed for fabrics; on PCIe it has no reserved tag and harms idle power states)
- Host Behavior Support, Host Memory Buffer, Number of Queues, and Autonomous Power State Transition (all driver-managed)
Keep Alive on fabrics is unchanged; I/O commands are unaffected as the check is confined to the admin path (ns == NULL).
Found by FuzzNvme.
--- drivers/nvme/host/ioctl.c | 111 ++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 39 deletions(-)
drivers/nvme/host/ioctl.c +72 -39
@@ -14,45 +14,54 @@ enum { NVME_IOCTL_PARTITION = (1 << 1), }; -static bool nvme_cmd_allowed (struct nvme_ns *ns,struct nvme_command *c, -unsigned int flags,bool open_for_write) +static bool nvme_admin_cmd_allowed (struct nvme_ctrl *ctrl, +struct nvme_command *c) { -u32 effects; - -/* -* Do not allow unprivileged passthrough on partitions, as that allows an -* escape from the containment of the partition. -*/ -if (flags &NVME_IOCTL_PARTITION ) - goto admin; - -/* -* Do not allow unprivileged processes to send vendor specific or fabrics -* commands as we can't be sure about their effects. -*/ -if (c->common.opcode >= nvme_cmd_vendor_start || - c->common.opcode == nvme_fabrics_command) - goto admin; -/* * Do not allow unprivileged passthrough of admin commands except * for a subset of identify commands that contain information required * to form proper I/O commands in userspace and do not expose any * potentially sensitive information. */ -if (!ns) { -if (c->common.opcode == nvme_admin_identify) { -switch (c->identify.cns) { -case NVME_ID_CNS_NS : -case NVME_ID_CNS_CS_NS : -case NVME_ID_CNS_NS_CS_INDEP : -case NVME_ID_CNS_CS_CTRL : -case NVME_ID_CNS_CTRL : -return true; - } +switch (c->common.opcode) { +case nvme_admin_identify: +switch (c->identify.cns) { +case NVME_ID_CNS_NS : +case NVME_ID_CNS_CS_NS : +case NVME_ID_CNS_NS_CS_INDEP : +case NVME_ID_CNS_CS_CTRL : +case NVME_ID_CNS_CTRL : +return true; } - goto admin; +break ; +case nvme_admin_set_features: +/* +* Reject Set Features that change controller state the driver +* manages itself; setting them behind the driver's back from +* userspace leaves it unable to react correctly. Keep Alive is +* only armed for fabrics - on other transports it has no +* reserved tag and harms idle power states. +*/ +switch (le32_to_cpu (c->features.fid) &0xff ) { +case NVME_FEAT_KATO : +if (ctrl->ops->flags &NVME_F_FABRICS ) +break ; + fallthrough; +case NVME_FEAT_HOST_BEHAVIOR : +case NVME_FEAT_HOST_MEM_BUF : +case NVME_FEAT_NUM_QUEUES : +case NVME_FEAT_AUTO_PST : +return false; + } +break ; } +return capable (CAP_SYS_ADMIN ); +} + +static bool nvme_ns_cmd_allowed (struct nvme_ns *ns,struct nvme_command *c, +bool open_for_write) +{ +u32 effects;/* * Check if the controller provides a Commands Supported and Effects log
@@ -61,7 +70,7 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,*/ effects =nvme_command_effects (ns->ctrl, ns, c->common.opcode);if (!(effects &NVME_CMD_EFFECTS_CSUPP )) - goto admin; +return capable (CAP_SYS_ADMIN );/* * Don't allow passthrough for command that have intrusive (or unknown)
@@ -70,7 +79,7 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,if (effects & ~(NVME_CMD_EFFECTS_CSUPP |NVME_CMD_EFFECTS_LBCC |NVME_CMD_EFFECTS_UUID_SEL |NVME_CMD_EFFECTS_SCOPE_MASK )) - goto admin; +return capable (CAP_SYS_ADMIN );/* * Only allow I/O commands that transfer data to the controller or that
@@ -79,11 +88,34 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,*/ if ((nvme_is_write (c) || (effects &NVME_CMD_EFFECTS_LBCC )) && !open_for_write) - goto admin; +return capable (CAP_SYS_ADMIN );return true; -admin: -return capable (CAP_SYS_ADMIN ); +} + +static bool nvme_cmd_allowed (struct nvme_ctrl *ctrl,struct nvme_ns *ns, +struct nvme_command *c,unsigned int flags, +bool open_for_write) +{ +/* +* Do not allow unprivileged passthrough on partitions, as that +* allows an escape from the containment of the partition. +*/ +if (flags &NVME_IOCTL_PARTITION ) +return capable (CAP_SYS_ADMIN ); + +/* +* Do not allow unprivileged processes to send vendor specific or +* fabrics commands as we can't be sure about their effects. +*/ +if (c->common.opcode >= nvme_cmd_vendor_start || + c->common.opcode == nvme_fabrics_command) +return capable (CAP_SYS_ADMIN ); + +if (!ns) +return nvme_admin_cmd_allowed (ctrl, c); + +return nvme_ns_cmd_allowed (ns, c, open_for_write); }/*
@@ -328,7 +360,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio, c.rw.apptag =cpu_to_le16 (io.apptag); c.rw.appmask =cpu_to_le16 (io.appmask); -if (!nvme_cmd_allowed (ns, &c, flags, open_for_write)) +if (!nvme_cmd_allowed (ns->ctrl, ns, &c, flags, open_for_write))return -EACCES ; return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata,
@@ -378,7 +410,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 =cpu_to_le32 (cmd.cdw14); c.common.cdw15 =cpu_to_le32 (cmd.cdw15); -if (!nvme_cmd_allowed (ns, &c,0 , open_for_write)) +if (!nvme_cmd_allowed (ctrl, ns, &c,0 , open_for_write))return -EACCES ;if (cmd.timeout_ms)
@@ -425,7 +457,7 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 =cpu_to_le32 (cmd.cdw14); c.common.cdw15 =cpu_to_le32 (cmd.cdw15); -if (!nvme_cmd_allowed (ns, &c, flags, open_for_write)) +if (!nvme_cmd_allowed (ctrl, ns, &c, flags, open_for_write))return -EACCES ;if (cmd.timeout_ms)
@@ -570,6 +602,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,struct nvme_uring_cmd_pdu *pdu =nvme_uring_cmd_pdu (ioucmd);const struct nvme_uring_cmd *cmd =io_uring_sqe_cmd (ioucmd->sqe);struct request_queue *q = ns ? ns->queue : ctrl->admin_q; +bool open_for_write = ioucmd->file->f_mode &FMODE_WRITE ;struct nvme_uring_data d;struct nvme_command c;struct request *req;
@@ -599,7 +632,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 =cpu_to_le32 (READ_ONCE (cmd->cdw14)); c.common.cdw15 =cpu_to_le32 (READ_ONCE (cmd->cdw15)); -if (!nvme_cmd_allowed (ns, &c,0 , ioucmd->file->f_mode &FMODE_WRITE )) +if (!nvme_cmd_allowed (ctrl, ns, &c,0 , open_for_write))return -EACCES ; d.metadata =READ_ONCE (cmd->metadata);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1166/1424 nfc: llcp: avoid userspace overflow on invalid optlen
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 99985bfa8336fadcc69190ba2dcbd5386af3d661 ]
nfc_llcp_getsockopt() casts optval to (u32 __user *) for put_user(), so the kernel always stores 4 bytes regardless of the caller-supplied optlen. The existing min_t(u32, len, sizeof(u32)) only clamps the length reported back to userspace; it does not constrain the store. A call with optlen < 4 therefore writes past the user buffer, violating the getsockopt(2) contract for all five supported optnames.
Reject any call with optlen < sizeof(u32) up front. 'len' is int, so a plain size comparison would promote a negative optlen to size_t and slip past the check; an explicit 'len < 0' test is added first to catch negative values before the size compare.
--- net/nfc/llcp_sock.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/nfc/llcp_sock.c +6 -0
@@ -319,6 +319,12 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,if (get_user (len, optlen))return -EFAULT ; +if (len <0 ) +return -EINVAL ; + +if (len <sizeof (u32)) +return -EINVAL ; + local = llcp_sock->local;if (!local)return -ENODEV ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1167/1424 nfc: llcp: read llcp_sock->local under the socket lock in getsockopt
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 36812527052c5bfb1ec6c1e292d67a5bf76b750f ]
nfc_llcp_getsockopt() read llcp_sock->local before lock_sock(sk) and then dereferenced the cached pointer inside the locked region. llcp_sock_bind() assigns and clears llcp_sock->local under the same socket lock, dropping the last reference on its error path. A getsockopt() racing an in-flight bind() can observe the pointer, block on lock_sock(), and then dereference a freed nfc_llcp_local once bind() has unwound.
Move the llcp_sock->local read and the NULL check inside the lock_sock(sk) region so bind() cannot mutate or free the pointer between the load and the use.
--- net/nfc/llcp_sock.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
net/nfc/llcp_sock.c +6 -4
@@ -325,14 +325,16 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,if (len <sizeof (u32))return -EINVAL ; - local = llcp_sock->local; -if (!local) -return -ENODEV ; - len =min_t (u32, len,sizeof (u32));lock_sock (sk); + local = llcp_sock->local; +if (!local) { +release_sock (sk); +return -ENODEV ; + } +switch (optname) {case NFC_LLCP_RW : rw = llcp_sock->rw >LLCP_MAX_RW ? local->rw : llcp_sock->rw;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1168/1424 nfc: nci: fix double completion race in nci_data_exchange_complete
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenghang Xiao <[email protected]>
[ Upstream commit 8265a626cc14a48e46e6dc8c47667e72b4232ac2 ]
nci_close_device() and nci_rx_work can both call nci_data_exchange_complete() concurrently. After commit 4527025d440ce8 ("nfc: nci: fix circular locking dependency in nci_close_device") moved flush_workqueue(ndev->rx_wq) after mutex_unlock(&ndev->req_lock), rx_work is no longer serialized with the explicit completion call in the close path. Both callers read the non-NULL callback pointer and invoke rawsock_data_exchange_complete(), which calls sock_put() -- but only one sock_hold() was taken, so the second sock_put() underflows the refcount and frees the socket while it is still in use.
Replace the bare clear_bit(NCI_DATA_EXCHANGE) with test_and_clear_bit() so that only the first caller proceeds to invoke the callback.
--- net/nfc/nci/data.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/nfc/nci/data.c +5 -5
@@ -46,11 +46,11 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,del_timer_sync (&ndev->data_timer);clear_bit (NCI_DATA_EXCHANGE_TO , &ndev->flags); -/* Mark the exchange as done before calling the callback. -* The callback (e.g. rawsock_data_exchange_complete) may -* want to immediately queue another data exchange. -*/ -clear_bit (NCI_DATA_EXCHANGE , &ndev->flags); +/* Claim completion atomically -- both close and rx_work may race here */ +if (!test_and_clear_bit (NCI_DATA_EXCHANGE , &ndev->flags)) { +kfree_skb (skb); +return ; + }if (cb) {/* forward skb to nfc core */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1169/1424 nfc: llcp: bound SNL TLV parsing to the skb and add length checks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
[ Upstream commit f4c7f37f0ab990952539dc68d931d65c3657600a ]
nfc_llcp_recv_snl() walked the SNL TLV list using a u16 offset/length pair derived from skb->len, without bounding reads to the actual skb data. Three problems followed:
- For a short frame (skb->len < LLCP_HEADER_SIZE), tlv_len underflowed.
- The per-TLV header (type, length) was read without checking that two bytes remained.
- A declared TLV length could run past the end of the buffer, and an SDREQ with length == 0 made "service_name_len = length - 1" underflow (size_t), driving an out-of-bounds read in the following strncmp() / nfc_llcp_sock_from_sn(). The SDRES case likewise read tlv[2]/tlv[3] without a length check.
A nearby NFC device can reach this without authentication; LLCP link activation happens automatically after NFC-DEP.
Walk the TLV list by pointer, bounded by skb_tail_pointer() over the linear skb data, and validate each TLV declared length before use. Add explicit length checks for SDREQ (>= 1) and SDRES (exactly 2).
Found by 0sec automated security-research tooling (https://0sec.ai).
--- net/nfc/llcp_core.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
net/nfc/llcp_core.c +21 -8
@@ -1286,10 +1286,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, {struct nfc_llcp_sock *llcp_sock;u8 dsap, ssap, type, length, tid, sap; -const u8 *tlv; -u16 tlv_len, offset; +const u8 *tlv, *tlv_end;const char *service_name; -size_t service_name_len; +int service_name_len;struct nfc_llcp_sdp_tlv *sdp;HLIST_HEAD (llc_sdres_list);size_t sdres_tlvs_len;
@@ -1305,22 +1304,34 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, return; } + /* + * Walk the SNL TLV list in the linear part of the skb only, + * bounded by skb_tail_pointer(). Each TLV needs a two-byte + * header (type, length) and its declared length must fit before + * the end; this also keeps the walk safe for very short frames. + */ tlv = &skb->data[LLCP_HEADER_SIZE]; - tlv_len = skb->len - LLCP_HEADER_SIZE; - offset = 0; + tlv_end = skb_tail_pointer(skb); sdres_tlvs_len = 0; - while (offset < tlv_len) { + while (tlv + 2 < tlv_end) { type = tlv[0]; length = tlv[1]; + if (tlv + 2 + length > tlv_end) + break; + switch (type) { case LLCP_TLV_SDREQ: + if (length < 1) + break; + tid = tlv[2]; service_name = (char *) &tlv[3]; service_name_len = length - 1; - pr_debug("Looking for %.16s\n", service_name); + pr_debug("Looking for %.*s\n", service_name_len, + service_name); if (service_name_len == strlen("urn:nfc:sn:sdp") && !strncmp(service_name, "urn:nfc:sn:sdp",
@@ -1380,6 +1391,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,break ;case LLCP_TLV_SDRES : +if (length !=2 ) +break ; +mutex_lock (&local->sdreq_lock);pr_debug ("LLCP_TLV_SDRES: searching tid %d\n" , tlv[2 ]);
@@ -1408,7 +1422,6 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,break ; } - offset += length +2 ; tlv += length +2 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1170/1424 nfc: pn533: hold a reference to the request skb during send_frame
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinhao Hu <[email protected]>
[ Upstream commit 47792358a624ea066455ef86b744159928cd7716 ]
__pn533_send_async() publishes the command and then calls dev->phy_ops->send_frame(). Once dev->cmd is set, an incoming frame can be matched to this command: the I2C threaded IRQ runs pn533_recv_frame(), which queues cmd_complete_work, and pn533_send_async_complete() frees cmd->req with consume_skb().
On the I2C transport, pn533_i2c_send_frame() still dereferences the same skb after i2c_master_send() returns, so a completion that races the send can free the skb while the transport is still using it.
The request skb is owned by the command object and may be freed by command completion at any time after dev->cmd is published, so the transport send path must not assume it stays alive. Hold a temporary reference to the request skb across the send_frame() call so the transport always sees a live skb even if completion races the send. Add a pn533_send_cmd_frame() helper and use it from all three send paths.
--- drivers/nfc/pn533/pn533.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/nfc/pn533/pn533.c +15 -6
@@ -434,6 +434,18 @@ static int pn533_send_async_complete(struct pn533 *dev)return rc; } +static int pn533_send_cmd_frame (struct pn533 *dev,struct pn533_cmd *cmd) +{ +struct sk_buff *req = cmd->req; +int rc; + +skb_get (req); + dev->cmd = cmd; + rc = dev->phy_ops->send_frame (dev, req); +dev_kfree_skb (req); +return rc; +} + static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, struct sk_buff *req, pn533_send_async_complete_t complete_cb,
@@ -458,8 +470,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,mutex_lock (&dev->cmd_lock);if (!dev->cmd_pending) { - dev->cmd = cmd; - rc = dev->phy_ops->send_frame (dev, req); + rc =pn533_send_cmd_frame (dev, cmd);if (rc) { dev->cmd =NULL ; goto error;
@@ -529,8 +540,7 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,pn533_build_cmd_frame (dev, cmd_code, req); - dev->cmd = cmd; - rc = dev->phy_ops->send_frame (dev, req); + rc =pn533_send_cmd_frame (dev, cmd);if (rc <0 ) { dev->cmd =NULL ;kfree (cmd);
@@ -569,8 +579,7 @@ static void pn533_wq_cmd(struct work_struct *work)mutex_unlock (&dev->cmd_lock); - dev->cmd = cmd; - rc = dev->phy_ops->send_frame (dev, cmd->req); + rc =pn533_send_cmd_frame (dev, cmd);if (rc <0 ) { dev->cmd =NULL ;dev_kfree_skb (cmd->req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1171/1424 nfc: digital: Do not dump a NULL response in command completion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 1c7dd70c0adfa58fd66b5cbd03efb747ad6d8d8d ]
digital_wq_cmd_complete() dumps the response data whenever cmd->resp is not an error pointer. However, a driver can legitimately complete a command with no response skb at all.
digital_tg_send_psl_res() is the only caller that passes timeout=0, meaning no response is expected once the command has been transmitted. On that path trf7970a completes the command with
trf->rx_skb = ERR_PTR(0);
which evaluates to NULL. IS_ERR(NULL) is false, so the NULL response passes the !IS_ERR() check and cmd->resp->data and cmd->resp->len are dereferenced whenever the debug print site is enabled. The driver guards its own dump with "trf->rx_skb && !IS_ERR(trf->rx_skb)"; the digital layer is missing the NULL half of that test.
Use IS_ERR_OR_NULL() so that NULL responses are skipped as well. The callback on that path, digital_tg_send_psl_res_complete(), never dereferences resp and dev_kfree_skb() accepts NULL, so only the debug dump needs fixing.
--- net/nfc/digital_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/nfc/digital_core.c +1 -1
@@ -127,7 +127,7 @@ static void digital_wq_cmd_complete(struct work_struct *work)mutex_unlock (&ddev->cmd_lock); -if (!IS_ERR (cmd->resp)) +if (!IS_ERR_OR_NULL (cmd->resp))print_hex_dump_debug ("DIGITAL RX: " ,DUMP_PREFIX_NONE ,16 ,1 , cmd->resp->data, cmd->resp->len, false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1172/1424 nfc: nci: fix use of uninitialized memory in CORE_INIT_RSP parsing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit d56575a2595ee1f597f39e8a1cfb67ed3501678d ]
nci_core_init_rsp_packet_v1() and nci_core_init_rsp_packet_v2() parse the CORE_INIT_RSP packet without validating that the skb contains enough data. A malformed response (e.g. injected via virtual_ncidev) can declare a large num_supported_rf_interfaces while providing insufficient data, causing reads of uninitialized slab memory. This is later used in nci_init_complete_req(), triggering a KMSAN uninit-value warning.
Add skb length checks before accessing packet fields:
- Validate the skb has at least 1 byte for the status field.
- Validate the skb can hold the fixed-size header before parsing.
- In v2, bounds-check each variable-length rf_interface entry and its extension parameters within the parsing loop.
- In v1, verify the skb is large enough for both the variable-length rf_interfaces array and the trailing rsp_2 structure.
--- net/nfc/nci/rsp.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
net/nfc/nci/rsp.c +38 -3
@@ -50,11 +50,27 @@ static u8 nci_core_init_rsp_packet_v1(struct nci_dev *ndev,const struct nci_core_init_rsp_1 *rsp_1 = (void *)skb->data;const struct nci_core_init_rsp_2 *rsp_2; +/* Ensure that the status field can be accessed. */ +if (skb_headlen (skb) <1 ) +return NCI_STATUS_SYNTAX_ERROR ; +pr_debug ("status 0x%x\n" , rsp_1->status);if (rsp_1->status !=NCI_STATUS_OK )return rsp_1->status; +/* Success response must contain the full fixed-size header */ +if (skb_headlen (skb) <sizeof (*rsp_1)) +return NCI_STATUS_SYNTAX_ERROR ; + +/* Ensure the variable-length rf_interfaces array and trailing +* rsp_2 structure are fully contained within the skb. +*/ +if (skb_headlen (skb) <sizeof (*rsp_1) + + rsp_1->num_supported_rf_interfaces + +sizeof (*rsp_2)) +return NCI_STATUS_SYNTAX_ERROR ; + ndev->nfcc_features =__le32_to_cpu (rsp_1->nfcc_features); ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
@@ -87,15 +103,25 @@ static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev, const struct sk_buff *skb) {const struct nci_core_init_rsp_nci_ver2 *rsp = (void *)skb->data; -const u8 *supported_rf_interface = rsp->supported_rf_interfaces; +const u8 *supported_rf_interface;u8 rf_interface_idx =0 ;u8 rf_extension_cnt =0 ; +/* Ensure that the status field can be accessed. */ +if (skb_headlen (skb) <1 ) +return NCI_STATUS_SYNTAX_ERROR ; +pr_debug ("status %x\n" , rsp->status);if (rsp->status !=NCI_STATUS_OK )return rsp->status; +/* Success response must contain the full fixed-size header */ +if (skb_headlen (skb) <sizeof (*rsp)) +return NCI_STATUS_SYNTAX_ERROR ; + + supported_rf_interface = rsp->supported_rf_interfaces; + ndev->nfcc_features =__le32_to_cpu (rsp->nfcc_features); ndev->num_supported_rf_interfaces = rsp->num_supported_rf_interfaces;
@@ -104,13 +130,22 @@ static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev, NCI_MAX_SUPPORTED_RF_INTERFACES);while (rf_interface_idx < ndev->num_supported_rf_interfaces) { - ndev->supported_rf_interfaces[rf_interface_idx++] = *supported_rf_interface++; +/* Each entry: [rf_interface_type (1B)] [ext_count (1B)] [ext...] */ +if (supported_rf_interface +2 >skb_tail_pointer (skb)) +break ; + ndev->supported_rf_interfaces[rf_interface_idx] = *supported_rf_interface++; -/* skip rf extension parameters */ rf_extension_cnt = *supported_rf_interface++; +if (supported_rf_interface + rf_extension_cnt >skb_tail_pointer (skb)) +break ; + +/* Only count the entry after full validation */ + rf_interface_idx++; supported_rf_interface += rf_extension_cnt; } + ndev->num_supported_rf_interfaces = rf_interface_idx; + ndev->max_logical_connections = rsp->max_logical_connections; ndev->max_routing_table_size =__le16_to_cpu (rsp->max_routing_table_size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1173/1424 dmaengine: qcom-bam-dma: fix autosuspend cleanup during removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit a50184171235045d96104811414b25cf5338cf86 ]
bam_dma_probe() calls pm_runtime_use_autosuspend(), but bam_dma_remove() does not call the matching pm_runtime_dont_use_autosuspend() when removing the device.
If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped and usage_count remains unbalanced.
Add the missing pm_runtime_dont_use_autosuspend() call before forcing the device into runtime suspend during removal.
This issue was found by manual code inspection.
--- drivers/dma/qcom/bam_dma.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/qcom/bam_dma.c +1 -0
@@ -1395,6 +1395,7 @@ static int bam_dma_remove(struct platform_device *pdev)struct bam_device *bdev =platform_get_drvdata (pdev);u32 i; +pm_runtime_dont_use_autosuspend (&pdev->dev);pm_runtime_force_suspend (&pdev->dev);of_dma_controller_free (pdev->dev.of_node);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1174/1424 RDMA/cxgb4: Free debugfs on registration failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit fe5c16bb6252dea6025b748257ddc3b2665495b0 ]
c4iw_alloc() creates the per-device debugfs tree (dev->debugfs_root via setup_debugfs()), but it is removed only in c4iw_remove(), not in c4iw_dealloc(). When RDMA device registration fails, the registration worker's err_dealloc_ctx path calls c4iw_dealloc() directly, bypassing c4iw_remove(), so the debugfs dentries leak and outlive the freed c4iw_dev.
Move debugfs_remove_recursive() into c4iw_dealloc() so every path that frees ctx->dev also removes its debugfs tree.
--- drivers/infiniband/hw/cxgb4/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/cxgb4/device.c +1 -1
@@ -935,6 +935,7 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev)void c4iw_dealloc (struct uld_ctx *ctx) { +debugfs_remove_recursive (ctx->dev->debugfs_root);c4iw_rdev_close (&ctx->dev->rdev);WARN_ON (!xa_empty (&ctx->dev->cqs));WARN_ON (!xa_empty (&ctx->dev->qps));
@@ -959,7 +960,6 @@ static void c4iw_remove(struct uld_ctx *ctx)if (!ctx->dev)return ; -debugfs_remove_recursive (ctx->dev->debugfs_root);c4iw_unregister_device (ctx->dev);c4iw_dealloc (ctx); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1175/1424 RDMA/cma: Fix WARNING in res_to_rt
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhu Yanjun <[email protected]>
[ Upstream commit c6d1ec4fbe56492bb88987d577f04a5fb6955f26 ]
syzbot reported a WARN_ON(!res->dev) in res_to_rt() triggered via addr_handler() during asynchronous address resolution:
"
WARNING: drivers/infiniband/core/restrack.c:138 at res_to_rt+0x1c4/0x230 CPU#1: kworker/u8:4/59 Modules linked in: CPU: 1 UID: 0 PID: 59 Comm: kworker/u8:4 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Compute Engine, BIOS Google 07/24/2026 Workqueue: ib_addr process_one_req RIP: 0010:res_to_rt+0x1c4/0x230 drivers/infiniband/core/restrack.c:138 RSP: 0018:ffffc9000201f850 EFLAGS: 00010293 RAX: ffffffff88d00ce5 RBX: ffff88807f0fd4f8 RCX: ffff88801e6e0000 RDX: 0000000000000000 RSI: ffffffff8fd996f0 RDI: 0000000000000003 RBP: 0000000000000000 R08: ffff88801e6e0000 R09: 000000000000000a R10: 0000000000000009 R11: 0000000000000000 R12: dffffc0000000000 R13: 1ffff1100fe1fa9f R14: 0000000000000000 R15: 0000000000000003 FS: 0000000000000000(0000) GS:ffff888125012000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00001d559c3d2000 CR3: 0000000077c4c000 CR4: 00000000003526f0 Call Trace: <TASK> rdma_restrack_add+0x5a/0x8a0 drivers/infiniband/core/restrack.c:236 addr_handler+0x41a/0x5a0 drivers/infiniband/core/cma.c:3534 process_one_req+0x2eb/0x540 drivers/infiniband/core/addr.c:624 process_one_work kernel/workqueue.c:3375 [inline] process_scheduled_works+0xc4e/0x1630 kernel/workqueue.c:3458 worker_thread+0xa47/0xfb0 kernel/workqueue.c:3539 kthread+0x388/0x470 kernel/kthread.c:436 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK>
"
In addr_handler(), cma_acquire_dev_by_src_ip() is called to populate id_priv->cma_dev and bind the associated ib_device to id_priv->id.device. If cma_acquire_dev_by_src_ip() returns an error (non-zero status), the ID remains unassociated with any RDMA device.
Previously, rdma_restrack_add(&id_priv->res) was invoked unconditionally even when cma_acquire_dev_by_src_ip() failed, passing a resource with a NULL dev pointer and triggering the WARN_ON assertion in res_to_rt().
Fix this by only adding the resource to restrack when acquiring the device succeeds.
--- drivers/infiniband/core/cma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/core/cma.c +4 -2
@@ -3501,10 +3501,12 @@ static void addr_handler(int status, struct sockaddr *src_addr,memcpy (addr, src_addr,rdma_addr_size (src_addr));if (!status && !id_priv->cma_dev) { status =cma_acquire_dev_by_src_ip (id_priv); -if (status) +if (status) {pr_debug_ratelimited ("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n" , status); -rdma_restrack_add (&id_priv->res); + }else { +rdma_restrack_add (&id_priv->res); + } }else if (status) {pr_debug_ratelimited ("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n" , status); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1176/1424 ice: clear the default forwarding VSI rule when releasing a VSI
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit d04287e27bf1c0b879a10d929c163f2da69715b6 ]
When a VSI is configured as the switch's default forwarding VSI (ICE_SW_LKUP_DFLT) and is then torn down, the rule is left behind in the switch. ice_vsi_release() no longer removes it, and the SR-IOV VF free path (ice_free_vfs() -> ice_free_vf_res() -> ice_vf_vsi_release() -> ice_vsi_release()) does not disable promiscuous mode either, which only happens on VF reset in ice_vf_clear_all_promisc_modes().
A trusted VF that enters unicast promiscuous mode becomes the default forwarding VSI (this is the default mode, when the PF does not have VF true-promiscuous mode enabled). If the VFs are then destroyed without the VF first leaving promiscuous mode, the ICE_SW_LKUP_DFLT rule for the now-freed VSI is leaked. When VFs are recreated, a VSI reuses the freed hw_vsi_id. If it is assigned a different VSI handle than the leaked rule holds, ice_set_dflt_vsi() does not recognize it as already-default, and ice_add_update_vsi_list() folds the dangling (freed) handle into a VSI list, which the firmware rejects. The VSI handle assigned on re-creation varies, so the failure is intermittent rather than every cycle.
Reproduce by repeatedly running the cycle below on the two ports of the same card, where $VF0 and $VF1 are the netdevs of vf 15 once they appear. The VF must be brought up so iavf actually pushes the unicast promiscuous request, and the rule must settle before the VFs are torn down again:
echo 16 > /sys/class/net/$PF0/device/sriov_numvfs echo 16 > /sys/class/net/$PF1/device/sriov_numvfs ip link set $PF0 vf 15 trust on
ip link set $PF1 vf 15 trust on
ip link set $VF0 up
ip link set $VF1 up
ip link set $VF0 promisc on
ip link set $VF1 promisc on
sleep 1
echo 0 > /sys/class/net/$PF0/device/sriov_numvfs echo 0 > /sys/class/net/$PF1/device/sriov_numvfs
Within a few cycles the ice PF and iavf VF log:
Failed to set VSI 25 as the default forwarding VSI, error -22 Turning on/off promiscuous mode for VF 63 failed, error: -22 PF returned error -53 (IAVF_ERR_ADMIN_QUEUE_ERROR) to our request 14
This cleanup used to live in ice_vsi_release() but was dropped by the referenced refactor. Restore it. Clear the default forwarding VSI rule in ice_vsi_release() when this VSI owns it, which covers every teardown path.
--- drivers/net/ethernet/intel/ice/ice_lib.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/intel/ice/ice_lib.c +3 -0
@@ -2948,6 +2948,9 @@ int ice_vsi_release(struct ice_vsi *vsi)return -ENODEV ; pf = vsi->back; +if (ice_is_vsi_dflt_vsi (vsi)) +ice_clear_dflt_vsi (vsi); +if (test_bit (ICE_FLAG_RSS_ENA , pf->flags))ice_rss_clean (vsi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1177/1424 ASoC: pxa: Use devm_clk_get_optional() for extclk clock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: bui duc phuc <[email protected]>
[ Upstream commit 6ec64d757af9b75a3c64f9f7dad76bdc1efc06ca ]
The Device Tree binding defines the extclk clock as an optional property, but the driver currently uses devm_clk_get() and manually handles the absence of the clock.
Use devm_clk_get_optional() to match the binding and simplify the optional clock handling. This also propagates errors other than the absence of the optional clock, including -EPROBE_DEFER.
This changes the existing behavior for errors other than -EPROBE_DEFER. RFC to discuss whether these errors should cause probe to fail rather than being treated as an unavailable optional clock.
--- sound/soc/pxa/pxa-ssp.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
sound/soc/pxa/pxa-ssp.c +2 -5
@@ -769,13 +769,10 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai) goto err_priv; } - priv->extclk =devm_clk_get (dev,"extclk" ); + priv->extclk =devm_clk_get_optional (dev,"extclk" );if (IS_ERR (priv->extclk)) { ret =PTR_ERR (priv->extclk); -if (ret == -EPROBE_DEFER ) - goto err_priv; - - priv->extclk =NULL ; + goto err_priv; } }else { priv->ssp =pxa_ssp_request (dai->id +1 ,"SoC audio" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1178/1424 ASoC: fsl-asoc-card: defer probe when the CPU DAI device is not ready
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: LiangCheng Wang <[email protected]>
[ Upstream commit 0286324da660875dc504fd65b3be87e9c8b9a547 ]
fsl_asoc_card_probe() hard-fails with -EINVAL when the CPU DAI (SAI) platform device is not found. Like the codec, the CPU DAI may just be probed later than the machine driver; the order is not guaranteed and varies across kernel versions, so a permanent -EINVAL leaves the card unregistered with no analog playback or capture.
Defer probe instead, mirroring commit e396dec46c56 ("ASoC:
fsl-asoc-card: Defer probe when fail to find codec device").
Tested on i.MX8MP with an ALC5672 on SAI3: the card that failed to register on v6.18 now comes up during boot.
--- sound/soc/fsl/fsl-asoc-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/fsl/fsl-asoc-card.c +2 -2
@@ -573,8 +573,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) cpu_pdev =of_find_device_by_node (cpu_np);if (!cpu_pdev) { -dev_err (&pdev->dev,"failed to find CPU DAI device\n" ); - ret = -EINVAL ; + ret =dev_err_probe (&pdev->dev, -EPROBE_DEFER , +"failed to find CPU DAI device\n" ); goto fail; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1179/1424 ubi: fastmap: Fix missed ec updating after erasing old fastmap data block
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit 4d18b5a57b16c21cf868369ca555068722c32b2d ]
After running fsstress on ubifs for a long time, UBI(16384 blocks, fastmap takes 2 blocks) has an erase block with different erase counters displayed from two views:
Quoted 1 line
From ubiscan view: PEB 8031 has erase counter 31581
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 16383 290 315 781 1000 .. 9999: 0 0 0 0 10000 .. 99999: 1 31581 31581 31581 100000 .. inf: 0 0 0 0
---------------------------------------------------------
Total : 16384 290 317 31581
Quoted 1 line
From
detailed_erase_block_infoview: PEB 8031 has erase counter 7
physical_block_number erase_count 8030 421 8031 7 # mem info is different from disk info 8032 434 8033 425 8034 431
Following process missed updating erase counter in wl_entry(in memory):ubi_update_fastmap
for (i = 1; i < new_fm->used_blocks; i++) // update fastmap data
if (!tmp_e)
if (old_fm && old_fm->e[i])
erase_block(ubi, old_fm->e[i]->pnum)
ret = ubi_io_sync_erase(ubi, pnum, 0)
ec = be64_to_cpu(ec_hdr->ec)
ec += ret
ec_hdr->ec = cpu_to_be64(ec)
ubi_io_write_ec_hdr(ubi, pnum, ec_hdr) // ec is updated on flash// ec is not updated in old_fm->e[i] (in memory)
Fix it by passing wl_enter into erase_block() and updating erase counter in erase_block().
Stable-dep-of: 420477a84f1e ("UBI: Preserve torture flag when rescheduling failed erasures")
--- drivers/mtd/ubi/fastmap.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
drivers/mtd/ubi/fastmap.c +15 -10
@@ -1393,11 +1393,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi,/** * erase_block - Manually erase a PEB. * @ubi: UBI device object -* @pnum: PEB to be erased +* @e: the physical eraseblock to erase * -* Returns the new EC value on success, < 0 indicates an internal error. +* This function returns zero in case of success and a negative error code in +* case of failure. */ -static int erase_block (struct ubi_device *ubi,int pnum) +static int erase_block (struct ubi_device *ubi,struct ubi_wl_entry *e) {int ret;struct ubi_ec_hdr *ec_hdr;
@@ -1407,7 +1408,7 @@ static int erase_block(struct ubi_device *ubi, int pnum)if (!ec_hdr)return -ENOMEM ; - ret =ubi_io_read_ec_hdr (ubi, pnum, ec_hdr,0 ); + ret =ubi_io_read_ec_hdr (ubi, e->pnum, ec_hdr,0 );if (ret <0 ) goto out;else if (ret && ret !=UBI_IO_BITFLIPS ) {
@@ -1415,7 +1416,7 @@ static int erase_block(struct ubi_device *ubi, int pnum) goto out; } - ret =ubi_io_sync_erase (ubi, pnum,0 ); + ret =ubi_io_sync_erase (ubi, e->pnum,0 );if (ret <0 ) goto out;
@@ -1427,11 +1428,16 @@ static int erase_block(struct ubi_device *ubi, int pnum) } ec_hdr->ec =cpu_to_be64 (ec); - ret =ubi_io_write_ec_hdr (ubi, pnum, ec_hdr); + ret =ubi_io_write_ec_hdr (ubi, e->pnum, ec_hdr);if (ret <0 ) goto out; - ret = ec; + e->ec = ec; +spin_lock (&ubi->wl_lock); +if (e->ec > ubi->max_ec) + ubi->max_ec = e->ec; +spin_unlock (&ubi->wl_lock); + out:kfree (ec_hdr);return ret;
@@ -1577,7 +1583,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (!tmp_e) {if (old_fm && old_fm->e[i]) { - ret =erase_block (ubi, old_fm->e[i]->pnum); + ret =erase_block (ubi, old_fm->e[i]);if (ret <0 ) {ubi_err (ubi,"could not erase old fastmap PEB" );
@@ -1629,7 +1635,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (old_fm) {/* no fresh anchor PEB was found, reuse the old one */ if (!tmp_e) { - ret =erase_block (ubi, old_fm->e[0 ]->pnum); + ret =erase_block (ubi, old_fm->e[0 ]);if (ret <0 ) {ubi_err (ubi,"could not erase old anchor PEB" );
@@ -1641,7 +1647,6 @@ int ubi_update_fastmap(struct ubi_device *ubi) goto err; } new_fm->e[0 ] = old_fm->e[0 ]; - new_fm->e[0 ]->ec = ret; old_fm->e[0 ] =NULL ; }else {/* we've got a new anchor PEB, return the old one */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1180/1424 ubi: fastmap: erase_block: Get erase counter from wl_entry rather than flash
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit 08a4267874164b2e9c8c50831acd466f47208acc ]
Just like sync_erase() does, getting erase counter from wl_entry is faster than reading from flash.
Stable-dep-of: 420477a84f1e ("UBI: Preserve torture flag when rescheduling failed erasures")
--- drivers/mtd/ubi/fastmap.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-)
drivers/mtd/ubi/fastmap.c +9 -18
@@ -1400,36 +1400,27 @@ static int ubi_write_fastmap(struct ubi_device *ubi,*/ static int erase_block (struct ubi_device *ubi,struct ubi_wl_entry *e) { -int ret; +int err;struct ubi_ec_hdr *ec_hdr; -long long ec; +long long ec = e->ec; ec_hdr =kzalloc (ubi->ec_hdr_alsize,GFP_KERNEL );if (!ec_hdr)return -ENOMEM ; - ret =ubi_io_read_ec_hdr (ubi, e->pnum, ec_hdr,0 ); -if (ret <0 ) - goto out; -else if (ret && ret !=UBI_IO_BITFLIPS ) { - ret = -EINVAL ; - goto out; - } - - ret =ubi_io_sync_erase (ubi, e->pnum,0 ); -if (ret <0 ) + err =ubi_io_sync_erase (ubi, e->pnum,0 ); +if (err <0 ) goto out; - ec =be64_to_cpu (ec_hdr->ec); - ec += ret; + ec += err;if (ec >UBI_MAX_ERASECOUNTER ) { - ret = -EINVAL ; + err = -EINVAL ; goto out; } ec_hdr->ec =cpu_to_be64 (ec); - ret =ubi_io_write_ec_hdr (ubi, e->pnum, ec_hdr); -if (ret <0 ) + err =ubi_io_write_ec_hdr (ubi, e->pnum, ec_hdr); +if (err <0 ) goto out; e->ec = ec;
@@ -1440,7 +1431,7 @@ static int erase_block(struct ubi_device *ubi, struct ubi_wl_entry *e) out:kfree (ec_hdr); -return ret; +return err; }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1181/1424 ubi: fastmap: Allocate memory with GFP_NOFS in ubi_update_fastmap
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit a033ab4fec5fd9194d1b6c0306efbdc75f70b142 ]
Function ubi_update_fastmap could be called in IO context, for example:
ubifs_writepage
do_writepage
ubifs_jnl_write_data
write_head
ubifs_wbuf_write_nolock
ubifs_leb_write
ubi_leb_write
ubi_eba_write_leb
try_write_vid_and_data
ubi_wl_get_peb
ubi_update_fastmap
erase_block
So it's better to allocate memory with GFP_NOFS mode, in case waiting page writeback(dead loop).
Stable-dep-of: 420477a84f1e ("UBI: Preserve torture flag when rescheduling failed erasures")
--- drivers/mtd/ubi/fastmap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/mtd/ubi/fastmap.c +5 -5
@@ -20,7 +20,7 @@ static inline unsigned long *init_seen(struct ubi_device *ubi)if (!ubi_dbg_chk_fastmap (ubi))return NULL ; - ret =bitmap_zalloc (ubi->peb_count,GFP_KERNEL ); + ret =bitmap_zalloc (ubi->peb_count,GFP_NOFS );if (!ret)return ERR_PTR (-ENOMEM );
@@ -106,7 +106,7 @@ static struct ubi_vid_io_buf *new_fm_vbuf(struct ubi_device *ubi, int vol_id)struct ubi_vid_io_buf *new;struct ubi_vid_hdr *vh; - new =ubi_alloc_vid_buf (ubi,GFP_KERNEL ); + new =ubi_alloc_vid_buf (ubi,GFP_NOFS );if (!new) goto out;
@@ -1404,7 +1404,7 @@ static int erase_block(struct ubi_device *ubi, struct ubi_wl_entry *e)struct ubi_ec_hdr *ec_hdr;long long ec = e->ec; - ec_hdr =kzalloc (ubi->ec_hdr_alsize,GFP_KERNEL ); + ec_hdr =kzalloc (ubi->ec_hdr_alsize,GFP_NOFS );if (!ec_hdr)return -ENOMEM ;
@@ -1460,7 +1460,7 @@ static int invalidate_fastmap(struct ubi_device *ubi) ubi->fm =NULL ; ret = -ENOMEM ; - fm =kzalloc (sizeof (*fm),GFP_KERNEL ); + fm =kzalloc (sizeof (*fm),GFP_NOFS );if (!fm) goto out;
@@ -1549,7 +1549,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)return 0 ; } - new_fm =kzalloc (sizeof (*new_fm),GFP_KERNEL ); + new_fm =kzalloc (sizeof (*new_fm),GFP_NOFS );if (!new_fm) {up_write (&ubi->fm_eba_sem);up_write (&ubi->work_sem);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1182/1424 ubi: Replace erase_block() with sync_erase()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit c19286d70aaa361cdb073a68a1f66232c359e2fd ]
Since erase_block() has same logic with sync_erase(), just replace it with sync_erase(), also rename 'sync_erase()' to 'ubi_sync_erase()'.
Stable-dep-of: 420477a84f1e ("UBI: Preserve torture flag when rescheduling failed erasures")
--- drivers/mtd/ubi/fastmap.c | 48 ++------------------------------------- drivers/mtd/ubi/ubi.h | 1 + drivers/mtd/ubi/wl.c | 9 ++++---- 3 files changed, 7 insertions(+), 51 deletions(-)
drivers/mtd/ubi/fastmap.c +2 -46
@@ -1390,50 +1390,6 @@ static int ubi_write_fastmap(struct ubi_device *ubi,return ret; } -/** -* erase_block - Manually erase a PEB. -* @ubi: UBI device object -* @e: the physical eraseblock to erase -* -* This function returns zero in case of success and a negative error code in -* case of failure. -*/ -static int erase_block (struct ubi_device *ubi,struct ubi_wl_entry *e) -{ -int err; -struct ubi_ec_hdr *ec_hdr; -long long ec = e->ec; - - ec_hdr =kzalloc (ubi->ec_hdr_alsize,GFP_NOFS ); -if (!ec_hdr) -return -ENOMEM ; - - err =ubi_io_sync_erase (ubi, e->pnum,0 ); -if (err <0 ) - goto out; - - ec += err; -if (ec >UBI_MAX_ERASECOUNTER ) { - err = -EINVAL ; - goto out; - } - - ec_hdr->ec =cpu_to_be64 (ec); - err =ubi_io_write_ec_hdr (ubi, e->pnum, ec_hdr); -if (err <0 ) - goto out; - - e->ec = ec; -spin_lock (&ubi->wl_lock); -if (e->ec > ubi->max_ec) - ubi->max_ec = e->ec; -spin_unlock (&ubi->wl_lock); - -out: -kfree (ec_hdr); -return err; -} -/** * invalidate_fastmap - destroys a fastmap. * @ubi: UBI device object
@@ -1574,7 +1530,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (!tmp_e) {if (old_fm && old_fm->e[i]) { - ret =erase_block (ubi, old_fm->e[i]); + ret =ubi_sync_erase (ubi, old_fm->e[i],0 );if (ret <0 ) {ubi_err (ubi,"could not erase old fastmap PEB" );
@@ -1626,7 +1582,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (old_fm) {/* no fresh anchor PEB was found, reuse the old one */ if (!tmp_e) { - ret =erase_block (ubi, old_fm->e[0 ]); + ret =ubi_sync_erase (ubi, old_fm->e[0 ],0 );if (ret <0 ) {ubi_err (ubi,"could not erase old anchor PEB" );
drivers/mtd/ubi/ubi.h +1 -0
@@ -902,6 +902,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, struct ubi_attach_info *ai_scan);/* wl.c */ +int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int torture);int ubi_wl_get_peb (struct ubi_device *ubi);int ubi_wl_put_peb (struct ubi_device *ubi,int vol_id,int lnum,int pnum,int torture);
drivers/mtd/ubi/wl.c +4 -5
@@ -427,7 +427,7 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum) }/** -* sync_erase - synchronously erase a physical eraseblock. +* ubi_sync_erase - synchronously erase a physical eraseblock. * @ubi: UBI device description object * @e: the physical eraseblock to erase * @torture: if the physical eraseblock has to be tortured
@@ -435,8 +435,7 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)* This function returns zero in case of success and a negative error code in * case of failure. */ -static int sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e, -int torture) +int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int torture) {int err;struct ubi_ec_hdr *ec_hdr;
@@ -1101,7 +1100,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)dbg_wl ("erase PEB %d EC %d LEB %d:%d" , pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum); - err =sync_erase (ubi, e, wl_wrk->torture); + err =ubi_sync_erase (ubi, e, wl_wrk->torture);if (!err) {spin_lock (&ubi->wl_lock);
@@ -1756,7 +1755,7 @@ static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync ubi->lookuptbl[e->pnum] = e;if (sync) { - err =sync_erase (ubi, e, false); + err =ubi_sync_erase (ubi, e, false);if (err) goto out_free;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1183/1424 UBI: Preserve torture flag when rescheduling failed erasures
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit 420477a84f1e52babfe60a43dbdd0988ed956845 ]
In __erase_worker(), when ubi_sync_erase() returns -EINTR, -ENOMEM, -EAGAIN, or -EBUSY, the physical eraseblock is rescheduled for erasure via schedule_erase() with the torture flag hardcoded to 0. This unconditionally drops the torture request.
If the error occurred before torture_peb() completed (e.g., -ENOMEM from the ec_hdr allocation in ubi_sync_erase(), errors from self_check_not_bad()/nor_erase_prepare() in ubi_io_sync_erase(), or torture_peb() failing mid-test because its internal do_sync_erase()/ ubi_io_read()/ubi_io_write() returned one of the above error codes), the torture test was never finished. Such a PEB may reach the free pool without being tortured, defeating the purpose of the torture test for detecting marginally-bad eraseblocks.
If the error occurred after torture_peb() succeeded (the final do_sync_erase() in ubi_io_sync_erase() or ubi_io_write_ec_hdr() in ubi_sync_erase() failed), the torture has already been done and need not be repeated.
Pass the torture flag by pointer to ubi_sync_erase() and ubi_io_sync_erase(), and clear it to zero once torture_peb() has completed successfully. __erase_worker() then forwards the updated wl_wrk->torture to schedule_erase(): torture already done is dropped, torture not completed is preserved across the reschedule.
--- drivers/mtd/ubi/attach.c | 4 ++-- drivers/mtd/ubi/fastmap.c | 6 +++--- drivers/mtd/ubi/io.c | 11 +++++++---- drivers/mtd/ubi/ubi.h | 4 ++-- drivers/mtd/ubi/wl.c | 15 +++++++++------ 5 files changed, 23 insertions(+), 17 deletions(-)
drivers/mtd/ubi/attach.c +2 -2
@@ -771,7 +771,7 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)static int early_erase_peb (struct ubi_device *ubi,const struct ubi_attach_info *ai,int pnum,int ec) { -int err; +int err, torture =0 ;struct ubi_ec_hdr *ec_hdr;if ((long long )ec >=UBI_MAX_ERASECOUNTER ) {
@@ -790,7 +790,7 @@ static int early_erase_peb(struct ubi_device *ubi, ec_hdr->ec =cpu_to_be64 (ec); - err =ubi_io_sync_erase (ubi, pnum,0 ); + err =ubi_io_sync_erase (ubi, pnum, &torture);if (err <0 ) goto out_free;
drivers/mtd/ubi/fastmap.c +3 -3
@@ -1488,7 +1488,7 @@ static void return_fm_pebs(struct ubi_device *ubi,*/ int ubi_update_fastmap (struct ubi_device *ubi) { -int ret, i, j; +int ret, i, j, torture =0 ;struct ubi_fastmap_layout *new_fm, *old_fm;struct ubi_wl_entry *tmp_e;
@@ -1530,7 +1530,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (!tmp_e) {if (old_fm && old_fm->e[i]) { - ret =ubi_sync_erase (ubi, old_fm->e[i],0 ); + ret =ubi_sync_erase (ubi, old_fm->e[i], &torture);if (ret <0 ) {ubi_err (ubi,"could not erase old fastmap PEB" );
@@ -1582,7 +1582,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (old_fm) {/* no fresh anchor PEB was found, reuse the old one */ if (!tmp_e) { - ret =ubi_sync_erase (ubi, old_fm->e[0 ],0 ); + ret =ubi_sync_erase (ubi, old_fm->e[0 ], &torture);if (ret <0 ) {ubi_err (ubi,"could not erase old anchor PEB" );
drivers/mtd/ubi/io.c +7 -4
@@ -507,8 +507,10 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)/** * ubi_io_sync_erase - synchronously erase a physical eraseblock. * @ubi: UBI device description object -* @pnum: physical eraseblock number to erase -* @torture: if this physical eraseblock has to be tortured +* @pnum: the physical eraseblock number to erase +* @torture: if this physical eraseblock has to be tortured; cleared to zero +* once the torture test has completed successfully so that a retry +* of the erase does not torture the physical eraseblock again * * This function synchronously erases physical eraseblock @pnum. If @torture * flag is not zero, the physical eraseblock is checked by means of writing
@@ -520,7 +522,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)* codes in case of other errors. Note, %-EIO means that the physical * eraseblock is bad. */ -int ubi_io_sync_erase (struct ubi_device *ubi,int pnum,int torture) +int ubi_io_sync_erase (struct ubi_device *ubi,int pnum,int *torture) {int err, ret =0 ;
@@ -548,10 +550,11 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)return err; } -if (torture) { +if (*torture) { ret =torture_peb (ubi, pnum);if (ret <0 )return ret; + *torture =0 ; } err =do_sync_erase (ubi, pnum);
drivers/mtd/ubi/ubi.h +2 -2
@@ -902,7 +902,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, struct ubi_attach_info *ai_scan);/* wl.c */ -int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int torture); +int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int *torture);int ubi_wl_get_peb (struct ubi_device *ubi);int ubi_wl_put_peb (struct ubi_device *ubi,int vol_id,int lnum,int pnum,int torture);
@@ -924,7 +924,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int len);int ubi_io_write (struct ubi_device *ubi,const void *buf,int pnum,int offset,int len); -int ubi_io_sync_erase (struct ubi_device *ubi,int pnum,int torture); +int ubi_io_sync_erase (struct ubi_device *ubi,int pnum,int *torture);int ubi_io_is_bad (const struct ubi_device *ubi,int pnum);int ubi_io_mark_bad (const struct ubi_device *ubi,int pnum); int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
drivers/mtd/ubi/wl.c +9 -6
@@ -430,12 +430,14 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)* ubi_sync_erase - synchronously erase a physical eraseblock. * @ubi: UBI device description object * @e: the physical eraseblock to erase -* @torture: if the physical eraseblock has to be tortured +* @torture: if the physical eraseblock has to be tortured; cleared to zero +* once the torture test has completed successfully so that a retry +* of the erase does not torture the physical eraseblock again * * This function returns zero in case of success and a negative error code in * case of failure. */ -int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int torture) +int ubi_sync_erase (struct ubi_device *ubi,struct ubi_wl_entry *e,int *torture) {int err;struct ubi_ec_hdr *ec_hdr;
@@ -1100,7 +1102,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)dbg_wl ("erase PEB %d EC %d LEB %d:%d" , pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum); - err =ubi_sync_erase (ubi, e, wl_wrk->torture); + err =ubi_sync_erase (ubi, e, &wl_wrk->torture);if (!err) {spin_lock (&ubi->wl_lock);
@@ -1137,7 +1139,8 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)int err1;/* Re-schedule the LEB for erasure */ - err1 =schedule_erase (ubi, e, vol_id, lnum,0 , true); + err1 =schedule_erase (ubi, e, vol_id, lnum, wl_wrk->torture, + true);if (err1) {spin_lock (&ubi->wl_lock);wl_entry_destroy (ubi, e);
@@ -1744,7 +1747,7 @@ static void shutdown_work(struct ubi_device *ubi)static int erase_aeb (struct ubi_device *ubi,struct ubi_ainf_peb *aeb,bool sync) {struct ubi_wl_entry *e; -int err; +int err, torture =0 ; e =kmem_cache_alloc (ubi_wl_entry_slab,GFP_KERNEL );if (!e)
@@ -1755,7 +1758,7 @@ static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync ubi->lookuptbl[e->pnum] = e;if (sync) { - err =ubi_sync_erase (ubi, e, false); + err =ubi_sync_erase (ubi, e, &torture);if (err) goto out_free;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1184/1424 UBI: fastmap: Pass to_be_tortured when reusing old fastmap PEBs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit be04fce9945aac2a843f5d16725391eb80d948ef ]
In ubi_update_fastmap(), when no fresh PEB is available to replace an old fastmap PEB, the old PEB is reused by erasing it synchronously via ubi_sync_erase() with the torture flag hardcoded to zero.
However, old_fm->to_be_tortured[] may be non-zero: it is set during fastmap scanning when ubi_io_read_data()/ubi_io_read_ec_hdr() reports UBI_IO_BITFLIPS, meaning the PEB showed signs of bit decay and should be tortured to verify it is still reliable.
When the old PEB is instead returned to the WL sub-system via ubi_wl_put_fm_peb(), the to_be_tortured flag is honored. The synchronous reuse path is inconsistent: it silently skips the torture test for PEBs that exhibited bit-flips.
Fix it by passing &old_fm->to_be_tortured[i] to ubi_sync_erase().
--- drivers/mtd/ubi/fastmap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/mtd/ubi/fastmap.c +5 -3
@@ -1488,7 +1488,7 @@ static void return_fm_pebs(struct ubi_device *ubi,*/ int ubi_update_fastmap (struct ubi_device *ubi) { -int ret, i, j, torture =0 ; +int ret, i, j;struct ubi_fastmap_layout *new_fm, *old_fm;struct ubi_wl_entry *tmp_e;
@@ -1530,7 +1530,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (!tmp_e) {if (old_fm && old_fm->e[i]) { - ret =ubi_sync_erase (ubi, old_fm->e[i], &torture); + ret =ubi_sync_erase (ubi, old_fm->e[i], + &old_fm->to_be_tortured[i]);if (ret <0 ) {ubi_err (ubi,"could not erase old fastmap PEB" );
@@ -1582,7 +1583,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)if (old_fm) {/* no fresh anchor PEB was found, reuse the old one */ if (!tmp_e) { - ret =ubi_sync_erase (ubi, old_fm->e[0 ], &torture); + ret =ubi_sync_erase (ubi, old_fm->e[0 ], + &old_fm->to_be_tortured[0 ]);if (ret <0 ) {ubi_err (ubi,"could not erase old anchor PEB" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1185/1424 ubi: fastmap: Wait until there are enough free PEBs before filling pools
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit a2ea69dac674df0fba59c66146a21145108a85ed ]
Wait until there are enough free PEBs before filling pool/wl_pool, sometimes erase_worker is not scheduled in time, which causes two situations:
A. There are few PEBs filled in pool, which makes ubi_update_fastmap
is frequently called and leads first 64 PEBs are erased more times than other PEBs. So waiting free PEBs before filling pool reduces fastmap updating frequency and prolongs flash service life.
B. In situation that space is nearly running out, ubi_refill_pools()
cannot make sure pool and wl_pool are filled with free PEBs, caused by the delay of erase_worker. After this patch applied, there must exist free PEBs in pool after one call of ubi_update_fastmap.
Besides, this patch is a preparetion for fixing large erase counter in fastmap data block and fixing lapsed wear leveling for first 64 PEBs.
Stable-dep-of: 5b0a6b554e12 ("ubi: Fix rollback for explicit UBI device numbers")
--- drivers/mtd/ubi/eba.c | 3 -- drivers/mtd/ubi/fastmap-wl.c | 53 ++++++++++++++++++++++++++++++++++-- drivers/mtd/ubi/fastmap.c | 6 +--- drivers/mtd/ubi/ubi.h | 5 +++- drivers/mtd/ubi/wl.c | 14 +++++++--- 5 files changed, 65 insertions(+), 16 deletions(-)
drivers/mtd/ubi/eba.c +0 -3
@@ -33,9 +33,6 @@#include <linux/err.h> #include "ubi.h" -/* Number of physical eraseblocks reserved for atomic LEB change operation */ -#define EBA_RESERVED_PEBS 1 -/** * struct ubi_eba_entry - structure encoding a single LEB -> PEB association * @pnum: the physical eraseblock number attached to the LEB
drivers/mtd/ubi/fastmap-wl.c +50 -3
79 lines not on this page · raw message
drivers/mtd/ubi/fastmap.c +1 -5
@@ -1492,11 +1492,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)struct ubi_fastmap_layout *new_fm, *old_fm;struct ubi_wl_entry *tmp_e; -down_write (&ubi->fm_protect); -down_write (&ubi->work_sem); -down_write (&ubi->fm_eba_sem); - -ubi_refill_pools (ubi); +ubi_refill_pools_and_lock (ubi);if (ubi->ro_mode || ubi->fm_disabled) {up_write (&ubi->fm_eba_sem);
drivers/mtd/ubi/ubi.h +4 -1
@@ -82,6 +82,9 @@ void ubi_err(const struct ubi_device *ubi, const char *fmt, ...);#define UBI_DFS_DIR_NAME "ubi%d"#define UBI_DFS_DIR_LEN (3 + 2 + 1) +/* Number of physical eraseblocks reserved for atomic LEB change operation */ +#define EBA_RESERVED_PEBS 1 +/* * Error codes returned by the I/O sub-system. *
@@ -915,7 +918,7 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor);int ubi_wl_put_fm_peb (struct ubi_device *ubi,struct ubi_wl_entry *used_e,int lnum,int torture);int ubi_is_erase_work (struct ubi_work *wrk); -void ubi_refill_pools (struct ubi_device *ubi); +void ubi_refill_pools_and_lock (struct ubi_device *ubi);int ubi_ensure_anchor_pebs (struct ubi_device *ubi);int ubi_bitflip_check (struct ubi_device *ubi,int pnum,int force_scrub);
drivers/mtd/ubi/wl.c +10 -4
@@ -181,11 +181,13 @@ static void wl_entry_destroy(struct ubi_device *ubi, struct ubi_wl_entry *e)/** * do_work - do one pending work. * @ubi: UBI device description object +* @executed: whether there is one work is executed * * This function returns zero in case of success and a negative error code in -* case of failure. +* case of failure. If @executed is not NULL and there is one work executed, +* @executed is set as %1, otherwise @executed is set as %0. */ -static int do_work (struct ubi_device *ubi) +static int do_work (struct ubi_device *ubi,int *executed) {int err;struct ubi_work *wrk;
@@ -203,9 +205,13 @@ static int do_work(struct ubi_device *ubi)if (list_empty (&ubi->works)) {spin_unlock (&ubi->wl_lock);up_read (&ubi->work_sem); +if (executed) + *executed =0 ;return 0 ; } +if (executed) + *executed =1 ; wrk = list_entry(ubi->works.next, struct ubi_work, list);list_del (&wrk->list); ubi->works_count -=1 ;
@@ -1695,7 +1701,7 @@ int ubi_thread(void *u) }spin_unlock (&ubi->wl_lock); - err =do_work (ubi); + err =do_work (ubi,NULL );if (err) {ubi_err (ubi,"%s: work failed with error code %d" , ubi->bgt_name, err);
@@ -2106,7 +2112,7 @@ static int produce_free_peb(struct ubi_device *ubi)spin_unlock (&ubi->wl_lock);dbg_wl ("do one work synchronously" ); - err =do_work (ubi); + err =do_work (ubi,NULL );spin_lock (&ubi->wl_lock);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1186/1424 ubi: fastmap: Fix lapsed wear leveling for first 64 PEBs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit 90e0be56144b064be1a816cbdd184d2a8be7061b ]
The anchor PEB must be picked from first 64 PEBs, these PEBs could have large erase counter greater than other PEBs especially when free space is nearly running out.
The ubi_update_fastmap will be called as long as pool/wl_pool is empty, old anchor PEB is erased when updating fastmap. Given an UBI device with N PEBs, free PEBs is nearly running out and pool will be filled with 1 PEB every time ubi_update_fastmap invoked. So t=N/POOL_SIZE[1]/64 means that in worst case the erase counter of first 64 PEBs is t times greater than other PEBs in theory.
After running fsstress for 24h, the erase counter statistics for two UBI devices shown as follow(CONFIG_MTD_UBI_WL_THRESHOLD=128):
Device A(1024 PEBs, pool=50, wl_pool=25):
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 0 0 0 0 1000 .. 9999: 0 0 0 0 10000 .. 99999: 960 29224 29282 29362 100000 .. inf: 64 117897 117934 117940
---------------------------------------------------------
Total : 1024 29224 34822 117940
Device B(8192 PEBs, pool=256, wl_pool=128):
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 0 0 0 0 1000 .. 9999: 8128 2253 2321 2387 10000 .. 99999: 64 35387 35387 35388 100000 .. inf: 0 0 0 0
---------------------------------------------------------
Total : 8192 2253 2579 35388
The key point is reducing fastmap updating frequency by enlarging POOL_SIZE, so let UBI reserve ubi->fm_pool.max_size PEBs during attaching. Then POOL_SIZE will become ubi->fm_pool.max_size/2 even in free space running out case.
Given an UBI device with 8192 PEBs(16384\8192\4096 is common large-capacity flash), t=8192/128/64=1. The fastmap updating will happen in either wl_pool or pool is empty, so setting fm_pool_rsv_cnt as ubi->fm_pool.max_size can fill wl_pool in full state.
After pool reservation, running fsstress for 24h:
Device A(1024 PEBs, pool=50, wl_pool=25):
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 0 0 0 0 1000 .. 9999: 0 0 0 0 10000 .. 99999: 1024 33801 33997 34056 100000 .. inf: 0 0 0 0
---------------------------------------------------------
Total : 1024 33801 33997 34056
Device B(8192 PEBs, pool=256, wl_pool=128):
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 0 0 0 0 1000 .. 9999: 8192 2205 2397 2460 10000 .. 99999: 0 0 0 0 100000 .. inf: 0 0 0 0
---------------------------------------------------------
Total : 8192 2205 2397 2460
The difference of erase counter between first 64 PEBs and others is under WL_FREE_MAX_DIFF(2*UBI_WL_THRESHOLD=2*128=256).
Device A: 34056 - 33801 = 255
Device B: 2460 - 2205 = 255
Next patch will add a switch to control whether UBI needs to reserve PEBs for filling pool.
Stable-dep-of: 5b0a6b554e12 ("ubi: Fix rollback for explicit UBI device numbers")
--- drivers/mtd/ubi/build.c | 1 + drivers/mtd/ubi/fastmap-wl.c | 2 +- drivers/mtd/ubi/ubi.h | 2 ++ drivers/mtd/ubi/wl.h | 6 ++++-- 4 files changed, 8 insertions(+), 3 deletions(-)
drivers/mtd/ubi/build.c +1 -0
@@ -951,6 +951,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, UBI_FM_MIN_POOL_SIZE); ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size /2 ; + ubi->fm_pool_rsv_cnt = ubi->fm_pool.max_size; ubi->fm_disabled = (!fm_autoconvert || disable_fm) ?1 :0 ;if (fm_debug)ubi_enable_dbg_chk_fastmap (ubi);
drivers/mtd/ubi/fastmap-wl.c +1 -1
@@ -118,7 +118,7 @@ static void wait_free_pebs_for_pool(struct ubi_device *ubi)* 4. beb_rsvd_pebs: This value should be get under lock ubi->wl_lock */ int reserved =WL_RESERVED_PEBS +EBA_RESERVED_PEBS + - ubi->fm_size / ubi->leb_size -1 ; + ubi->fm_size / ubi->leb_size -1 + ubi->fm_pool_rsv_cnt; do { spin_lock(&ubi->wl_lock);
drivers/mtd/ubi/ubi.h +2 -0
@@ -494,6 +494,7 @@ struct ubi_debug_info {* @fast_attach: non-zero if UBI was attached by fastmap * @fm_anchor: The next anchor PEB to use for fastmap * @fm_do_produce_anchor: If true produce an anchor PEB in wl +* @fm_pool_rsv_cnt: Number of reserved PEBs for filling pool/wl_pool * * @used: RB-tree of used physical eraseblocks * @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -604,6 +605,7 @@ struct ubi_device {int fast_attach;struct ubi_wl_entry *fm_anchor;int fm_do_produce_anchor; +int fm_pool_rsv_cnt;/* Wear-leveling sub-system's stuff */ struct rb_root used;
drivers/mtd/ubi/wl.h +4 -2
@@ -11,8 +11,10 @@ static bool need_wear_leveling(struct ubi_device *ubi);static void ubi_fastmap_close (struct ubi_device *ubi);static inline void ubi_fastmap_init (struct ubi_device *ubi,int *count) { -/* Reserve enough LEBs to store two fastmaps. */ - *count += (ubi->fm_size / ubi->leb_size) *2 ; +if (ubi->fm_disabled) + ubi->fm_pool_rsv_cnt =0 ; +/* Reserve enough LEBs to store two fastmaps and to fill pools. */ + *count += (ubi->fm_size / ubi->leb_size) *2 + ubi->fm_pool_rsv_cnt;INIT_WORK (&ubi->fm_work, update_fastmap_work_fn); } static struct ubi_wl_entry *may_reserve_for_fm(struct ubi_device *ubi,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1187/1424 ubi: fastmap: Add module parameter to control reserving filling pool PEBs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhihao Cheng <[email protected]>
[ Upstream commit d4c48e5b58f12835de779f5425ef741c4d0fb53e ]
Adding 6th module parameter in 'mtd=xxx' to control whether or not reserving PEBs for filling pool/wl_pool.
Stable-dep-of: 5b0a6b554e12 ("ubi: Fix rollback for explicit UBI device numbers")
--- drivers/mtd/ubi/build.c | 26 ++++++++++++++++++++++---- drivers/mtd/ubi/cdev.c | 3 ++- drivers/mtd/ubi/ubi.h | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-)
drivers/mtd/ubi/build.c +22 -4
@@ -35,7 +35,7 @@#define MTD_PARAM_LEN_MAX 64/* Maximum number of comma-separated items in the 'mtd=' parameter */ -#define MTD_PARAM_MAX_COUNT 5 +#define MTD_PARAM_MAX_COUNT 6/* Maximum value for the number of bad PEBs per 1024 PEBs */ #define MAX_MTD_UBI_BEB_LIMIT 768
@@ -54,6 +54,7 @@* @vid_hdr_offs: VID header offset * @max_beb_per1024: maximum expected number of bad PEBs per 1024 PEBs * @enable_fm: enable fastmap when value is non-zero +* @need_resv_pool: reserve pool->max_size pebs when value is none-zero */ struct mtd_dev_param {char name[MTD_PARAM_LEN_MAX ];
@@ -61,6 +62,7 @@ struct mtd_dev_param {int vid_hdr_offs;int max_beb_per1024;int enable_fm; +int need_resv_pool; };/* Numbers of elements set in the @mtd_dev_param array */
@@ -825,6 +827,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)* @vid_hdr_offset: VID header offset * @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs * @disable_fm: whether disable fastmap +* @need_resv_pool: whether reserve pebs to fill fm_pool * * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
@@ -840,7 +843,8 @@ static int autoresize(struct ubi_device *ubi, int vol_id)* @ubi_devices_mutex. */ int ubi_attach_mtd_dev (struct mtd_info *mtd,int ubi_num, -int vid_hdr_offset,int max_beb_per1024,bool disable_fm) +int vid_hdr_offset,int max_beb_per1024,bool disable_fm, +bool need_resv_pool) {struct ubi_device *ubi;int i, err;
@@ -951,7 +955,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, UBI_FM_MIN_POOL_SIZE); ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size /2 ; - ubi->fm_pool_rsv_cnt = ubi->fm_pool.max_size; + ubi->fm_pool_rsv_cnt = need_resv_pool ? ubi->fm_pool.max_size :0 ; ubi->fm_disabled = (!fm_autoconvert || disable_fm) ?1 :0 ;if (fm_debug)ubi_enable_dbg_chk_fastmap (ubi);
@@ -1274,7 +1278,8 @@ static int __init ubi_init(void)mutex_lock (&ubi_devices_mutex); err =ubi_attach_mtd_dev (mtd, p->ubi_num, p->vid_hdr_offs, p->max_beb_per1024, - p->enable_fm ==0 ); + p->enable_fm ==0 , + p->need_resv_pool !=0 );mutex_unlock (&ubi_devices_mutex);if (err <0 ) { pr_err("UBI error: cannot attach mtd%d\n",
@@ -1483,6 +1488,18 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) }else p->enable_fm =0 ; + token = tokens[5 ]; +if (token) { +int err =kstrtoint (token,10 , &p->need_resv_pool); + +if (err) { +pr_err ("UBI error: bad value for need_resv_pool parameter: %s\n" , + token); +return -EINVAL ; + } + }else + p->need_resv_pool =0 ; + mtd_devs +=1 ;return 0 ; }
@@ -1496,6 +1513,7 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa __stringify(CONFIG_MTD_UBI_BEB_LIMIT) ") if 0)\n""Optional \"ubi_num\" parameter specifies UBI device number which have to be assigned to the newly created UBI device (assigned automatically by default)\n" "Optional \"enable_fm\" parameter determines whether to enable fastmap during attach. If the value is non-zero, fastmap is enabled. Default value is 0.\n" +"Optional \"need_resv_pool\" parameter determines whether to reserve pool->max_size pebs during attach. If the value is non-zero, peb reservation is enabled. Default value is 0.\n" "\n" "Example 1: mtd=/dev/mtd0 - attach MTD device /dev/mtd0.\n" "Example 2: mtd=content,1984 mtd=4 - attach MTD device with name \"content\" using VID header offset 1984, and MTD device number 4 with default VID header offset.\n"
drivers/mtd/ubi/cdev.c +2 -1
@@ -1041,7 +1041,8 @@ static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,*/ mutex_lock (&ubi_devices_mutex); err =ubi_attach_mtd_dev (mtd, req.ubi_num, req.vid_hdr_offset, - req.max_beb_per1024, !!req.disable_fm); + req.max_beb_per1024, !!req.disable_fm, + false);mutex_unlock (&ubi_devices_mutex);if (err <0 )put_mtd_device (mtd);
drivers/mtd/ubi/ubi.h +1 -1
@@ -944,7 +944,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,/* build.c */ int ubi_attach_mtd_dev (struct mtd_info *mtd,int ubi_num,int vid_hdr_offset,int max_beb_per1024, -bool disable_fm); +bool disable_fm,bool need_resv_pool);int ubi_detach_mtd_dev (int ubi_num,int anyway);struct ubi_device *ubi_get_device (int ubi_num);void ubi_put_device (struct ubi_device *ubi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1188/1424 ubi: Fix rollback for explicit UBI device numbers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 5b0a6b554e12a97f9771a9a9f4ea1f5457373c73 ]
ubi_init_attach() rolls back module initialization failures by scanning ubi_devices[0..i-1], where i is the mtd= parameter index. That assumes the parameter index matches the UBI device number.
That assumption is not true when mtd= specifies an explicit ubi_num. A successfully attached device can be stored at a higher ubi_devices[] slot, and a later failure can miss it during rollback.
Scan the full ubi_devices[] array and detach by the actual array index, matching the way UBI devices are stored.
--- drivers/mtd/ubi/build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/ubi/build.c +2 -2
@@ -1316,10 +1316,10 @@ static int __init ubi_init(void)return 0 ; out_detach: -for (k =0 ; k < i; k++) +for (k =0 ; k <UBI_MAX_DEVICES ; k++)if (ubi_devices[k]) {mutex_lock (&ubi_devices_mutex); -ubi_detach_mtd_dev (ubi_devices[k]->ubi_num,1 ); +ubi_detach_mtd_dev (k,1 );mutex_unlock (&ubi_devices_mutex); }ubi_debugfs_exit ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1189/1424 ASoC: xilinx: formatter_pcm: fix stream_data leak on open error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit b992511180e126150c6ad3580a6fd568c385f4c6 ]
In xlnx_formatter_pcm_open(), stream_data is allocated and adata->play_stream or adata->capture_stream is assigned early. If a later step, such as snd_pcm_hw_constraint_step() or snd_pcm_hw_constraint_integer(), fails, the function returns the error immediately. ALSA does not call the close callback when open fails, so stream_data is leaked and the stream pointer is left dangling, pointing to a substream that ALSA frees. A later interrupt would then call snd_pcm_period_elapsed() on the freed substream.
Free stream_data and clear the stream pointer on the error paths.
--- sound/soc/xilinx/xlnx_formatter_pcm.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
sound/soc/xilinx/xlnx_formatter_pcm.c +11 -3
@@ -384,7 +384,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,if (err) {dev_err (component->dev,"Unable to set constraint on period bytes\n" ); -return err; + goto error; }/* Resize the buffer bytes as divisible by 64 */
@@ -394,7 +394,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,if (err) {dev_err (component->dev,"Unable to set constraint on buffer bytes\n" ); -return err; + goto error; }/* Set periods as integer multiple */
@@ -403,7 +403,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,if (err <0 ) {dev_err (component->dev,"Unable to set constraint on periods to be integer\n" ); -return err; + goto error; }/* enable DMA IOC irq */
@@ -412,6 +412,14 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,writel (val, stream_data->mmio +XLNX_AUD_CTRL );return 0 ; + +error: +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + adata->play_stream =NULL ; +else + adata->capture_stream =NULL ; +kfree (stream_data); +return err; } static int xlnx_formatter_pcm_close(struct snd_soc_component *component,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1190/1424 UBI: fix two issues in the ubi.mtd MODULE_PARM_DESC
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ran Hongyun <[email protected]>
[ Upstream commit ff7937d14f5333ec7e6fb50d00a152d7974f4105 ]
Fix two issues introduced before:
- The parameter format string was missing the enable_fm and need_resv_pool tokens introduced in an earlier commit.
- The bad-block reservation note was misplaced after Example 5 instead of after Example 3. It was misplaced due to an earlier patch.
--- drivers/mtd/ubi/build.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/mtd/ubi/build.c +3 -3
@@ -1505,7 +1505,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) }module_param_call (mtd, ubi_mtd_param_parse,NULL ,NULL ,0400 ); -MODULE_PARM_DESC (mtd,"MTD devices to attach. Parameter format: mtd=<name|num|path>[,<vid_hdr_offs>[,max_beb_per1024[,ubi_num]]].\n" +MODULE_PARM_DESC (mtd,"MTD devices to attach. Parameter format: mtd=<name|num|path>[,<vid_hdr_offs>[,max_beb_per1024[,ubi_num[,enable_fm[,need_resv_pool]]]]].\n" "Multiple \"mtd\" parameters may be specified.\n" "MTD devices may be specified by their number, name, or path to the MTD character device node.\n" "Optional \"vid_hdr_offs\" parameter specifies UBI VID header position to be used by UBI. (default value if 0)\n"
@@ -1518,9 +1518,9 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa"Example 1: mtd=/dev/mtd0 - attach MTD device /dev/mtd0.\n" "Example 2: mtd=content,1984 mtd=4 - attach MTD device with name \"content\" using VID header offset 1984, and MTD device number 4 with default VID header offset.\n" "Example 3: mtd=/dev/mtd1,0,25 - attach MTD device /dev/mtd1 using default VID header offset and reserve 25*nand_size_in_blocks/1024 erase blocks for bad block handling.\n" +"\t(e.g. if the NAND *chipset* has 4096 PEB, 100 will be reserved for this UBI device).\n" "Example 4: mtd=/dev/mtd1,0,0,5 - attach MTD device /dev/mtd1 to UBI 5 and using default values for the other fields.\n" -"example 5: mtd=1,0,0,5 mtd=2,0,0,6,1 - attach MTD device /dev/mtd1 to UBI 5 and disable fastmap; attach MTD device /dev/mtd2 to UBI 6 and enable fastmap.(only works when fastmap is enabled and fm_autoconvert=Y).\n" - "\t(e.g. if the NAND *chipset* has 4096 PEB, 100 will be reserved for this UBI device)."); + "example 5: mtd=1,0,0,5 mtd=2,0,0,6,1 - attach MTD device /dev/mtd1 to UBI 5 and disable fastmap; attach MTD device /dev/mtd2 to UBI 6 and enable fastmap.(only works when fastmap is enabled and fm_autoconvert=Y).\n");#ifdef CONFIG_MTD_UBI_FASTMAP module_param (fm_autoconvert, bool,0644 );MODULE_PARM_DESC (fm_autoconvert,"Set this parameter to enable fastmap automatically on images without a fastmap." );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1191/1424 kunit: tool: fix _list_tests filtering wrong variable when list has TAP prefix
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohammad Abu-Khader <[email protected]>
[ Upstream commit dea754ded9518b51740c417d2c1e02ff540784c6 ]
_list_tests() runs the kernel to list tests, strips printk timestamp lines via extract_tap_lines(), then drops the dummy TAP header from the cleaned lines. However the subsequent regex filter mistakenly operates on the original output instead of the cleaned lines. When the kernel output includes timestamp prefixes (common with UML or slower setups), e.g.:
[ 0.100000] suite.test1 [ 0.100000] suite.test2
the anchored regex ^[^\s.]+\.[^\s.]+$ rejects them and --list_tests returns an empty list.
Filter lines instead of output, matching the behavior of the adjacent _list_tests_attr() which already returns the cleaned list.
Add a regression test with timestamp-prefixed input to verify the fix.
--- tools/testing/kunit/kunit.py | 2 +- tools/testing/kunit/kunit_tool_test.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-)
tools/testing/kunit/kunit.py +1 -1
@@ -121,7 +121,7 @@ def _list_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) lines.pop() # Filter out any extraneous non-test output that might have gotten mixed in. - return [l for l in output if re.match(r'^[^\s.]+\.[^\s.]+$', l)] + return [l for l in lines if re.match(r'^[^\s.]+\.[^\s.]+$', l)] def _list_tests_attr(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> Iterable[str]: args = ['kunit.action=list_attr']
tools/testing/kunit/kunit_tool_test.py +12 -0
@@ -826,6 +826,18 @@ class KUnitMainTest(unittest.TestCase): self.linux_source_mock.run_kernel.assert_called_once_with( args=['kunit.action=list'], build_dir='.kunit', filter_glob='suite*', filter='', filter_action=None, timeout=300) + def test_list_tests_with_prefix(self): + want = ['suite.test1', 'suite.test2', 'suite2.test1'] + self.linux_source_mock.run_kernel.return_value = [ + '[ 0.100000] TAP version 14', + '[ 0.200000] suite.test1', + '[ 0.200000] suite.test2', + '[ 0.300000] suite2.test1'] + + got = kunit._list_tests(self.linux_source_mock, + kunit.KunitExecRequest(None, None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False, False)) + self.assertEqual(got, want) + @mock.patch.object(kunit, '_list_tests') def test_run_isolated_by_suite(self, mock_tests): mock_tests.return_value = ['suite.test1', 'suite.test2', 'suite2.test1']
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1192/1424 selftests/bpf: Limit URLS parsing logic to actual scope in vmtest
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 0c3fc330be6d85febd0f68b66c657c752e9cd63c ]
The URLS array is only valid in the download_rootfs function and does not need to be parsed globally in advance. At the same time, the logic of loading rootfs is refactored to prepare vmtest for supporting local rootfs.
Stable-dep-of: 3a59f11e0f98 ("selftests/bpf: vmtest.sh: Preserve command quoting when running in the VM")
--- tools/testing/selftests/bpf/vmtest.sh | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-)
tools/testing/selftests/bpf/vmtest.sh +19 -20
@@ -90,19 +90,6 @@ populate_url_map() fi } -download() -{ - local file="$1" - - if [[ ! -v URLS[$file] ]]; then - echo "$file not found" >&2 - return 1 - fi - - echo "Downloading $file..." >&2 - curl -Lsf "${URLS[$file]}" "${@:2}" -} - newest_rootfs_version() { {
@@ -116,16 +103,30 @@ newest_rootfs_version() download_rootfs() { - local rootfsversion="$1" - local dir="$2" + populate_url_map + + local rootfsversion="$(newest_rootfs_version)" + local file="${ARCH}/libbpf-vmtest-rootfs-$rootfsversion.tar.zst" + + if [[ ! -v URLS[$file] ]]; then + echo "$file not found" >&2 + return 1 + fi + + echo "Downloading $file..." >&2 + curl -Lsf "${URLS[$file]}" "${@:2}" +} + +load_rootfs() +{ + local dir="$1" if ! which zstd &> /dev/null; then echo 'Could not find "zstd" on the system, please install zstd' exit 1 fi - download "${ARCH}/libbpf-vmtest-rootfs-$rootfsversion.tar.zst" | - zstd -d | sudo tar -C "$dir" -x + download_rootfs | zstd -d | sudo tar -C "$dir" -x } recompile_kernel()
@@ -225,7 +226,7 @@ create_vm_image() mkfs.ext4 -q "${rootfs_img}" mount_image - download_rootfs "$(newest_rootfs_version)" "${mount_dir}" + load_rootfs "${mount_dir}" unmount_image }
@@ -400,8 +401,6 @@ main() make_command="${make_command} KBUILD_OUTPUT=${KBUILD_OUTPUT}" fi - populate_url_map - local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}" local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1193/1424 selftests/bpf: Support local rootfs image for vmtest
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 2294073dce32af8535e9d4a32e1efdeea35c1786 ]
Support vmtest to use local rootfs image generated by [0] that is consistent with BPF CI. Now we can specify the local rootfs image through the -l parameter like as follows:
vmtest.sh -l ./libbpf-vmtest-rootfs-2024.08.22-noble-amd64.tar.zst -- ./test_progs
Meanwhile, some descriptions have been flushed.
Stable-dep-of: 3a59f11e0f98 ("selftests/bpf: vmtest.sh: Preserve command quoting when running in the VM")
--- tools/testing/selftests/bpf/README.rst | 2 -- tools/testing/selftests/bpf/vmtest.sh | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-)
tools/testing/selftests/bpf/README.rst +0 -2
@@ -85,8 +85,6 @@ In case of linker errors when running selftests, try using static linking: If you want to change pahole and llvm, you can change `PATH` environment variable in the beginning of script. -.. note:: The script currently only supports x86_64 and s390x architectures. - Additional information about selftest failures are documented here.
tools/testing/selftests/bpf/vmtest.sh +16 -5
@@ -4,9 +4,11 @@ set -u set -e -# This script currently only works for x86_64 and s390x, as -# it is based on the VM image used by the BPF CI, which is -# available only for these architectures. +# This script currently only works for the following platforms, +# as it is based on the VM image used by the BPF CI, which is +# available only for these architectures. We can also specify +# the local rootfs image generated by the following script: +# https://github.com/libbpf/ci/blob/main/rootfs/mkrootfs_debian.sh ARCH="$(uname -m)" case "${ARCH}" in s390x)
@@ -34,6 +36,7 @@ aarch64) esac DEFAULT_COMMAND="./test_progs" MOUNT_DIR="mnt" +LOCAL_ROOTFS_IMAGE="" ROOTFS_IMAGE="root.img" OUTPUT_DIR="$HOME/.bpf_selftests" KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config" "tools/testing/selftests/bpf/config.${ARCH}")
@@ -67,6 +70,7 @@ or Options: + -l) Specify the path to the local rootfs image. -i) Update the rootfs image with a newer version. -d) Update the output directory (default: ${OUTPUT_DIR}) -j) Number of jobs for compilation, similar to -j in make
@@ -126,7 +130,11 @@ load_rootfs() exit 1 fi - download_rootfs | zstd -d | sudo tar -C "$dir" -x + if [[ -n "${LOCAL_ROOTFS_IMAGE}" ]]; then + cat "${LOCAL_ROOTFS_IMAGE}" | zstd -d | sudo tar -C "$dir" -x + else + download_rootfs | zstd -d | sudo tar -C "$dir" -x + fi } recompile_kernel()
@@ -340,8 +348,11 @@ main() local exit_command="poweroff -f" local debug_shell="no" - while getopts ':hskid:j:' opt; do + while getopts ':hskl:id:j:' opt; do case ${opt} in + l) + LOCAL_ROOTFS_IMAGE="$OPTARG" + ;; i) update_image="yes" ;;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1194/1424 selftests/bpf: Add description for running vmtest on RV64
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 95b1c5d17832f61d0438cd5060a997bafaf75f2c ]
Add description in tools/testing/selftests/bpf/README.rst for running vmtest on RV64.
Stable-dep-of: 3a59f11e0f98 ("selftests/bpf: vmtest.sh: Preserve command quoting when running in the VM")
--- tools/testing/selftests/bpf/README.rst | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
tools/testing/selftests/bpf/README.rst +32 -0
@@ -85,6 +85,38 @@ In case of linker errors when running selftests, try using static linking: If you want to change pahole and llvm, you can change `PATH` environment variable in the beginning of script. +Running vmtest on RV64 +====================== +To speed up testing and avoid various dependency issues, it is recommended to +run vmtest in a Docker container. Before running vmtest, we need to prepare +Docker container and local rootfs image. The overall steps are as follows: + +1. Create Docker container as shown in link [0]. + +2. Use mkrootfs_debian.sh script [1] to build local rootfs image: + +.. code-block:: console + + $ sudo ./mkrootfs_debian.sh --arch riscv64 --distro noble + +3. Start Docker container [0] and run vmtest in the container: + +.. code-block:: console + + $ PLATFORM=riscv64 CROSS_COMPILE=riscv64-linux-gnu- \ + tools/testing/selftests/bpf/vmtest.sh \ + -l <path of local rootfs image> -- \ + ./test_progs -d \ + \"$(cat tools/testing/selftests/bpf/DENYLIST.riscv64 \ + | cut -d'#' -f1 \ + | sed -e 's/^[[:space:]]*//' \ + -e 's/[[:space:]]*$//' \ + | tr -s '\n' ',' \ + )\" + +Link: https://github.com/pulehui/riscv-bpf-vmtest.git [0] +Link: https://github.com/libbpf/ci/blob/main/rootfs/mkrootfs_debian.sh [1] + Additional information about selftest failures are documented here.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1195/1424 selftests/bpf: vmtest.sh: Preserve command quoting when running in the VM
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vineet Gupta <[email protected]>
[ Upstream commit 3a59f11e0f989bdd637c87151992605a6559a7cb ]
vmtest.sh captures the trailing command with command="$@", which flattens the arguments into a single space-separated string, and then pastes it into the generated guest init script:
cd /root/bpf
echo ${command}
stdbuf -oL -eL ${command}That here-doc is unquoted, so the host expands ${command} and the flattened text lands in the script verbatim. The guest bash then parses those lines as shell source, re-splitting the text on whitespace and glob-expanding it against /root/bpf. As a result any command with a glob or an argument containing spaces is corrupted before it reaches the test binary. For example:
vmtest.sh -- ./test_progs -a 'verifier_*'
has 'verifier_*' expanded in the guest into the matching object/skeleton files (verifier_align.bpf.o verifier_align.skel.h ...), so test_progs is handed a list of filenames instead of the intended name filter and runs no matching tests.
Quote each argument with printf '%q ' so the command is reproduced verbatim inside the VM: the escaped text goes through exactly one round of quote removal when the guest parses the init script, yielding the original argv with globs and special characters intact. The common case (e.g. -t <name>) is unaffected.
Only do this when there is a command to quote. printf '%q ' with no arguments still applies the format once and emits '', which the -s (debug shell) path would take for a real command and try to run.
Note this makes the trailing command strictly an argv rather than a shell
snippet: passing it pre-quoted as one word, e.g.
vmtest.sh -- "./test_progs -t foo"
no longer works, and neither does embedding guest-side shell syntax such as ';' or a redirection. 'sh -c ...' still works.
The RV64 recipe in README.rst does depend on the old double parse: it wraps the denylist in \" so the literal quotes reach the guest, whose second parse of the init script removes them. Under %q those quotes now survive into argv, and parse_test_list() strtok_r()s on ',' turns them into junk filters:
-d ",exceptions," -> ["] [exceptions] ["]
That is harmless for DENYLIST.riscv64 only because its first line is a comment, so the leading field is empty. A denylist starting with a real entry would silently lose it - ["*arena*] never matches - so drop the backslashes and let the host consume the quotes instead.
--- tools/testing/selftests/bpf/README.rst | 4 ++-- tools/testing/selftests/bpf/vmtest.sh | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/README.rst +2 -2
@@ -107,12 +107,12 @@ Docker container and local rootfs image. The overall steps are as follows: tools/testing/selftests/bpf/vmtest.sh \ -l <path of local rootfs image> -- \ ./test_progs -d \ - \"$(cat tools/testing/selftests/bpf/DENYLIST.riscv64 \ + "$(cat tools/testing/selftests/bpf/DENYLIST.riscv64 \ | cut -d'#' -f1 \ | sed -e 's/^[[:space:]]*//' \ -e 's/[[:space:]]*$//' \ | tr -s '\n' ',' \ - )\" + )" Link: https://github.com/pulehui/riscv-bpf-vmtest.git [0] Link: https://github.com/libbpf/ci/blob/main/rootfs/mkrootfs_debian.sh [1]
tools/testing/selftests/bpf/vmtest.sh +11 -2
@@ -389,8 +389,17 @@ main() if [[ $# -eq 0 && "${debug_shell}" == "no" ]]; then echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" - else - command="$@" + elif [[ $# -gt 0 ]]; then + # Quote each argument so the command survives into the guest: the + # host expands ${command} into the generated init script, which + # the guest bash then parses as shell source. Without the %q + # escapes an argument with a space or a glob (e.g. -a 'verifier_*') + # is re-split and expanded against /root/bpf there. + # + # Skip this when there is no command: printf '%q ' would still + # apply the format once and emit '', which is not the empty + # command that -s (debug shell) expects. + command=$(printf '%q ' "$@") fi local kconfig_file="${OUTPUT_DIR}/latest.config"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1196/1424 spi: img-spfi: dont disable runtime PM on DMA deferred probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 923e41ed59511cffe98357c7d58d0294a1c157ee ]
When dma_request_chan() returns -EPROBE_DEFER, the error path jumps to disable_pm and calls pm_runtime_disable() even though pm_runtime_enable() was never called, leaving disable_depth unbalanced and the device permanently PM-disabled.
Route the defer path through free_dma to skip pm_runtime_disable().
--- drivers/spi/spi-img-spfi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/spi/spi-img-spfi.c +3 -2
@@ -616,7 +616,7 @@ static int img_spfi_probe(struct platform_device *pdev) ret =PTR_ERR (spfi->tx_ch); spfi->tx_ch =NULL ;if (ret == -EPROBE_DEFER ) - goto disable_pm; + goto free_dma; } spfi->rx_ch =dma_request_chan (spfi->dev,"rx" );
@@ -624,7 +624,7 @@ static int img_spfi_probe(struct platform_device *pdev) ret =PTR_ERR (spfi->rx_ch); spfi->rx_ch =NULL ;if (ret == -EPROBE_DEFER ) - goto disable_pm; + goto free_dma; }if (!spfi->tx_ch || !spfi->rx_ch) {
@@ -652,6 +652,7 @@ static int img_spfi_probe(struct platform_device *pdev) disable_pm:pm_runtime_disable (spfi->dev); +free_dma:if (spfi->rx_ch)dma_release_channel (spfi->rx_ch);if (spfi->tx_ch)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1197/1424 power: supply: bd99954: Drop bad register fields
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matti Vaittinen <[email protected]>
[ Upstream commit 177299384a224377b4152242d875e752e5958c02 ]
The bd99954 driver creates regmap fields for all the registers. All the fields for VBUS_UCD_FCTRL_SET (extended command 0x33) are accidentally created for VCC_UCD_FCTRL_SET (extended command 0x2b), causing all reads/writes for the fields to access wrong register. Luckily the fields for VBUS_UCD_FCTRL_SET are unused.
Taking a look at the data-sheet all the fields in the VBUS_UCD_FCTRL_SET are marked as: "In normal operation, please don’t set these registers" with not much of additional documentation. As the fields are wrong and because there seems to be no users of the fields - it is better to just drop them. This will also decrease the memory footprint.
Drop incorrect VBUS_UCD_FCTRL_SET fields.
Datasheet: https://fscdn.rohm.com/en/products/databook/datasheet/ic/power/battery_management/bd99954xxx-e.pdf
--- drivers/power/supply/bd99954-charger.h | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-)
drivers/power/supply/bd99954-charger.h +1 -22
@@ -279,17 +279,7 @@ enum bd9995x_fields {F_VBUS_EXTID ,F_VBUS_IDRDET ,F_VBUS_INDO , -F_VBUS_UCDSWEN , -F_VBUS_RREF_EN , -F_VBUS_DPPU_EN , -F_VBUS_DPREF_EN , -F_VBUS_DMREF_EN , -F_VBUS_DPDET_EN , -F_VBUS_DMDET_EN , -F_VBUS_DPSINK_EN , -F_VBUS_DMSINK_EN , -F_VBUS_DP_BUFF_EN , -F_VBUS_DM_BUFF_EN , +F_VBUS_EXTCLKENBL ,F_VBUS_PLSTESTEN , F_VBUS_UCDSWEN_TSTENB,
@@ -626,17 +616,6 @@ static const struct reg_field bd9995x_reg_fields[] = { [F_VBUS_EXTID] = REG_FIELD(VBUS_IDD_STATUS, 5, 5), [F_VBUS_IDRDET] = REG_FIELD(VBUS_IDD_STATUS, 4, 4), [F_VBUS_INDO] = REG_FIELD(VBUS_IDD_STATUS, 0, 3), - [F_VBUS_UCDSWEN] = REG_FIELD(VCC_UCD_FCTRL_SET, 10, 10), - [F_VBUS_RREF_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 9, 9), - [F_VBUS_DPPU_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 8, 8), - [F_VBUS_DPREF_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 7, 7), - [F_VBUS_DMREF_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 6, 6), - [F_VBUS_DPDET_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 5, 5), - [F_VBUS_DMDET_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 4, 4), - [F_VBUS_DPSINK_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 3, 3), - [F_VBUS_DMSINK_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 2, 2), - [F_VBUS_DP_BUFF_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 1, 1), - [F_VBUS_DM_BUFF_EN] = REG_FIELD(VCC_UCD_FCTRL_SET, 0, 0), [F_VBUS_EXTCLKENBL] = REG_FIELD(VBUS_UCD_FCTRL_EN, 15, 15), [F_VBUS_PLSTESTEN] = REG_FIELD(VBUS_UCD_FCTRL_EN, 14, 14),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1198/1424 power: supply: bq27xxx: bq27520g4: fix REG_TTES address
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrik Grimler <[email protected]>
[ Upstream commit c774a623c821a173c950e1297f8e8c85a89455be ]
According to the technical reference manual the StandbyTimeToEmpty (TTES) register is at 0x1a, not 0x1c. At 0x1c StateOfHealth instead resides.
--- drivers/power/supply/bq27xxx_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery.c +1 -1
@@ -324,7 +324,7 @@ static u8 [BQ27XXX_REG_FLAGS] = 0x0a, [BQ27XXX_REG_TTE] = 0x16, [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTES] = 0x1a, [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, [BQ27XXX_REG_NAC] = 0x0c, [BQ27XXX_REG_RC] = 0x10,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1199/1424 power: supply: bq27xxx: bq28z610: fix invalid AverageEnergy address
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrik Grimler <[email protected]>
[ Upstream commit e9387e9ab5121f330d313afb90430c02200f9782 ]
bq28z610 currently uses the AveragePower reg, 0x22, for reading both AveragePower and AvailableEnergy. The technical reference manual does not mention AvailableEnergy, and it does not make sense to read a cumulative, always positive, property like AvailableEnergy from a rate property like AveragePower. Set REG_AE as invalid to fix it.
--- drivers/power/supply/bq27xxx_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery.c +1 -1
@@ -510,7 +510,7 @@ static u8 [BQ27XXX_REG_RC] = 0x10, [BQ27XXX_REG_FCC] = 0x12, [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, [BQ27XXX_REG_SOC] = 0x2c, [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = 0x22,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1200/1424 power: supply: bq27xxx: bq27z561: fix invalid AverageEnergy address
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrik Grimler <[email protected]>
[ Upstream commit 2da28b059e0ddcd2e1956eeae383246207965573 ]
bq27z561 currently uses the AveragePower reg, 0x22, for reading both AveragePower and AvailableEnergy. The technical reference manual does not mention AvailableEnergy, and it does not make sense to read a cumulative, always positive, property like AvailableEnergy from a rate property like AveragePower. Set REG_AE as invalid to fix it.
--- drivers/power/supply/bq27xxx_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery.c +1 -1
@@ -489,7 +489,7 @@ static u8 [BQ27XXX_REG_RC] = 0x10, [BQ27XXX_REG_FCC] = 0x12, [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, [BQ27XXX_REG_SOC] = 0x2c, [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = 0x22,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1201/1424 xenbus: Unregister reboot notifier on init failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit d330fb86a7170f845123ae82d95df440fad9b707 ]
xs_init() registers xs_reboot_nb before initializing XenStore communications and starting xenwatch. If either operation fails, the notifier remains registered and a later initialization attempt can hit a duplicate registration.
Check the notifier registration result and unregister it on every subsequent failure path.
Message-ID: <[email protected]>
--- drivers/xen/xenbus/xenbus_xs.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/xen/xenbus/xenbus_xs.c +12 -4
@@ -952,19 +952,27 @@ int xs_init(void)int err;struct task_struct *task; -register_reboot_notifier (&xs_reboot_nb); + err =register_reboot_notifier (&xs_reboot_nb); +if (err) +return err;/* Initialize the shared memory rings to talk to xenstored */ err =xb_init_comms ();if (err) -return err; + goto err_unregister_reboot_notifier; task =kthread_run (xenwatch_thread,NULL ,"xenwatch" ); -if (IS_ERR (task)) -return PTR_ERR (task); +if (IS_ERR (task)) { + err =PTR_ERR (task); + goto err_unregister_reboot_notifier; + }/* shutdown watches for kexec boot */ xs_reset_watches ();return 0 ; + +err_unregister_reboot_notifier: +unregister_reboot_notifier (&xs_reboot_nb); +return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1202/1424 s390/debug: Fix deadlock during unregister
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Oberparleiter <[email protected]>
[ Upstream commit 445c31ac638fd1af203d79bdf25fc0cb3149fbbc ]
Unregistering an s390dbf debug area while one of the associated debugfs files is being written to can cause a deadlock:
$ echo >.../vmur/level $ rmmod vmur
===================================================
debugfs write
debugfs_file_get()
debug_unregister()
mutex_lock(debug_mutex)
debugfs_remove()
wait for debugfs_file_put()
debug_file_ops.write()
debug_input()
mutex_lock(debug_mutex) ==> DEADLOCKFix this by splitting debug_unregister() into an s390dbf and debugfs part, and running only the s390dbf part with debug_mutex locked.
--- arch/s390/kernel/debug.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/s390/kernel/debug.c +8 -2
@@ -747,8 +747,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)mutex_unlock (&debug_mutex); } -/* Remove debugfs entries and remove from internal list. */ -static void _debug_unregister (debug_info_t *id) +/* Remove debugfs entries. */ +static void _debug_unregister_debugfs (debug_info_t *id) {int i;
@@ -758,6 +758,11 @@ static void _debug_unregister(debug_info_t *id)debugfs_remove (id->debugfs_entries[i]); }debugfs_remove (id->debugfs_root_entry); +} + +/* Remove from internal list. */ +static void _debug_unregister (debug_info_t *id) +{if (id == debug_area_first) debug_area_first = id->next;if (id == debug_area_last)
@@ -783,6 +788,7 @@ void debug_unregister(debug_info_t *id)mutex_lock (&debug_mutex);_debug_unregister (id);mutex_unlock (&debug_mutex); +_debug_unregister_debugfs (id);debug_info_put (id); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1203/1424 clocksource/drivers/clps711x: Do not unmap clocksource MMIO
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit e998c6300ef4e062a704ee17b5a812c0b595cf42 ]
clps711x_clksrc_init() stores the timer base address in the static tcd pointer and registers it as both the clocksource MMIO address and the sched_clock read address.
The clocksource init path must therefore keep the mapping alive after clps711x_timer_init() returns. However, the shared unmap_io exit path is also reached after successful clocksource registration, so the MMIO mapping is torn down while the clocksource and sched_clock readers may still access it.
Return directly after successful clocksource registration and leave the mapping alive for the registered readers. Keep the unmap_io path for the error paths and for the clockevent init path.
--- drivers/clocksource/clps711x-timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/clps711x-timer.c +1 -1
@@ -94,7 +94,7 @@ static int __init clps711x_timer_init(struct device_node *np)switch (of_alias_get_id (np,"timer" )) {case CLPS711X_CLKSRC_CLOCKSOURCE :clps711x_clksrc_init (clock, base); -break ; +return 0 ;case CLPS711X_CLKSRC_CLOCKEVENT : ret =_clps711x_clkevt_init (clock, base, irq);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1204/1424 clocksource/drivers/armada: Unwind timer clock on init failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 8b4127f6db40381229f3564d34ac35f36311c201 ]
The Armada timer init paths enable their clock before calling the common initialization routine. If that routine returns an error, the clock is left enabled even though the timer was not initialized successfully.
--- drivers/clocksource/timer-armada-370-xp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
drivers/clocksource/timer-armada-370-xp.c +15 -3
@@ -346,7 +346,11 @@ static int __init armada_xp_timer_init(struct device_node *np) timer_clk =clk_get_rate (clk); -return armada_370_xp_timer_common_init (np); + ret =armada_370_xp_timer_common_init (np); +if (ret) +clk_disable_unprepare (clk); + +return ret; }TIMER_OF_DECLARE (armada_xp,"marvell,armada-xp-timer" , armada_xp_timer_init);
@@ -384,7 +388,11 @@ static int __init armada_375_timer_init(struct device_node *np) timer25Mhz = false; } -return armada_370_xp_timer_common_init (np); + ret =armada_370_xp_timer_common_init (np); +if (ret) +clk_disable_unprepare (clk); + +return ret; }TIMER_OF_DECLARE (armada_375,"marvell,armada-375-timer" , armada_375_timer_init);
@@ -407,7 +415,11 @@ static int __init armada_370_timer_init(struct device_node *np) timer_clk =clk_get_rate (clk) /TIMER_DIVIDER ; timer25Mhz = false; -return armada_370_xp_timer_common_init (np); + ret =armada_370_xp_timer_common_init (np); +if (ret) +clk_disable_unprepare (clk); + +return ret; }TIMER_OF_DECLARE (armada_370,"marvell,armada-370-timer" , armada_370_timer_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1205/1424 ALSA: seq: midi: Optimize event_input locking with RCU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit 4cc25cdd3cffa475edb8dec8199b3227038ebcfb ]
The recent fix for serializing the output teardown introduced a spinlock invocation at every MIDI output event via event_process_midi. Since this is a hot path, let's do performance optimization with RCU.
The new output_substream __rcu pointer is published via rcu_assign_pointer() in midisynth_use() after output_rfile is set, and cleared in midisynth_unuse() before the resource teardown. event_process_midi() reads it under rcu_read_lock() and bumps output_use_lock inside that section, which is necessary to close the window between the pointer dereference and the refcount increment.
midisynth_unuse() calls synchronize_rcu() before snd_use_lock_sync():
this guarantees that any reader who obtained a non-NULL pointer has already called atomic_inc (output_use_lock), so the subsequent snd_use_lock_sync() sees the correct in-flight count.
--- sound/core/seq/seq_midi.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-)
sound/core/seq/seq_midi.c +11 -13
@@ -43,8 +43,8 @@ struct seq_midisynth {int device;int subdevice;struct snd_rawmidi_file input_rfile; -spinlock_t output_lock;/* protects output_rfile publication */ snd_use_lock_t output_use_lock;/* in-flight event_input users */ +struct snd_rawmidi_substream __rcu *output_substream;struct snd_rawmidi_file output_rfile;int seq_client;int seq_port;
@@ -134,8 +134,8 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,if (snd_BUG_ON (!msynth))return -EINVAL ; - scoped_guard(spinlock_irqsave, &msynth->output_lock) { - substream = msynth->output_rfile.output; +scoped_guard (rcu) { + substream =rcu_dereference (msynth->output_substream);if (!substream)return -ENODEV ;snd_use_lock_use (&msynth->output_use_lock);
@@ -177,7 +177,6 @@ static int snd_seq_midisynth_new(struct seq_midisynth *msynth, msynth->card = card; msynth->device = device; msynth->subdevice = subdevice; -spin_lock_init (&msynth->output_lock);snd_use_lock_init (&msynth->output_use_lock);return 0 ; }
@@ -252,8 +251,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *inforeturn err; }snd_midi_event_reset_decode (msynth->parser); -scoped_guard (spinlock_irqsave, &msynth->output_lock) - msynth->output_rfile = rfile; + msynth->output_rfile = rfile; +rcu_assign_pointer (msynth->output_substream, rfile.output);return 0 ; }
@@ -261,17 +260,16 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *infostatic int midisynth_unuse (void *private_data,struct snd_seq_port_subscribe *info) {struct seq_midisynth *msynth = private_data; -struct snd_rawmidi_file rfile = {}; +struct snd_rawmidi_file rfile; - scoped_guard(spinlock_irqsave, &msynth->output_lock) { - rfile = msynth->output_rfile; - msynth->output_rfile = (struct snd_rawmidi_file ){}; - } +rcu_assign_pointer (msynth->output_substream,NULL ); +synchronize_rcu (); +snd_use_lock_sync (&msynth->output_use_lock); + rfile = msynth->output_rfile; + msynth->output_rfile = (struct snd_rawmidi_file ){};if (snd_BUG_ON (!rfile.output))return -EINVAL ; - -snd_use_lock_sync (&msynth->output_use_lock);snd_rawmidi_drain_output (rfile.output);return snd_rawmidi_kernel_release (&rfile); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1206/1424 ALSA: seq: midi: Serialize input teardown with event_input
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Keeping <[email protected]>
[ Upstream commit 403f7f3ad3808a0096d84cf228fab68dc253fd9d ]
snd_midi_input_event() must not be running while a rawmidi substream is closing, since this can lead to the trigger state becoming out-of-step through this sequence in snd_rawmidi_input_trigger():
snd_rawmidi_input_trigger(up=0) snd_midi_input_event() -> snd_rawmidi_kernel_read() -> snd_rawmidi_input_trigger(up=1) -> cancel_work_sync()
which ends with the underlying device being active unexpectedly.
When this is called from close_substream(), further input can re-trigger the input event leaving it running after rawmidi_release_priv() has set rfile->rmidi to NULL which leads to:
Unable to handle kernel NULL pointer dereference at virtual address 00000000000000b0 Call trace: snd_midi_input_event+0x3c/0x134 [snd_seq_midi] (P) snd_rawmidi_input_event_work+0x1c/0x2c process_one_work+0x150/0x3a4 worker_thread+0x190/0x318
Apply a similar approach to commit ef7607ab1c8ad ("ALSA: seq: midi:
Serialize output teardown with event_input") which fixed the same issue in the output direction, but updated to use RCU following Takashi Iwai's proposed follow-on patch [1].
With this change in place, midisynth_unsubscribe() clears the input file so snd_midi_input_event() will not re-trigger the stream and will be quiesced by the cancel_work_sync() in snd_rawmidi_input_trigger().
[1] https://lore.kernel.org/linux-sound/[email protected]/
--- sound/core/seq/seq_midi.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-)
sound/core/seq/seq_midi.c +31 -6
@@ -42,6 +42,8 @@ struct seq_midisynth {struct snd_rawmidi *rmidi;int device;int subdevice; +struct snd_rawmidi_substream __rcu *input_substream; +snd_use_lock_t input_use_lock;/* in-flight event_input users */ struct snd_rawmidi_file input_rfile;snd_use_lock_t output_use_lock;/* in-flight event_input users */ struct snd_rawmidi_substream __rcu *output_substream;
@@ -76,6 +78,14 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) msynth = runtime->private_data;if (msynth ==NULL )return ; + +scoped_guard (rcu) { +if (rcu_dereference (msynth->input_substream) != substream) +return ; + +snd_use_lock_use (&msynth->input_use_lock); + } +memset (&ev,0 ,sizeof (ev));while (runtime->avail >0 ) { res =snd_rawmidi_kernel_read (substream, buf,sizeof (buf));
@@ -95,6 +105,8 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream)memset (&ev,0 ,sizeof (ev)); } } + +snd_use_lock_free (&msynth->input_use_lock); }static int dump_midi (struct snd_rawmidi_substream *substream,const char *buf,int count)
@@ -177,6 +189,7 @@ static int snd_seq_midisynth_new(struct seq_midisynth *msynth, msynth->card = card; msynth->device = device; msynth->subdevice = subdevice; +snd_use_lock_init (&msynth->input_use_lock);snd_use_lock_init (&msynth->output_use_lock);return 0 ; }
@@ -187,28 +200,31 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribeint err;struct seq_midisynth *msynth = private_data;struct snd_rawmidi_runtime *runtime; +struct snd_rawmidi_file rfile = {};struct snd_rawmidi_params params;/* open midi port */ err =snd_rawmidi_kernel_open (msynth->rmidi, msynth->subdevice,SNDRV_RAWMIDI_LFLG_INPUT , - &msynth->input_rfile); + &rfile);if (err <0 ) {pr_debug ("ALSA: seq_midi: midi input open failed!!!\n" );return err; } - runtime = msynth->input_rfile.input->runtime; + runtime = rfile.input->runtime;memset (¶ms,0 ,sizeof (params)); params.avail_min =1 ; params.buffer_size = input_buffer_size; - err =snd_rawmidi_input_params (msynth->input_rfile.input, ¶ms); + err =snd_rawmidi_input_params (rfile.input, ¶ms);if (err <0 ) { -snd_rawmidi_kernel_release (&msynth->input_rfile); +snd_rawmidi_kernel_release (&rfile);return err; }snd_midi_event_reset_encode (msynth->parser); runtime->event = snd_midi_input_event; runtime->private_data = msynth; + msynth->input_rfile = rfile; +rcu_assign_pointer (msynth->input_substream, rfile.input);snd_rawmidi_kernel_read (msynth->input_rfile.input,NULL ,0 );return 0 ; }
@@ -218,10 +234,19 @@ static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscri {int err;struct seq_midisynth *msynth = private_data; +struct snd_rawmidi_file rfile; -if (snd_BUG_ON (!msynth->input_rfile.input)) +rcu_assign_pointer (msynth->input_substream,NULL ); +synchronize_rcu (); +snd_use_lock_sync (&msynth->input_use_lock); + + rfile = msynth->input_rfile; + msynth->input_rfile = (struct snd_rawmidi_file ){}; + +if (snd_BUG_ON (!rfile.input))return -EINVAL ; - err =snd_rawmidi_kernel_release (&msynth->input_rfile); + + err =snd_rawmidi_kernel_release (&rfile);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1207/1424 x86/pkeys: Fix pkey_alloc() return value when pkeys are not supported
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bijan Tabatabai <[email protected]>
[ Upstream commit dee87e09b0dd63da9b1e1876167ccae37842dfd0 ]
The man page for pkey_alloc(2) specifies that it should return -1 with the errno set to ENOSPC when pkeys are not supported [1]. However, on x86 pkey_alloc() sets errno to EINVAL when called for the first time on a CPU that does not support pkeys.
The root cause of this is the x86 implementation of mm_pkey_alloc() not directly checking if pkeys are supported. It only checks if all the pkeys have been allocated by comparing the allocation map against all_pkeys_mask. When OSPKE is not enabled, init_new_context() skips the initialization of the allocation map, leaving it as 0, while all_pkeys_mask is 1. mm_pkey_alloc() interprets this as there being a pkey available and it returns pkey 0. Then, pkey_alloc() fails with -EINVAL from arch_set_user_pkey_access() instead of returning -ENOSPC. Subsequent calls to pkey_alloc() do return -ENOSPC because pkey 0 is left marked as allocated.
Change mm_pkey_alloc() to directly check if OSPKE is enabled, and return -1 if it is not, which causes pkey_alloc() to return -ENOSPC. The arm64 and powerpc implementations of mm_pkey_alloc() already do this check.
[1] https://man7.org/linux/man-pages/man2/pkey_alloc.2.html
[ dhansen: use arch_pkeys_enabled() to follow arm ]
--- arch/x86/include/asm/pkeys.h | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/include/asm/pkeys.h +3 -0
@@ -89,6 +89,9 @@ int mm_pkey_alloc(struct mm_struct *mm)u16 all_pkeys_mask = ((1U <<arch_max_pkey ()) -1 );int ret; +if (!arch_pkeys_enabled ()) +return -1 ; +/* * Are we out of pkeys? We must handle this specially * because ffz() behavior is undefined if there are no
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1208/1424 bpftool: Fix double close in map dump
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuan Chen <[email protected]>
[ Upstream commit 259d60f5bfa41056fe01cbf2ba3f6f0331865a16 ]
map_dump() closes the map fd in its error path, and do_dump() then closes the same fd again after a successful dump. Closing an already closed fd leaves errno set to EBADF, which poisons later errno checks such as the batch file read check in do_batch(). Let do_dump() own the fd and remove the close from map_dump().
The same double-close pattern exists in do_show_subset(): both show_map_close_json() and show_map_close_plain() already close the fd, so drop the extra close() there as well.
Also propagate the error when bpf_map_get_info_by_fd() fails on a subsequent map in do_dump(): set err = -1 before breaking out of the loop, so a later failure is not silently hidden after an earlier iteration succeeded.
--- tools/bpf/bpftool/map.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
tools/bpf/bpftool/map.c +1 -3
@@ -659,8 +659,6 @@ static int do_show_subset(int argc, char **argv)show_map_close_json (fds[i], &info); else show_map_close_plain(fds[i], &info); - -close (fds[i]); }if (json_output && nb_fds >1 )jsonw_end_array (json_wtr);/* root array */
@@ -892,7 +890,6 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr, exit_free:free (key);free (value); -close (fd);free_map_kv_btf (btf);return err;
@@ -941,6 +938,7 @@ static int do_dump(int argc, char **argv)for (i =0 ; i < nb_fds; i++) {if (bpf_map_get_info_by_fd (fds[i], &info, &len)) {p_err ("can't get map info: %s" ,strerror (errno)); + err =-1 ;break ; } err =map_dump (fds[i], &info, wtr, nb_fds >1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1209/1424 ocfs2: fix circular locking dependency in ocfs2_init_acl()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krystian Kaniewski <[email protected]>
[ Upstream commit bd7c05fb4a4776dff5a87b19008d28458647d15d ]
A lockdep warning indicates a circular locking dependency between &oi->ip_xattr_sem and &journal->j_trans_barrier:
WARNING: possible circular locking dependency detected is trying to acquire lock:
(&oi->ip_xattr_sem){++++}-{4:4}, at: ocfs2_init_acl+0x2fd/0x7e0 fs/ocfs2/acl.c:367
but task is already holding lock:
(&journal->j_trans_barrier){.+.+}-{4:4}, at: ocfs2_start_trans+0x3ab/0x700 fs/ocfs2/journal.c:369
The deadlock involves two code paths: Path 1 (setxattr) where ocfs2_xattr_set() acquires ip_xattr_sem (write) and then starts a transaction, which acquires j_trans_barrier (read); and Path 2 (mkdir/mknod) where ocfs2_mknod() starts a transaction (j_trans_barrier read) and then calls ocfs2_init_acl(), which attempts to acquire ip_xattr_sem (read) on the parent directory to retrieve the default ACL.
Because rw_semaphores are subject to writer priority, a pending writer on j_trans_barrier (e.g., the journal commit thread) can cause Path 1 to block, while Path 2 is blocked waiting for Path 1 to release ip_xattr_sem.
The patch fixes the lock ordering by precomputing the ACL state before starting the OCFS2 transaction, while preserving POSIX ACL storage semantics and the existing inode/security initialization order. By reading the parent directory's default ACL and preparing the new inode's ACLs outside the transaction, ip_xattr_sem is always acquired before j_trans_barrier.
struct ocfs2_acl_state encapsulates the prepared ACL state, while ocfs2_acl_init_prepare() and ocfs2_acl_init_release() avoid code duplication between ocfs2_mknod() and ocfs2_init_security_and_acl(). ocfs2_calc_xattr_init() and ocfs2_init_acl() use this precomputed state, removing internal ip_xattr_sem acquisition and redundant disk reads.
Additionally, remove the ip_xattr_sem acquisition from ocfs2_xattr_set_handle(). This function is only used while initializing a new inode that has not yet been inserted into the inode hash or attached to a dentry, meaning there is no risk of concurrent access and the lock is unnecessary.
--- fs/ocfs2/acl.c | 135 ++++++++++++++++++++++++++++++----------------- fs/ocfs2/acl.h | 19 +++++-- fs/ocfs2/namei.c | 17 ++++-- fs/ocfs2/xattr.c | 86 ++++++++++++++++++------------ fs/ocfs2/xattr.h | 9 ++-- 5 files changed, 173 insertions(+), 93 deletions(-)
fs/ocfs2/acl.c +88 -47
@@ -109,8 +109,7 @@ static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)return ocfs2_acl; } -static struct posix_acl *ocfs2_get_acl_nolock (struct inode *inode, -int type, +static struct posix_acl *ocfs2_get_acl_nolock (struct inode *inode,int type,struct buffer_head *di_bh) {int name_index;
@@ -348,63 +347,105 @@ int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)* Initialize the ACLs of a new inode. If parent directory has default ACL, * then clone to new inode. Called from ocfs2_mknod. */ -int ocfs2_init_acl (handle_t *handle, -struct inode *inode, -struct inode *dir, -struct buffer_head *di_bh, -struct buffer_head *dir_bh, -struct ocfs2_alloc_context *meta_ac, -struct ocfs2_alloc_context *data_ac) +void ocfs2_acl_init_release (struct ocfs2_acl_state *state) +{ +posix_acl_release (state->default_acl); +posix_acl_release (state->acl); + state->default_acl =NULL ; + state->acl =NULL ; +} + +int ocfs2_acl_init_prepare (struct inode *inode,struct inode *dir, +struct buffer_head *dir_bh, +struct ocfs2_acl_state *state) {struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); -struct posix_acl *acl =NULL ; -int ret =0 , ret2; -umode_t mode; - -if (!S_ISLNK (inode->i_mode)) { -if (osb->s_mount_opt &OCFS2_MOUNT_POSIX_ACL ) { -down_read (&OCFS2_I (dir)->ip_xattr_sem); - acl =ocfs2_get_acl_nolock (dir,ACL_TYPE_DEFAULT , - dir_bh); -up_read (&OCFS2_I (dir)->ip_xattr_sem); -if (IS_ERR (acl)) -return PTR_ERR (acl); +int ret =0 ; + + state->default_acl =NULL ; + state->acl =NULL ; + state->mode = inode->i_mode; + +if (S_ISLNK (inode->i_mode)) +return 0 ; + +if (osb->s_mount_opt &OCFS2_MOUNT_POSIX_ACL ) { +down_read (&OCFS2_I (dir)->ip_xattr_sem); + state->default_acl = +ocfs2_get_acl_nolock (dir,ACL_TYPE_DEFAULT , dir_bh); +up_read (&OCFS2_I (dir)->ip_xattr_sem); +if (IS_ERR (state->default_acl)) { + ret =PTR_ERR (state->default_acl); + state->default_acl =NULL ; +return ret; } -if (!acl) { - mode = inode->i_mode & ~current_umask (); - ret =ocfs2_acl_set_mode (inode, di_bh, handle, mode); -if (ret) { -mlog_errno (ret); +if (state->default_acl) { + state->acl =posix_acl_dup (state->default_acl); +if (!state->acl) { + ret = -ENOMEM ; goto cleanup; } + ret =__posix_acl_create (&state->acl,GFP_NOFS , + &state->mode); +if (ret <0 ) + goto cleanup; +if (ret ==0 ) { +posix_acl_release (state->acl); + state->acl =NULL ; + } +if (!S_ISDIR (inode->i_mode)) { +posix_acl_release (state->default_acl); + state->default_acl =NULL ; + } + }else { + state->mode &= ~current_umask (); } + }else { + state->mode &= ~current_umask (); } -if ((osb->s_mount_opt &OCFS2_MOUNT_POSIX_ACL ) && acl) { -if (S_ISDIR (inode->i_mode)) { + +return 0 ; +cleanup: +ocfs2_acl_init_release (state); +return ret; +} + +int ocfs2_init_acl (handle_t *handle,struct inode *inode, +struct buffer_head *di_bh, +struct ocfs2_alloc_context *meta_ac, +struct ocfs2_alloc_context *data_ac, +struct ocfs2_acl_state *state) +{ +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +int ret =0 ; + +if (S_ISLNK (inode->i_mode)) +return 0 ; + +if (osb->s_mount_opt &OCFS2_MOUNT_POSIX_ACL ) { +if (S_ISDIR (inode->i_mode) && state->default_acl) { ret =ocfs2_set_acl (handle, inode, di_bh, -ACL_TYPE_DEFAULT , acl, - meta_ac, data_ac); +ACL_TYPE_DEFAULT , + state->default_acl, meta_ac, + data_ac);if (ret) - goto cleanup; +return ret; } - mode = inode->i_mode; - ret =__posix_acl_create (&acl,GFP_NOFS , &mode); -if (ret <0 ) -return ret; + } - ret2 =ocfs2_acl_set_mode (inode, di_bh, handle, mode); -if (ret2) { -mlog_errno (ret2); - ret = ret2; - goto cleanup; - } -if (ret >0 ) { - ret =ocfs2_set_acl (handle, inode, - di_bh,ACL_TYPE_ACCESS , - acl, meta_ac, data_ac); + ret =ocfs2_acl_set_mode (inode, di_bh, handle, state->mode); +if (ret) { +mlog_errno (ret); +return ret; + } + +if (osb->s_mount_opt &OCFS2_MOUNT_POSIX_ACL ) { +if (state->acl) { + ret =ocfs2_set_acl (handle, inode, di_bh, +ACL_TYPE_ACCESS , state->acl, + meta_ac, data_ac); } } -cleanup: -posix_acl_release (acl); +return ret; }
fs/ocfs2/acl.h +15 -4
@@ -20,9 +20,20 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu);int ocfs2_iop_set_acl (struct mnt_idmap *idmap,struct dentry *dentry,struct posix_acl *acl,int type);extern int ocfs2_acl_chmod (struct inode *,struct buffer_head *); -extern int ocfs2_init_acl (handle_t *,struct inode *,struct inode *, -struct buffer_head *,struct buffer_head *, -struct ocfs2_alloc_context *, -struct ocfs2_alloc_context *); +struct ocfs2_acl_state { +struct posix_acl *default_acl; +struct posix_acl *acl; +umode_t mode; +}; + +int ocfs2_acl_init_prepare (struct inode *inode,struct inode *dir, +struct buffer_head *dir_bh, +struct ocfs2_acl_state *state); +void ocfs2_acl_init_release (struct ocfs2_acl_state *state); +int ocfs2_init_acl (handle_t *handle,struct inode *inode, +struct buffer_head *di_bh, +struct ocfs2_alloc_context *meta_ac, +struct ocfs2_alloc_context *data_ac, +struct ocfs2_acl_state *state);#endif /* OCFS2_ACL_H */
fs/ocfs2/namei.c +12 -5
@@ -252,6 +252,7 @@ static int ocfs2_mknod(struct mnt_idmap *idmap,sigset_t oldset;int did_block_signals =0 ;struct ocfs2_dentry_lock *dl =NULL ; +struct ocfs2_acl_state acl_state = {0 }; trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno,
@@ -326,10 +327,14 @@ static int ocfs2_mknod(struct mnt_idmap *idmap, } } + status =ocfs2_acl_init_prepare (inode, dir, parent_fe_bh, &acl_state); +if (status <0 ) + goto leave; +/* calculate meta data/clusters for setting security and acl xattr */ - status =ocfs2_calc_xattr_init (dir, parent_fe_bh, mode, - &si, &want_clusters, - &xattr_credits, &want_meta); + status =ocfs2_calc_xattr_init (dir, mode, &si, &want_clusters, + &xattr_credits, &want_meta, + &acl_state);if (status <0 ) {mlog_errno (status); goto leave;
@@ -407,8 +412,8 @@ static int ocfs2_mknod(struct mnt_idmap *idmap,inc_nlink (dir); } - status =ocfs2_init_acl (handle, inode, dir, new_fe_bh, parent_fe_bh, - meta_ac, data_ac); + status =ocfs2_init_acl (handle, inode, new_fe_bh, meta_ac, data_ac, + &acl_state);if (status <0 ) {mlog_errno (status);
@@ -473,6 +478,8 @@ static int ocfs2_mknod(struct mnt_idmap *idmap,brelse (parent_fe_bh);kfree (si.value); +ocfs2_acl_init_release (&acl_state); +ocfs2_free_dir_lookup_result (&lookup);if (inode_ac)
fs/ocfs2/xattr.c +52 -34
138 lines not on this page · raw message
fs/ocfs2/xattr.h +6 -3
@@ -55,9 +55,12 @@ int ocfs2_init_security_set(handle_t *, struct inode *,int ocfs2_calc_security_init (struct inode *,struct ocfs2_security_xattr_info *,int *,int *,struct ocfs2_alloc_context **); -int ocfs2_calc_xattr_init (struct inode *,struct buffer_head *, -umode_t ,struct ocfs2_security_xattr_info *, -int *,int *,int *); + +struct ocfs2_acl_state ; +int ocfs2_calc_xattr_init (struct inode *dir,umode_t mode, +struct ocfs2_security_xattr_info *si, +int *want_clusters,int *xattr_credits, +int *want_meta,struct ocfs2_acl_state *acl_state);/* * xattrs can live inside an inode, as part of an external xattr block,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1210/1424 Squashfs: check block offset is not negative
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Phillip Lougher <[email protected]>
[ Upstream commit e300eb5002925b29be803d2661af07266cfa267e ]
If a negative offset is read off disk (for example the offset into the decompressed fragment block), this will cause squashfs_copy_data() to perform an out of bounds access.
Fix by checking if offset is negative, and returning 0. This matches existing behaviour where an offset beyond the block returns 0 bytes copied.
To trigger this out of bounds access requires a crafted Squashfs filesystem and CAP_SYS_ADMIN to mount it. Unprivileged users will not be able to mount such a filesystem, but once mounted, an unprivileged user can trigger the out of bounds access by reading the crafted file with the negative offset.
--- fs/squashfs/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/squashfs/cache.c +1 -1
@@ -295,7 +295,7 @@ int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry, {int remaining = length; -if (length ==0 ) +if (length ==0 || offset <0 )return 0 ;else if (buffer ==NULL )return min (length, entry->length - offset);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1211/1424 selftests/bpf: Fix for veristat file/prog filters processing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit 98d309ec8189fd91698d1a72946c3d888270c57e ]
At the moment veristat filtering behaves unexpectedly for the following filter expression:
-f !file/prog
The expression rejects all programs with name 'prog', and all programs in a file with name 'file'. This commit fixes the expression to exclude only a program 'prog' from a file 'file'. Additionally, the commit makes empty filters like '-f ""' or '-f "/"' and error. Here is the filtering behaviour compared old versus new:
| filter | file | prog | old verdict | new verdict | |----------+------+------+-------------+-------------| | !foo | foo | bar | skipped | skipped | | !foo | bar | foo | skipped | skipped | | !foo | bar | bar | processed | processed | | !foo/bar | foo | bar | skipped | skipped | | !foo/bar | foo | buz | skipped | processed | (!) | !foo/bar | bar | bar | skipped | processed | (!) | !foo/ | foo | bar | skipped | skipped | | !foo/ | bar | bar | processed | processed | | !/bar | foo | bar | skipped | skipped | | !/bar | foo | foo | processed | processed | | !/ | foo | bar | processed | error | (!) | ! | foo | bar | processed | error | (!) |----------+------+------+-------------+-------------| | foo | foo | bar | processed | processed | | foo | bar | foo | processed | processed | | foo | bar | bar | skipped | skipped | | foo/bar | foo | bar | processed | processed | | foo/bar | foo | buz | skipped | skipped | | foo/bar | bar | bar | skipped | skipped | | foo/ | foo | bar | processed | processed | | foo/ | bar | bar | skipped | skipped | | /bar | foo | bar | processed | processed | | /bar | foo | foo | skipped | skipped | | / | foo | bar | processed | error | (!) | | foo | bar | skipped | error | (!)
--- tools/testing/selftests/bpf/veristat.c | 76 +++++++++++++++++--------- 1 file changed, 49 insertions(+), 27 deletions(-)
tools/testing/selftests/bpf/veristat.c +49 -27
@@ -385,6 +385,40 @@ static bool is_bpf_obj_file(const char *path) {return err ==0 ; } +/* Exact filter match */ +static bool name_filter_matches (struct filter *f,const char *filename,const char *prog_name) +{ +if (f->any_glob) +return glob_matches (filename, f->any_glob) || + (prog_name &&glob_matches (prog_name, f->any_glob)); +if (f->file_glob && f->prog_glob) +return prog_name && +glob_matches (filename, f->file_glob) && +glob_matches (prog_name, f->prog_glob); +if (f->file_glob) +return glob_matches (filename, f->file_glob); +if (f->prog_glob) +return prog_name &&glob_matches (prog_name, f->prog_glob); +return false; +} + +/* Check if the filter does not outright reject the file name */ +static bool name_filter_may_match (struct filter *f,const char *filename) +{ +if (f->file_glob) +return glob_matches (filename, f->file_glob); +/* +* If we don't know program name yet, any_glob filter +* has to assume that current BPF object file might be +* relevant; we'll check again later on after opening +* BPF object file, at which point program name will +* be known finally. +*/ +if (f->any_glob || f->prog_glob) +return true; +return false; +} +static bool should_process_file_prog (const char *filename,const char *prog_name) {struct filter *f;
@@ -392,16 +426,7 @@ static bool should_process_file_prog(const char *filename, const char *prog_namefor (i =0 ; i < env.deny_filter_cnt; i++) { f = &env.deny_filters[i]; -if (f->kind !=FILTER_NAME ) -continue ; - -if (f->any_glob &&glob_matches (filename, f->any_glob)) -return false; -if (f->any_glob && prog_name &&glob_matches (prog_name, f->any_glob)) -return false; -if (f->file_glob &&glob_matches (filename, f->file_glob)) -return false; -if (f->prog_glob && prog_name &&glob_matches (prog_name, f->prog_glob)) +if (f->kind ==FILTER_NAME &&name_filter_matches (f, filename, prog_name))return false; }
@@ -411,24 +436,15 @@ static bool should_process_file_prog(const char *filename, const char *prog_namecontinue ; allow_cnt++; -if (f->any_glob) { -if (glob_matches (filename, f->any_glob)) -return true; -/* If we don't know program name yet, any_glob filter -* has to assume that current BPF object file might be -* relevant; we'll check again later on after opening -* BPF object file, at which point program name will -* be known finally. -*/ -if (!prog_name ||glob_matches (prog_name, f->any_glob)) -return true; - }else { -if (f->file_glob && !glob_matches (filename, f->file_glob)) -continue ; -if (f->prog_glob && prog_name && !glob_matches (prog_name, f->prog_glob)) -continue ; +if (prog_name &&name_filter_matches (f, filename, prog_name)) +return true; +/* +* If there is no prog_name and the file name is not blocked by +* the filter, allow to open the file. Afterwards there would be +* a second refining query with prog_name set. +*/ +if (!prog_name &&name_filter_may_match (f, filename))return true; - } }/* if there are no file/prog name allow filters, allow all progs,
@@ -571,6 +587,12 @@ static int append_filter(struct filter **filters, int *cnt, const char *str) } } +if ((!f->any_glob && !f->file_glob && !f->prog_glob) || + (f->any_glob &&strcmp (f->any_glob,"" ) ==0 )) { +fprintf (stderr,"Invalid filter: '%s'\n" , str); +return -EINVAL ; + } + *cnt +=1 ;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1212/1424 scsi: mpt3sas: Avoid freeing unallocated PCIe SGL buffers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chandrakanth Patil <[email protected]>
[ Upstream commit b9f679dfe629004b593f018df33b330d799bcee4 ]
_base_release_memory_pools() unconditionally frees every ioc->pcie_sg_lookup[] entry, including ones the setup loop never allocated after a partial failure, causing a "bad dma" warning on debug kernels or a NULL pointer dereference otherwise.
--- drivers/scsi/mpt3sas/mpt3sas_base.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/mpt3sas/mpt3sas_base.c +2 -0
@@ -5863,6 +5863,8 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)if (ioc->pcie_sgl_dma_pool) {for (i =0 ; i < ioc->scsiio_depth; i++) { +if (!ioc->pcie_sg_lookup[i].pcie_sgl) +continue ;dma_pool_free (ioc->pcie_sgl_dma_pool, ioc->pcie_sg_lookup[i].pcie_sgl, ioc->pcie_sg_lookup[i].pcie_sgl_dma);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1213/1424 scsi: ufs: core: Remove unnecessary wmb() after ringing doorbell
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Halaney <[email protected]>
[ Upstream commit d3fb9a24a6023c744d498f5b4d575517726a42b4 ]
Currently, the doorbell is written to and a wmb() is used to commit it immediately.
wmb() ensures that the write completes before following writes occur, but completion doesn't mean that it isn't stored in a buffer somewhere. The recommendation for ensuring this bit has taken effect on the device is to perform a read back to force it to make it all the way to the device. This is documented in device-io.rst and a talk by Will Deacon on this can be seen over here:
https://youtu.be/i6DayghhA8Q?si=MiyxB5cKJXSaoc01&t=1678
But, completion and taking effect aren't necessary to guarantee here.
There's already other examples of the doorbell being rung that don't do this. The writel() of the doorbell guarantees prior writes by this thread (to the request being setup for example) complete prior to the ringing of the doorbell, and the following wait_for_completion_io_timeout() doesn't require any special memory barriers either.
With that in mind, just remove the wmb() altogether here.
Stable-dep-of: 720d8b2f2457 ("scsi: ufs: core: Set task state before io_schedule_timeout()")
--- drivers/ufs/core/ufshcd.c | 3 --- 1 file changed, 3 deletions(-)
drivers/ufs/core/ufshcd.c +0 -3
@@ -7117,10 +7117,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,/* send command to the controller */ __set_bit (task_tag, &hba->outstanding_tasks); -ufshcd_writel (hba,1 << task_tag,REG_UTP_TASK_REQ_DOOR_BELL ); -/* Make sure that doorbell is committed immediately */ -wmb ();spin_unlock_irqrestore (host->host_lock, flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1214/1424 scsi: ufs: core: Remove redundant host_lock calls around UTMRLDBR
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avri Altman <[email protected]>
[ Upstream commit 2b314e182caabd32f656ddba22432a7749572013 ]
There is no need to serialize single read/write calls to the host controller registers. Remove the redundant host_lock calls that protect access to the task management doorbell register: UTMRLDBR.
Stable-dep-of: 720d8b2f2457 ("scsi: ufs: core: Set task state before io_schedule_timeout()")
--- drivers/ufs/core/ufshcd.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
drivers/ufs/core/ufshcd.c +6 -8
@@ -1187,11 +1187,13 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,static u32 ufshcd_pending_cmds (struct ufs_hba *hba) {const struct scsi_device *sdev; +unsigned long flags;u32 pending =0 ; -lockdep_assert_held (hba->host->host_lock); +spin_lock_irqsave (hba->host->host_lock, flags);__shost_for_each_device (sdev, hba->host) pending +=sbitmap_weight (&sdev->budget_map); +spin_unlock_irqrestore (hba->host->host_lock, flags);return pending; }
@@ -1205,7 +1207,6 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba)static int ufshcd_wait_for_doorbell_clr (struct ufs_hba *hba,u64 wait_timeout_us) { -unsigned long flags;int ret =0 ;u32 tm_doorbell;u32 tr_pending;
@@ -1213,7 +1214,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,ktime_t start;ufshcd_hold (hba); -spin_lock_irqsave (hba->host->host_lock, flags);/* * Wait for all the outstanding tasks/transfer requests. * Verify by checking the doorbell registers are clear.
@@ -1234,7 +1234,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,break ; } -spin_unlock_irqrestore (hba->host->host_lock, flags);io_schedule_timeout (msecs_to_jiffies (20 ));if (ktime_to_us (ktime_sub (ktime_get (), start)) > wait_timeout_us) {
@@ -1246,7 +1245,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,*/ do_last_check = true; } -spin_lock_irqsave (hba->host->host_lock, flags); }while (tm_doorbell || tr_pending);if (timeout) {
@@ -1256,7 +1254,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, ret = -EBUSY ; } out: -spin_unlock_irqrestore (hba->host->host_lock, flags);ufshcd_release (hba);return ret; }
@@ -7115,12 +7112,13 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,memcpy (hba->utmrdl_base_addr + task_tag, treq,sizeof (*treq));ufshcd_vops_setup_task_mgmt (hba, task_tag, tm_function); -/* send command to the controller */ __set_bit (task_tag, &hba->outstanding_tasks); -ufshcd_writel (hba,1 << task_tag,REG_UTP_TASK_REQ_DOOR_BELL );spin_unlock_irqrestore (host->host_lock, flags); +/* send command to the controller */ +ufshcd_writel (hba,1 << task_tag,REG_UTP_TASK_REQ_DOOR_BELL ); +ufshcd_add_tm_upiu_trace (hba, task_tag,UFS_TM_SEND );/* wait until the task management command is completed */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1215/1424 scsi: ufs: core: Set task state before io_schedule_timeout()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <[email protected]>
[ Upstream commit 720d8b2f2457f4962ca353dd90395e2660d9a10d ]
Set the task state to TASK_UNINTERRUPTIBLE before calling io_schedule_timeout() in ufshcd_wait_for_pending_cmds(). Without setting the task state, io_schedule_timeout() returns immediately because the task state remains TASK_RUNNING. This results in a busy loop that wastes CPU cycles.
--- drivers/ufs/core/ufshcd.c | 1 + 1 file changed, 1 insertion(+)
drivers/ufs/core/ufshcd.c +1 -0
@@ -1234,6 +1234,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,break ; } +__set_current_state (TASK_UNINTERRUPTIBLE );io_schedule_timeout (msecs_to_jiffies (20 ));if (ktime_to_us (ktime_sub (ktime_get (), start)) > wait_timeout_us) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1216/1424 fs/ntfs3: fix integer overflow in MFT cluster validation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
[ Upstream commit c510c63873103a5da6a498fe537bdb5d6f8d03a2 ]
In ntfs_init_from_boot(), the boot sector's MFT cluster numbers are validated against the volume size with:
if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) goto out;
mlcn and mlcn2 are u64 fields read directly from the boot sector. sct_per_clst is bounded above by 4096 (true_sectors_per_clst() plus the is_power_of_2() check below it), but the multiplication is done in u64 and wraps when mlcn (or mlcn2) is large enough -- e.g. mlcn near 2^62 with sct_per_clst == 4 wraps to 0, which compares below any non-zero 'sectors', so the check is bypassed and the malformed record is accepted.
The accepted mlcn is then used unchanged in
sbi->mft.lbo = mlcn << cluster_bits;
In practice the resulting reads fail at the block layer (sb_bread() returns NULL via grow_buffers()'s check_mul_overflow() guard), so today this manifests as mount failing in odd places rather than as something more dangerous, but the validation step is still wrong and there is no reason for callers to rely on the block layer to catch a value that should never have been accepted in the first place.
Use check_mul_overflow() to compute the two sector positions and fail the mount if either multiplication wraps; this preserves the existing semantics (mlcn * sct_per_clst >= sectors) instead of switching to division (mlcn >= sectors / sct_per_clst), which would tighten the check at edge cases where 'sectors' is not a multiple of sct_per_clst. The check_*_overflow() style is the one ntfs3 already uses for similar on-disk arithmetic in fs/ntfs3/run.c.
--- fs/ntfs3/super.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
fs/ntfs3/super.c +11 -2
@@ -57,6 +57,7 @@#include <linux/minmax.h> #include <linux/module.h> #include <linux/nls.h> +#include <linux/overflow.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/statfs.h>
@@ -870,7 +871,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,struct ntfs_sb_info *sbi = sb->s_fs_info;int err;u32 mb, gb, boot_sector_size, sct_per_clst, record_size; -u64 sectors, clusters, mlcn, mlcn2, dev_size0; +u64 sectors, clusters, mlcn, mlcn2, mft_pos, mft2_pos, dev_size0;struct NTFS_BOOT *boot;struct buffer_head *bh;struct MFT_REC *rec;
@@ -939,7 +940,15 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, mlcn2 =le64_to_cpu (boot->mft2_clst); sectors =le64_to_cpu (boot->sectors_per_volume); -if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) { +/* +* Convert mlcn/mlcn2 to sector positions before comparing with +* 'sectors'. All three are u64 values that come from the boot +* sector, so use check_mul_overflow() to keep a wraparound from +* silently bypassing the comparison. +*/ +if (check_mul_overflow (mlcn, (u64 )sct_per_clst, &mft_pos) || +check_mul_overflow (mlcn2, (u64 )sct_per_clst, &mft2_pos) || + mft_pos >= sectors || mft2_pos >= sectors) { ntfs_err( sb, "%s: start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1217/1424 fs/ntfs3: reject out-of-range evcn in mi_enum_attr()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
[ Upstream commit 20fd9f64c0050658f2031e6bd5d552c6f0c8f7e3 ]
In mi_enum_attr(), the start/end VCN validation for non-resident attributes is:
if (svcn > evcn + 1) goto out;
When evcn is U64_MAX the "evcn + 1" expression wraps to 0 and any svcn passes the check. For evcn values close to U64_MAX (but not equal to it) the right-hand side is still a meaningless near-wrap upper bound, so a malformed on-disk attribute with svcn == 0 and evcn near U64_MAX can pass mi_enum_attr() unrejected.
VCN (virtual cluster number) is a cluster index, so any valid evcn is bounded by the volume's total cluster count, which ntfs3 holds in sbi->used.bitmap.nbits (set up in ntfs_init_from_boot() before any caller of mi_enum_attr() runs). Reject evcn values that fall outside this range.
However, an empty non-resident attribute (no allocated clusters) is legitimately encoded with svcn == 0 and evcn == -1 (U64_MAX), e.g. via attr->nres.evcn = cpu_to_le64((u64)vcn - 1) with vcn == 0. That sentinel must keep passing, so exclude evcn == U64_MAX from the range check. The existing "svcn > evcn + 1" test still tolerates the sentinel ("0 > 0" is false) and continues to require svcn == 0 for it, while the range check rejects every other out-of-range evcn and thereby also defuses the "evcn + 1" wraparound.
svcn does not need its own bound: once evcn < nbits, "svcn > evcn + 1" implies svcn <= nbits.
--- fs/ntfs3/record.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-)
fs/ntfs3/record.c +31 -3
@@ -202,7 +202,7 @@ struct ATTRIB *mi_enum_attr(struct ntfs_inode *ni, struct mft_inode *mi,u32 used =le32_to_cpu (rec->used);u32 t32, off, asize, prev_type;u16 t16; -u64 data_size, alloc_size, tot_size; +u64 svcn, evcn, data_size, alloc_size, tot_size;if (!attr) {u32 total =le32_to_cpu (rec->total);
@@ -310,10 +310,38 @@ struct ATTRIB *mi_enum_attr(struct ntfs_inode *ni, struct mft_inode *mi,if (t32 &&le16_to_cpu (attr->name_off) + t32 > t16) goto out; -/* Check start/end vcn. */ -if (le64_to_cpu (attr->nres.svcn) >le64_to_cpu (attr->nres.evcn) +1 ) +/* +* Check start/end vcn. svcn == 0 with evcn == -1 (U64_MAX) is the +* sentinel for an empty non-resident attribute (no allocated +* clusters) and must be accepted: "svcn > evcn + 1" tolerates it, +* since "(u64)-1 + 1" is 0 and "0 > 0" is false. +* +* For a non-empty attribute evcn is a cluster index and must lie +* within the volume (sbi->used.bitmap.nbits, set up in +* ntfs_init_from_boot() before any caller of mi_enum_attr() runs). +* Bounding evcn also prevents a malformed value close to U64_MAX +* from slipping through the near-wrap "evcn + 1" upper bound. +*/ + svcn =le64_to_cpu (attr->nres.svcn); + evcn =le64_to_cpu (attr->nres.evcn); +if (svcn > evcn +1 ) goto out; +if (is_attr_ext (attr)) { +/* sparsed/compressed attribute. */ +#ifdef CONFIG_NTFS3_64BIT_CLUSTER +/* No limits. */ +#else +/* Check evcn fits into 32 bits. */ +if (evcn !=U64_MAX && evcn >= (1ull <<32 )) + goto out; +#endif + }else { +/* Check out of volume for normal attribute. */ +if (evcn !=U64_MAX && evcn >= mi->sbi->used.bitmap.nbits) + goto out; + } + data_size =le64_to_cpu (attr->nres.data_size);if (le64_to_cpu (attr->nres.valid_size) > data_size) goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1218/1424 ALSA: core: Fix use-after-free in snd_card_do_free()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit 5ae1a690c522fea2900ff56c8c2ace7b059f5e04 ]
A use-after-free was detected in snd_card_do_free() when a sound card managed by devres is unbound while a user-space application still holds an open file descriptor.
For managed cards, the memory is allocated using devres_alloc(), and its release function is set to __snd_card_release(), which calls snd_card_free(). When the device is unbound, the unbind thread calls snd_card_free(), which drops a reference to the card's device. If the user thread still has an open file descriptor, the reference count does not reach zero, and the unbind thread blocks on wait_for_completion(&released).
When the user thread closes the file descriptor, it drops the final reference, invoking the device release callback release_card_device(), which calls snd_card_do_free(). snd_card_do_free() performs cleanup and calls complete(card->release_completion). This wakes up the unbind thread, which returns from snd_card_free() and __snd_card_release(). The devres core then immediately frees the memory block containing the snd_card structure.
Meanwhile, the user thread continues execution in snd_card_do_free() and evaluates if (!card->managed). It reads the managed boolean from the snd_card structure that was just freed by the unbind thread, triggering a KASAN use-after-free.
Fix this by caching the value of card->managed in a local variable before calling complete(). This ensures that the card pointer is not dereferenced after the unbind thread has been woken up and potentially freed the card.
BUG: KASAN: use-after-free in snd_card_do_free sound/core/init.c:604 [inline] BUG: KASAN: use-after-free in release_card_device+0x1ab/0x1b0 sound/core/init.c:153 Read of size 1 at addr ffff8881912ec909 by task syz-executor130/5857 Call Trace: <TASK> dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description+0x55/0x1e0 mm/kasan/report.c:378 print_report+0x58/0x70 mm/kasan/report.c:482 kasan_report+0x117/0x150 mm/kasan/report.c:595 snd_card_do_free sound/core/init.c:604 [inline] release_card_device+0x1ab/0x1b0 sound/core/init.c:153 device_release+0xc4/0x1f0 drivers/base/core.c:-1 kobject_cleanup lib/kobject.c:689 [inline] kobject_release lib/kobject.c:720 [inline] kref_put include/linux/kref.h:65 [inline] kobject_put+0x222/0x550 lib/kobject.c:737 snd_card_file_remove+0x331/0x390 sound/core/init.c:1125 snd_pcm_release+0x12c/0x160 sound/core/pcm_native.c:2986 __fput+0x418/0xa50 fs/file_table.c:512 fput_close_sync+0x11f/0x240 fs/file_table.c:617 __do_sys_close fs/open.c:1511 [inline] __se_sys_close fs/open.c:1496 [inline] __x64_sys_close+0x7e/0x110 fs/open.c:1496 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
--- sound/core/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/core/init.c +3 -1
@@ -591,6 +591,8 @@ EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);static int snd_card_do_free (struct snd_card *card) { +bool managed = card->managed; + card->releasing = true;#if IS_ENABLED (CONFIG_SND_MIXER_OSS )if (snd_mixer_oss_notify_callback)
@@ -605,7 +607,7 @@ static int snd_card_do_free(struct snd_card *card) }if (card->release_completion)complete (card->release_completion); -if (!card->managed) +if (!managed)kfree (card);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1219/1424 tracing: Remove "__attribute__()" from the type field of event format
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 1a967e92bf47cf5170336b88d748117c700edc47 ]
With CONFIG_DEBUG_INFO_BTF=y and PAHOLE_HAS_BTF_TAG=y, __user is converted to __attribute__((btf_type_tag("user"))). In this case, some syscall events have it for __user data, like below;
/sys/kernel/tracing # cat events/syscalls/sys_enter_openat/format
name: sys_enter_openat
ID: 720
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:int dfd; offset:16; size:8; signed:0;
field:const char __attribute__((btf_type_tag("user"))) * filename; offset:24; size:8; signed:0;
field:int flags; offset:32; size:8; signed:0;
field:umode_t mode; offset:40; size:8; signed:0;Then the trace event filter fails to set the string acceptable flag (FILTER_PTR_STRING) to the field and rejects setting string filter;
# echo 'filename.ustring ~ "*ftracetest-dir.wbx24v*"' \
Quoted 1 line
Quoted 1 line
events/syscalls/sys_enter_openat/filter
sh: write error: Invalid argument
# cat error_log [ 723.743637] event filter parse error: error: Expecting numeric field Command: filename.ustring ~ "*ftracetest-dir.wbx24v*"
Since this __attribute__ makes format parsing complicated and not needed, remove the __attribute__(.*) from the type string.
Stable-dep-of: ae70b04ab9c7 ("tracing: Have trace_event_update_all() only handle module that is loading")
--- kernel/trace/trace.c | 28 +++++--- kernel/trace/trace.h | 4 +- kernel/trace/trace_events.c | 128 ++++++++++++++++++++++++++++++------ 3 files changed, 127 insertions(+), 33 deletions(-)
kernel/trace/trace.c +18 -10
@@ -6174,17 +6174,27 @@ static inline void trace_insert_eval_map_file(struct module *mod, struct trace_eval_map **start, int len) { }#endif /* !CONFIG_TRACE_EVAL_MAP_FILE */ -static void trace_insert_eval_map (struct module *mod, -struct trace_eval_map **start,int len) +static void +trace_event_update_with_eval_map (struct module *mod, +struct trace_eval_map **start, +int len) {struct trace_eval_map **map; -if (len <=0 ) -return ; +/* Always run sanitizer only if btf_type_tag attr exists. */ +if (len <=0 ) { +if (!(IS_ENABLED (CONFIG_DEBUG_INFO_BTF ) && +IS_ENABLED (CONFIG_PAHOLE_HAS_BTF_TAG ) && +__has_attribute (btf_type_tag))) +return ; + } map = start; -trace_event_eval_update (map, len); +trace_event_update_all (map, len); + +if (len <=0 ) +return ;trace_insert_eval_map_file (mod, start, len); }
@@ -9820,7 +9830,7 @@ static void __init eval_map_work_func(struct work_struct *work)int len; len = __stop_ftrace_eval_maps - __start_ftrace_eval_maps; -trace_insert_eval_map (NULL , __start_ftrace_eval_maps, len); +trace_event_update_with_eval_map (NULL , __start_ftrace_eval_maps, len); }static int __init trace_eval_init (void )
@@ -9855,9 +9865,6 @@ late_initcall_sync(trace_eval_sync);#ifdef CONFIG_MODULES static void trace_module_add_evals (struct module *mod) { -if (!mod->num_trace_evals) -return ; -/* * Modules with bad taint do not have events created, do * not bother with enums either.
@@ -9865,7 +9872,8 @@ static void trace_module_add_evals(struct module *mod)if (trace_module_has_bad_taint (mod))return ; -trace_insert_eval_map (mod, mod->trace_evals, mod->num_trace_evals); +/* Even if no trace_evals, this need to sanitize field types. */ +trace_event_update_with_eval_map (mod, mod->trace_evals, mod->num_trace_evals); }#ifdef CONFIG_TRACE_EVAL_MAP_FILE
kernel/trace/trace.h +2 -2
@@ -1987,13 +1987,13 @@ static inline const char *get_syscall_name(int syscall)#ifdef CONFIG_EVENT_TRACING void trace_event_init (void ); -void trace_event_eval_update (struct trace_eval_map **map,int len); +void trace_event_update_all (struct trace_eval_map **map,int len);/* Used from boot time tracer */ extern int ftrace_set_clr_event (struct trace_array *tr,char *buf,int set);extern int trigger_process_regex (struct trace_event_file *file,char *buff);#else static inline void __init trace_event_init (void ) { } -static inline void trace_event_eval_update (struct trace_eval_map **map,int len) { } +static inline void trace_event_update_all (struct trace_eval_map **map,int len) { }#endif #ifdef CONFIG_TRACER_SNAPSHOT
kernel/trace/trace_events.c +107 -21
178 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1220/1424 tracing: Have trace_event_update_all() only handle module that is loading
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit ae70b04ab9c7f6162a8c0fdd18a62a945c133142 ]
The function trace_event_update_all() does a scan of events looking to replace enums with their values in the strings that get exported to the event format files. It's run at boot up on all events and again when a module loads.
The issue is that when a module loads, it still runs on *all* events. There's no reason to process every event when a module loads as the previous events have already been processed. Only execute on the events that are loaded with the module.
--- kernel/trace/trace.c | 2 +- kernel/trace/trace.h | 4 ++-- kernel/trace/trace_events.c | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-)
kernel/trace/trace.c +1 -1
@@ -6191,7 +6191,7 @@ trace_event_update_with_eval_map(struct module *mod, map = start; -trace_event_update_all (map, len); +trace_event_update_all (map, len, mod);if (len <=0 )return ;
kernel/trace/trace.h +2 -2
@@ -1987,13 +1987,13 @@ static inline const char *get_syscall_name(int syscall)#ifdef CONFIG_EVENT_TRACING void trace_event_init (void ); -void trace_event_update_all (struct trace_eval_map **map,int len); +void trace_event_update_all (struct trace_eval_map **map,int len,struct module *mod);/* Used from boot time tracer */ extern int ftrace_set_clr_event (struct trace_array *tr,char *buf,int set);extern int trigger_process_regex (struct trace_event_file *file,char *buff);#else static inline void __init trace_event_init (void ) { } -static inline void trace_event_update_all (struct trace_eval_map **map,int len) { } +static inline void trace_event_update_all (struct trace_eval_map **map,int len,struct module *mod) { }#endif #ifdef CONFIG_TRACER_SNAPSHOT
kernel/trace/trace_events.c +5 -1
@@ -3110,7 +3110,7 @@ static void update_event_fields(struct trace_event_call *call, }/* Update all events for replacing eval and sanitizing */ -void trace_event_update_all (struct trace_eval_map **map,int len) +void trace_event_update_all (struct trace_eval_map **map,int len,struct module *mod) {struct trace_event_call *call, *p;const char *last_system =NULL ;
@@ -3122,6 +3122,10 @@ void trace_event_update_all(struct trace_eval_map **map, int len)mutex_lock (&event_mutex);down_write (&trace_event_sem);list_for_each_entry_safe (call, p, &ftrace_events, list) { + +if (mod && call->module != mod) +continue ; +/* events are usually grouped together with systems */ if (!last_system || call->class->system != last_system) { first = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1221/1424 ASoC: SOF: validate topology volume range before allocation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit a698e4a60fa54268a38f4e66378851a196cb139b ]
SOF treats the topology mixer min and max values as non-negative indices into its volume table. It stores them in signed fields, allocates max + 1 entries through an int argument, and later indexes the table with the stored range.
An inverted range is invalid, while a maximum at or above INT_MAX cannot be represented safely after the increment or in the signed fields. Validate the complete range before storing it or allocating the table.
--- sound/soc/sof/topology.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
sound/soc/sof/topology.c +12 -6
@@ -825,6 +825,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,struct snd_soc_tplg_mixer_control *mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);int tlv[SOF_TLV_ITEMS ]; +u32 min, max;unsigned int mask;int ret;
@@ -832,6 +833,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,if (le32_to_cpu (mc->num_channels) >SND_SOC_TPLG_MAX_CHAN )return -EINVAL ; + min =le32_to_cpu (mc->min); + max =le32_to_cpu (mc->max); +if (min > max || max >=INT_MAX ) +return -EINVAL ; +/* * If control has more than 2 channels we need to override the info. This is because even if * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
@@ -842,12 +848,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, kc->info = snd_sof_volume_info; scontrol->comp_id = sdev->next_comp_id; - scontrol->min_volume_step =le32_to_cpu (mc->min); - scontrol->max_volume_step =le32_to_cpu (mc->max); + scontrol->min_volume_step = min; + scontrol->max_volume_step = max; scontrol->num_channels =le32_to_cpu (mc->num_channels); - scontrol->max =le32_to_cpu (mc->max); -if (le32_to_cpu (mc->max) ==1 ) + scontrol->max = max; +if (max ==1 ) goto skip;/* extract tlv data */
@@ -857,7 +863,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, }/* set up volume table */ - ret =set_up_volume_table (scontrol, tlv,le32_to_cpu (mc->max) +1 ); + ret =set_up_volume_table (scontrol, tlv, max +1 );if (ret <0 ) {dev_err (scomp->dev,"error: setting up volume table\n" );return ret;
@@ -890,7 +896,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,return 0 ; err: -if (le32_to_cpu (mc->max) >1 ) +if (max >1 )kfree (scontrol->volume_table);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1222/1424 ACPI: scan: fix bus ID cleanup on device_add() failures
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit a414485ebc2aa50907d0ce97cde2b1a353696897 ]
When device_add() fails after acpi_device_set_name() has allocated an instance ID and a new acpi_device_bus_id has been linked into acpi_bus_id_list, the rollback path only removes wakeup_list and detaches the ACPI handle data.
That leaves the bus-ID bookkeeping behind and keeps the allocated instance number consumed.
Move the bus-ID cleanup and wakeup-list removal into a single helper.
Use it from both the normal device teardown path and the device_add() rollback path. The wakeup list node is initialized before registration, so it can be deleted without checking whether the device is wakeup- capable like in the original teardown path.
--- drivers/acpi/scan.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/acpi/scan.c +9 -4
@@ -454,12 +454,10 @@ static void acpi_device_release(struct device *dev)kfree (acpi_dev); } -static void acpi_device_del (struct acpi_device *device) +static void acpi_device_cleanup (struct acpi_device *device) {struct acpi_device_bus_id *acpi_device_bus_id; -mutex_lock (&acpi_device_lock); -list_for_each_entry (acpi_device_bus_id, &acpi_bus_id_list, node)if (!strcmp (acpi_device_bus_id->bus_id,acpi_device_hid (device))) {
@@ -474,6 +472,13 @@ static void acpi_device_del(struct acpi_device *device) }list_del (&device->wakeup_list); +} + +static void acpi_device_del (struct acpi_device *device) +{ +mutex_lock (&acpi_device_lock); + +acpi_device_cleanup (device);mutex_unlock (&acpi_device_lock);
@@ -739,7 +744,7 @@ int acpi_device_add(struct acpi_device *device) err:mutex_lock (&acpi_device_lock); -list_del (&device->wakeup_list); +acpi_device_cleanup (device); err_unlock:mutex_unlock (&acpi_device_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1223/1424 bpf: Fix pending_pos walk on 32-bit ring position wrap
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Israel Téllez García <[email protected]>
[ Upstream commit 6ff5b56a50c5351aeeb180e34327736576c038fa ]
The reservation path caches the position of the oldest not-yet-committed record in rb->pending_pos and advances it past already committed records on every reservation:
while (pend_pos < prod_pos) {consumer_pos, producer_pos and pending_pos are unsigned long, i.e. 32-bit on 32-bit architectures, and Documentation/bpf/ringbuf.rst states that these counters may wrap around there. Every other comparison in the file is written as a difference, so modular arithmetic keeps them correct across the wrap. This one is an ordering comparison, and it is not wrap-safe.
Once producer_pos wraps past 2^32, prod_pos is small while pend_pos still holds its pre-wrap value, so the loop condition is false and pending_pos is never advanced again. Reservations keep succeeding for a while, because bpf_ringbuf_has_space() uses differences, but new_prod_pos - pend_pos grows as the producer advances, and once it exceeds rb->mask every subsequent __bpf_ringbuf_reserve() call fails:
the kernel believes a pending record spans the whole buffer. The ring never recovers, bpf_ringbuf_output() drops every event from then on, and nothing is logged.
Observed on four armv7 devices (i.MX7 Dual, 6.6.52) running a tracepoint-based collector with a 512 KiB ring and 160-byte records. Every one of them stopped delivering after exactly 26846821 records and 4295491360 bytes had passed through the ring, at event rates between 441 and 862 records/s, that is after 8 h to 17 h of uptime: the trigger is the byte count, not time or load. That figure is 2^32 plus 524064 bytes, and the excess is one ring's worth of grace period, as expected while new_prod_pos - pend_pos is still below rb->mask. The last reservation that fits is the largest record boundary X with X + 160 <= 524287, and since 2^32 mod 160 = 96 the boundaries after the wrap sit at X = 64 (mod 160), giving X = 524064. Userspace kept consuming normally until the producer stopped, then read zero records for good. With this patch applied, one of the four devices took 10 GiB through the same ring with no stall, while the three unpatched ones kept wedging at the same byte count.
64-bit hosts are unaffected in practice: their counters would need 16 EiB to wrap.
Compare the two positions as a difference instead. pending_pos never runs ahead of producer_pos, so the unsigned difference is the real distance between them and stays correct across the wrap.
--- kernel/bpf/ringbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/ringbuf.c +1 -1
@@ -429,7 +429,7 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size) prod_pos = rb->producer_pos; new_prod_pos = prod_pos + len; -while (pend_pos < prod_pos) { +while (prod_pos - pend_pos >0 ) { hdr = (void *)rb->data + (pend_pos & rb->mask); hdr_len =READ_ONCE (hdr->len);if (hdr_len &BPF_RINGBUF_BUSY_BIT )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1224/1424 crypto: hisilicon/sec2 - fix CCM algorithm long packet failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhushuai Yin <[email protected]>
[ Upstream commit b82f60be50c87b3d75e207852c5ca74fa18f66cf ]
In the CCM B0 block the message-length field Q spans L bytes, where L (cl in the driver) is derived from the cipher IV flags byte as c_ivin[0] + 1. set_aead_auth_iv() hardcoded writing only the last 2 bytes of a_ivin with cryptlen, implicitly assuming cl = 2.
When cl = 3 (a shorter nonce yielding a 3-byte length field) and the packet is longer than 65535 bytes, cryptlen no longer fits in 2 bytes. The dropped high byte made the auth IV built by the driver differ from the one consumed by the hardware, so the software/hardware comparison failed and the CCM request errored out.
Write the last cl bytes of a_ivin in a loop driven by the IV's CL value, so the length-field width always matches the algorithm configuration instead of assuming a fixed 2-byte field.
--- drivers/crypto/hisilicon/sec2/sec_crypto.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/crypto/hisilicon/sec2/sec_crypto.c +6 -6
@@ -98,7 +98,6 @@#define IV_FLAGS_OFFSET 0x6#define IV_CM_OFFSET 0x3#define IV_LAST_BYTE1 1 -#define IV_LAST_BYTE2 2#define IV_LAST_BYTE_MASK 0xFF#define IV_CTR_INIT 0x1#define IV_BYTE_OFFSET 0x8
@@ -1469,7 +1468,7 @@ static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)struct sec_cipher_req *c_req = &req->c_req;u32 data_size = aead_req->cryptlen;u8 flage =0 ; -u8 cm, cl; +u8 cm, cl, i;/* the specification has been checked in aead_iv_demension_check() */ cl = c_req->c_ivin[0 ] +1 ;
@@ -1493,15 +1492,16 @@ static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)* the last 32bit is counter's initial number, * but the nonce uses the first 16bit * the tail 16bit fill with the cipher length +* When CL is 3, the tail 24bit fill with the cipher length. */ if (!c_req->encrypt) data_size = aead_req->cryptlen - authsize; - a_req->a_ivin[ctx->c_ctx.ivsize -IV_LAST_BYTE1 ] = - data_size &IV_LAST_BYTE_MASK ; - data_size >>=IV_BYTE_OFFSET ; - a_req->a_ivin[ctx->c_ctx.ivsize -IV_LAST_BYTE2 ] = +for (i =1 ; i <= cl; i++) { + a_req->a_ivin[ctx->c_ctx.ivsize - i] = data_size &IV_LAST_BYTE_MASK ; + data_size >>=IV_BYTE_OFFSET ; + } }static void sec_aead_set_iv (struct sec_ctx *ctx,struct sec_req *req)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1225/1424 perf dso: Guard close() against invalid fd in dso__decompress_kmodule_path()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 10f452dc2de401be76ae8e7395c9663313df8b53 ]
dso__decompress_kmodule_path() unconditionally calls close(fd) on the return value of decompress_kmodule(). When decompression fails or the DSO is not compressed, decompress_kmodule() returns -1. close(-1) fails with EBADF and clobbers errno, which callers up the chain (dso__get_filename → __open_dso) depend on for error propagation.
Guard the close() call with fd >= 0 so only valid file descriptors are closed.
--- tools/perf/util/dso.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +3 -1
@@ -379,7 +379,9 @@ int dso__decompress_kmodule_path(struct dso *dso, const char *name, {int fd =decompress_kmodule (dso, name, pathname, len); -close (fd); +/* decompress_kmodule() returns -1 on failure, don't close(-1) */ +if (fd >=0 ) +close (fd);return fd >=0 ?0 :-1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1226/1424 perf dso: Guard against cache underflow on short reads in dso_cache__memcpy()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 390a9461cd73bdd13acc0f6d763618ae1ff8fa17 ]
dso_cache__memcpy() computes cache_offset = offset - cache->offset, then cache_size = min(cache->size - cache_offset, size). The RB tree lookup in __dso_cache__find() matches using the full DSO__DATA_CACHE_SIZE window, but cache->size reflects the actual pread return value from dso_cache__populate().
A short pread (e.g. near end-of-file) makes cache->size smaller than DSO__DATA_CACHE_SIZE. If a subsequent access targets an offset past cache->offset + cache->size but within the DSO__DATA_CACHE_SIZE window, the cache entry is found but cache_offset exceeds cache->size. Since both are u64, the subtraction cache->size - cache_offset wraps to a large value, min() selects the caller's size, and memcpy reads out of bounds.
Return 0 for an offset past the valid cached data. For a regular file a short pread only happens at end-of-file, so 0 is what a direct pread() at that offset would return: cached_io() stops its read loop as on EOF. Re-reading from the backing file would not help — a second pread at the same offset returns the same short count.
--- tools/perf/util/dso.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +14 -1
@@ -915,7 +915,20 @@ static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data, u64 size, bool out) {u64 cache_offset = offset - cache->offset; -u64 cache_size =min (cache->size - cache_offset, size); +u64 cache_size; + +/* +* The RB tree matches using DSO__DATA_CACHE_SIZE, but a short +* pread may leave cache->size smaller. For a regular file a +* short pread only happens at end-of-file, so an offset past +* the valid data is EOF: return 0, matching what a direct +* pread() at that offset would return, and cached_io() then +* stops its read loop. +*/ +if (cache_offset >= cache->size) +return 0 ; + + cache_size =min (cache->size - cache_offset, size);if (out)memcpy (data, cache->data + cache_offset, cache_size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1227/1424 mailbox: rockchip: disable pclk on probe failure and unbind
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit ded48fcbdc1e3ed1dc8e1974b7fe9639fcea6dd6 ]
rockchip_mbox_probe() enables the peripheral clock and then keeps going. None of the later failure paths - platform_get_irq(), devm_request_threaded_irq() and devm_mbox_controller_register() - disables it again. The driver has no remove callback either, so the clock also stays prepared and enabled once the device is unbound, and its enable count keeps growing over bind/unbind cycles.
Use devm_clk_get_enabled() to tie disabling and unpreparing the clock to the device lifetime. It is registered before the interrupts and the mailbox controller, so devres releases it after both are gone.
While rewriting the error path, switch it to dev_err_probe() so that a deferred probe is not reported as an error.
--- drivers/mailbox/rockchip-mailbox.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
drivers/mailbox/rockchip-mailbox.c +4 -13
@@ -201,19 +201,10 @@ static int rockchip_mbox_probe(struct platform_device *pdev)/* Each channel has two buffers for A2B and B2A */ mb->buf_size = (size_t )resource_size (res) / (drv_data->num_chans *2 ); - mb->pclk =devm_clk_get (&pdev->dev,"pclk_mailbox" ); -if (IS_ERR (mb->pclk)) { - ret =PTR_ERR (mb->pclk); -dev_err (&pdev->dev,"failed to get pclk_mailbox clock: %d\n" , - ret); -return ret; - } - - ret =clk_prepare_enable (mb->pclk); -if (ret) { -dev_err (&pdev->dev,"failed to enable pclk: %d\n" , ret); -return ret; - } + mb->pclk =devm_clk_get_enabled (&pdev->dev,"pclk_mailbox" ); +if (IS_ERR (mb->pclk)) +return dev_err_probe (&pdev->dev,PTR_ERR (mb->pclk), +"failed to get and enable pclk_mailbox clock\n" );for (i =0 ; i < mb->mbox.num_chans; i++) { irq =platform_get_irq (pdev, i);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1228/1424 mailbox: pcc: Always map the shared memory communication address
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit fa362ffafa51b08cf8e2fcca38e056332f6b9b05 ]
Currently the shared memory communication address was mapped by the mailbox client drivers leading to all sorts of inconsistencies.
It also has resulted in the inconsistent attributes used while mapping the shared memory regions.
In order to remove/eliminate any issues, let us ensures the shared memory address is always mapped and unmapped when the PCC channels are requested and release.
We need to map them as the ACPI PCCT associates these shared memory with each channel subspace and may need use the status or the flags in the headers of those shared memory communication address regions to manage the transport/channel.
Note, until all the drivers using PCC start using this mapped shmem, there might be double mapping of the shared memory address. This shouldn't have any impact on existing mbox client drivers.
Since there are no users of pcc_chan_ioremap() and also it is mapped by default, we can stop exporting it and merge the functionality into pcc_mbox_request_channel().
Stable-dep-of: 3360b088175d ("mailbox: pcc: Fix command timeout due to missed interrupt")
--- drivers/mailbox/pcc.c | 29 +++++++++-------------------- include/acpi/pcc.h | 5 ----- 2 files changed, 9 insertions(+), 25 deletions(-)
drivers/mailbox/pcc.c +9 -20
@@ -372,6 +372,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)struct pcc_mbox_chan *pcc_mbox_request_channel (struct mbox_client *cl,int subspace_id) { +struct pcc_mbox_chan *pcc_mchan;struct pcc_chan_info *pchan;struct mbox_chan *chan;int rc;
@@ -390,7 +391,14 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)if (rc)return ERR_PTR (rc); -return &pchan->chan; + pcc_mchan = &pchan->chan; + pcc_mchan->shmem =acpi_os_ioremap (pcc_mchan->shmem_base_addr, + pcc_mchan->shmem_size); +if (pcc_mchan->shmem) +return pcc_mchan; + +mbox_free_channel (chan); +return ERR_PTR (-ENXIO ); }EXPORT_SYMBOL_GPL (pcc_mbox_request_channel);
@@ -419,25 +427,6 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) }EXPORT_SYMBOL_GPL (pcc_mbox_free_channel); -int pcc_mbox_ioremap (struct mbox_chan *chan) -{ -struct pcc_chan_info *pchan_info; -struct pcc_mbox_chan *pcc_mbox_chan; - -if (!chan || !chan->cl) -return -1 ; - pchan_info = chan->con_priv; - pcc_mbox_chan = &pchan_info->chan; - - pcc_mbox_chan->shmem =acpi_os_ioremap (pcc_mbox_chan->shmem_base_addr, - pcc_mbox_chan->shmem_size); -if (!pcc_mbox_chan->shmem) -return -ENXIO ; - -return 0 ; -} -EXPORT_SYMBOL_GPL (pcc_mbox_ioremap); -/** * pcc_send_data - Called from Mailbox Controller code. Used * here only to ring the channel doorbell. The PCC client
include/acpi/pcc.h +0 -5
@@ -38,7 +38,6 @@ struct pcc_mbox_chan {extern struct pcc_mbox_chan *pcc_mbox_request_channel (struct mbox_client *cl,int subspace_id);extern void pcc_mbox_free_channel (struct pcc_mbox_chan *chan); -extern int pcc_mbox_ioremap (struct mbox_chan *chan);#else static inline struct pcc_mbox_chan *pcc_mbox_request_channel (struct mbox_client *cl,int subspace_id)
@@ -46,10 +45,6 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)return ERR_PTR (-ENODEV ); }static inline void pcc_mbox_free_channel (struct pcc_mbox_chan *chan) { } -static inline int pcc_mbox_ioremap (struct mbox_chan *chan) -{ -return 0 ; -};#endif #endif /* _PCC_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1229/1424 mailbox/pcc: support mailbox management of the shared buffer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adam Young <[email protected]>
[ Upstream commit 5378bdf6a611a32500fccf13d14156f219bb0c85 ]
Define a new, optional, callback that allows the driver to specify how the return data buffer is allocated. If that callback is set, mailbox/pcc.c is now responsible for reading from and writing to the PCC shared buffer.
This also allows for proper checks of the Commnand complete flag between the PCC sender and receiver.
For Type 4 channels, initialize the command complete flag prior to accepting messages.
Since the mailbox does not know what memory allocation scheme to use for response messages, the client now has an optional callback that allows it to allocate the buffer for a response message.
When an outbound message is written to the buffer, the mailbox checks for the flag indicating the client wants an tx complete notification via IRQ. Upon receipt of the interrupt It will pair it with the outgoing message. The expected use is to free the kernel memory buffer for the previous outgoing message.
Stable-dep-of: 3360b088175d ("mailbox: pcc: Fix command timeout due to missed interrupt")
--- drivers/mailbox/pcc.c | 102 ++++++++++++++++++++++++++++++++++++++++-- include/acpi/pcc.h | 29 ++++++++++++ 2 files changed, 127 insertions(+), 4 deletions(-)
drivers/mailbox/pcc.c +98 -4
@@ -316,6 +316,22 @@ static void check_and_ack(struct pcc_chan_info *pchan, struct mbox_chan *chan)pcc_chan_reg_read_modify_write (&pchan->cmd_update); } +static void *write_response (struct pcc_chan_info *pchan) +{ +struct pcc_header pcc_header; +void *buffer; +int data_len; + +memcpy_fromio (&pcc_header, pchan->chan.shmem, +sizeof (pcc_header)); + data_len = pcc_header.length -sizeof (u32) +sizeof (struct pcc_header ); + + buffer = pchan->chan.rx_alloc (pchan->chan.mchan->cl, data_len); +if (buffer !=NULL ) +memcpy_fromio (buffer, pchan->chan.shmem, data_len); +return buffer; +} +/** * pcc_mbox_irq - PCC mailbox interrupt handler * @irq: interrupt number
@@ -327,6 +343,8 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) {struct pcc_chan_info *pchan;struct mbox_chan *chan = p; +struct pcc_header *pcc_header = chan->active_req; +void *handle =NULL ; pchan = chan->con_priv;
@@ -350,7 +368,17 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)* required to avoid any possible race in updatation of this flag. */ pchan->chan_in_use = false; -mbox_chan_received_data (chan,NULL ); + +if (pchan->chan.rx_alloc) + handle =write_response (pchan); + +if (chan->active_req) { + pcc_header = chan->active_req; +if (pcc_header->flags &PCC_CMD_COMPLETION_NOTIFY ) +mbox_chan_txdone (chan,0 ); + } + +mbox_chan_received_data (chan, handle);check_and_ack (pchan, chan);
@@ -394,9 +422,24 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) pcc_mchan = &pchan->chan; pcc_mchan->shmem =acpi_os_ioremap (pcc_mchan->shmem_base_addr, pcc_mchan->shmem_size); -if (pcc_mchan->shmem) -return pcc_mchan; +if (!pcc_mchan->shmem) + goto err; + + pcc_mchan->manage_writes = false; +/* This indicates that the channel is ready to accept messages. +* This needs to happen after the channel has registered +* its callback. There is no access point to do that in +* the mailbox API. That implies that the mailbox client must +* have set the allocate callback function prior to +* sending any messages. +*/ +if (pchan->type ==ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE ) +pcc_chan_reg_read_modify_write (&pchan->cmd_update); + +return pcc_mchan; + +err:mbox_free_channel (chan);return ERR_PTR (-ENXIO ); }
@@ -427,8 +470,38 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) }EXPORT_SYMBOL_GPL (pcc_mbox_free_channel); +static int pcc_write_to_buffer (struct mbox_chan *chan,void *data) +{ +struct pcc_chan_info *pchan = chan->con_priv; +struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan; +struct pcc_header *pcc_header = data; + +if (!pchan->chan.manage_writes) +return 0 ; + +/* The PCC header length includes the command field +* but not the other values from the header. +*/ +int len = pcc_header->length -sizeof (u32) +sizeof (struct pcc_header ); +u64 val; + +pcc_chan_reg_read (&pchan->cmd_complete, &val); +if (!val) { +pr_info ("%s pchan->cmd_complete not set" , __func__); +return -1 ; + } +memcpy_toio (pcc_mbox_chan->shmem, data, len); +return 0 ; +} + +/** -* pcc_send_data - Called from Mailbox Controller code. Used +* pcc_send_data - Called from Mailbox Controller code. If +* pchan->chan.rx_alloc is set, then the command complete +* flag is checked and the data is written to the shared +* buffer io memory. +* +* If pchan->chan.rx_alloc is not set, then it is used * here only to ring the channel doorbell. The PCC client * specific read/write is done in the client driver in * order to maintain atomicity over PCC channel once
@@ -444,17 +517,37 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)int ret;struct pcc_chan_info *pchan = chan->con_priv; + ret =pcc_write_to_buffer (chan, data); +if (ret) +return ret; + ret =pcc_chan_reg_read_modify_write (&pchan->cmd_update);if (ret)return ret; ret =pcc_chan_reg_read_modify_write (&pchan->db); +if (!ret && pchan->plat_irq >0 ) pchan->chan_in_use = true;return ret; } + +static bool pcc_last_tx_done (struct mbox_chan *chan) +{ +struct pcc_chan_info *pchan = chan->con_priv; +u64 val; + +pcc_chan_reg_read (&pchan->cmd_complete, &val); +if (!val) +return false; +else +return true; +} + + +/** * pcc_startup - Called from Mailbox Controller code. Used here * to request the interrupt.
@@ -500,6 +593,7 @@ static const struct mbox_chan_ops pcc_chan_ops = { .send_data = pcc_send_data, .startup = pcc_startup, .shutdown = pcc_shutdown, + .last_tx_done = pcc_last_tx_done, };/**
include/acpi/pcc.h +29 -0
@@ -17,6 +17,35 @@ struct pcc_mbox_chan {u32 latency;u32 max_access_rate;u16 min_turnaround_time; + +/* Set to true to indicate that the mailbox should manage +* writing the dat to the shared buffer. This differs from +* the case where the drivesr are writing to the buffer and +* using send_data only to ring the doorbell. If this flag +* is set, then the void * data parameter of send_data must +* point to a kernel-memory buffer formatted in accordance with +* the PCC specification. +* +* The active buffer management will include reading the +* notify_on_completion flag, and will then +* call mbox_chan_txdone when the acknowledgment interrupt is +* received. +*/ +bool manage_writes; + +/* Optional callback that allows the driver +* to allocate the memory used for receiving +* messages. The return value is the location +* inside the buffer where the mailbox should write the data. +*/ +void *(*rx_alloc)(struct mbox_client *cl,int size); +}; + +struct pcc_header { +u32 signature; +u32 flags; +u32 length; +u32 command; };/* Generic Communications Channel Shared Memory Region */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1230/1424 Revert "mailbox/pcc: support mailbox management of the shared buffer"
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit f82c3e62b6b8c31d8c56415bf38658f306fda4cb ]
This reverts commit 5378bdf6a611a32500fccf13d14156f219bb0c85.
Commit 5378bdf6a611 ("mailbox/pcc: support mailbox management of the shared buffer") attempted to introduce generic helpers for managing the PCC shared memory, but it largely duplicates functionality already provided by the mailbox core and leaves gaps:
1. TX preparation: The mailbox framework already supports this via ->tx_prepare callback for mailbox clients. The patch adds pcc_write_to_buffer() and expects clients to toggle pchan->chan.manage_writes, but no drivers set manage_writes, so pcc_write_to_buffer() has no users.
2. RX handling: Data reception is already delivered through mbox_chan_received_data() and client ->rx_callback. The patch adds an optional pchan->chan.rx_alloc, which again has no users and duplicates the existing path.
3. Completion handling: While adding last_tx_done is directionally useful, the implementation only covers Type 3/4 and fails to handle the absence of a command_complete register, so it is incomplete for other types.
Given the duplication and incomplete coverage, revert this change. Any new requirements should be addressed in focused follow-ups rather than bundling multiple behavioral changes together.
Stable-dep-of: 3360b088175d ("mailbox: pcc: Fix command timeout due to missed interrupt")
--- drivers/mailbox/pcc.c | 102 ++---------------------------------------- include/acpi/pcc.h | 29 ------------ 2 files changed, 4 insertions(+), 127 deletions(-)
drivers/mailbox/pcc.c +4 -98
@@ -316,22 +316,6 @@ static void check_and_ack(struct pcc_chan_info *pchan, struct mbox_chan *chan)pcc_chan_reg_read_modify_write (&pchan->cmd_update); } -static void *write_response (struct pcc_chan_info *pchan) -{ -struct pcc_header pcc_header; -void *buffer; -int data_len; - -memcpy_fromio (&pcc_header, pchan->chan.shmem, -sizeof (pcc_header)); - data_len = pcc_header.length -sizeof (u32) +sizeof (struct pcc_header ); - - buffer = pchan->chan.rx_alloc (pchan->chan.mchan->cl, data_len); -if (buffer !=NULL ) -memcpy_fromio (buffer, pchan->chan.shmem, data_len); -return buffer; -} -/** * pcc_mbox_irq - PCC mailbox interrupt handler * @irq: interrupt number
@@ -343,8 +327,6 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) {struct pcc_chan_info *pchan;struct mbox_chan *chan = p; -struct pcc_header *pcc_header = chan->active_req; -void *handle =NULL ; pchan = chan->con_priv;
@@ -368,17 +350,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)* required to avoid any possible race in updatation of this flag. */ pchan->chan_in_use = false; - -if (pchan->chan.rx_alloc) - handle =write_response (pchan); - -if (chan->active_req) { - pcc_header = chan->active_req; -if (pcc_header->flags &PCC_CMD_COMPLETION_NOTIFY ) -mbox_chan_txdone (chan,0 ); - } - -mbox_chan_received_data (chan, handle); +mbox_chan_received_data (chan,NULL );check_and_ack (pchan, chan);
@@ -422,24 +394,9 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) pcc_mchan = &pchan->chan; pcc_mchan->shmem =acpi_os_ioremap (pcc_mchan->shmem_base_addr, pcc_mchan->shmem_size); -if (!pcc_mchan->shmem) - goto err; - - pcc_mchan->manage_writes = false; +if (pcc_mchan->shmem) +return pcc_mchan; -/* This indicates that the channel is ready to accept messages. -* This needs to happen after the channel has registered -* its callback. There is no access point to do that in -* the mailbox API. That implies that the mailbox client must -* have set the allocate callback function prior to -* sending any messages. -*/ -if (pchan->type ==ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE ) -pcc_chan_reg_read_modify_write (&pchan->cmd_update); - -return pcc_mchan; - -err:mbox_free_channel (chan);return ERR_PTR (-ENXIO ); }
@@ -470,38 +427,8 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) }EXPORT_SYMBOL_GPL (pcc_mbox_free_channel); -static int pcc_write_to_buffer (struct mbox_chan *chan,void *data) -{ -struct pcc_chan_info *pchan = chan->con_priv; -struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan; -struct pcc_header *pcc_header = data; - -if (!pchan->chan.manage_writes) -return 0 ; - -/* The PCC header length includes the command field -* but not the other values from the header. -*/ -int len = pcc_header->length -sizeof (u32) +sizeof (struct pcc_header ); -u64 val; - -pcc_chan_reg_read (&pchan->cmd_complete, &val); -if (!val) { -pr_info ("%s pchan->cmd_complete not set" , __func__); -return -1 ; - } -memcpy_toio (pcc_mbox_chan->shmem, data, len); -return 0 ; -} - -/** -* pcc_send_data - Called from Mailbox Controller code. If -* pchan->chan.rx_alloc is set, then the command complete -* flag is checked and the data is written to the shared -* buffer io memory. -* -* If pchan->chan.rx_alloc is not set, then it is used +* pcc_send_data - Called from Mailbox Controller code. Used * here only to ring the channel doorbell. The PCC client * specific read/write is done in the client driver in * order to maintain atomicity over PCC channel once
@@ -517,37 +444,17 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)int ret;struct pcc_chan_info *pchan = chan->con_priv; - ret =pcc_write_to_buffer (chan, data); -if (ret) -return ret; - ret =pcc_chan_reg_read_modify_write (&pchan->cmd_update);if (ret)return ret; ret =pcc_chan_reg_read_modify_write (&pchan->db); -if (!ret && pchan->plat_irq >0 ) pchan->chan_in_use = true;return ret; } - -static bool pcc_last_tx_done (struct mbox_chan *chan) -{ -struct pcc_chan_info *pchan = chan->con_priv; -u64 val; - -pcc_chan_reg_read (&pchan->cmd_complete, &val); -if (!val) -return false; -else -return true; -} - - -/** * pcc_startup - Called from Mailbox Controller code. Used here * to request the interrupt.
@@ -593,7 +500,6 @@ static const struct mbox_chan_ops pcc_chan_ops = { .send_data = pcc_send_data, .startup = pcc_startup, .shutdown = pcc_shutdown, - .last_tx_done = pcc_last_tx_done, };/**
include/acpi/pcc.h +0 -29
@@ -17,35 +17,6 @@ struct pcc_mbox_chan {u32 latency;u32 max_access_rate;u16 min_turnaround_time; - -/* Set to true to indicate that the mailbox should manage -* writing the dat to the shared buffer. This differs from -* the case where the drivesr are writing to the buffer and -* using send_data only to ring the doorbell. If this flag -* is set, then the void * data parameter of send_data must -* point to a kernel-memory buffer formatted in accordance with -* the PCC specification. -* -* The active buffer management will include reading the -* notify_on_completion flag, and will then -* call mbox_chan_txdone when the acknowledgment interrupt is -* received. -*/ -bool manage_writes; - -/* Optional callback that allows the driver -* to allocate the memory used for receiving -* messages. The return value is the location -* inside the buffer where the mailbox should write the data. -*/ -void *(*rx_alloc)(struct mbox_client *cl,int size); -}; - -struct pcc_header { -u32 signature; -u32 flags; -u32 length; -u32 command; };/* Generic Communications Channel Shared Memory Region */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1231/1424 mailbox: pcc: Fix command timeout due to missed interrupt
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huisong Li <[email protected]>
[ Upstream commit 3360b088175dc5d5c9166685836158470d00571e ]
PCC command execution can time out when a fast platform completes a transaction and signals the platform interrupt before pcc_send_data() marks the channel as in use. For shared platform interrupts, the type 3 handler uses chan_in_use to decide whether the interrupt belongs to the channel. If it observes false, it ignores the completion and the caller waits until timeout.
Publish chan_in_use before ringing the doorbell. Use WRITE_ONCE() for the lockless flag updates and READ_ONCE() in the interrupt handler. The following ordered I/O accessor orders the flag store before the platform is notified.
Clear chan_in_use if ringing the doorbell fails. Otherwise, leave it set until the interrupt handler completes the transaction, clearing it before the mailbox core can submit another transfer.
--- drivers/mailbox/pcc.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-)
drivers/mailbox/pcc.c +27 -14
@@ -93,12 +93,11 @@ struct pcc_chan_reg {* @plat_irq: platform interrupt * @type: PCC subspace type * @plat_irq_flags: platform interrupt flags -* @chan_in_use: this flag is used just to check if the interrupt needs -* handling when it is shared. Since only one transfer can occur -* at a time and mailbox takes care of locking, this flag can be -* accessed without a lock. Note: the type only support the -* communication from OSPM to Platform, like type3, use it, and -* other types completely ignore it. +* @chan_in_use: lockless flag used by type 3 initiator subspaces to filter +* platform interrupts. Only one transfer can occur at a time, but +* the interrupt handler may sample the flag on another CPU, so all +* accesses must use READ_ONCE() or WRITE_ONCE(). Other subspace +* types do not test it. */ struct pcc_chan_info {struct pcc_mbox_chan chan;
@@ -333,8 +332,13 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)if (pcc_chan_reg_read_modify_write (&pchan->plat_irq_ack))return IRQ_NONE ; +/* +* Initiator subspaces use this flag to filter shared interrupts. Use +* READ_ONCE() to sample the lockless flag written by pcc_send_data() +* on another CPU. +*/ if (pchan->type ==ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && - !pchan->chan_in_use) + !READ_ONCE (pchan->chan_in_use))return IRQ_NONE ;if (!pcc_mbox_cmd_complete_check (pchan))
@@ -344,12 +348,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)return IRQ_NONE ;/* -* Clear this flag after updating interrupt ack register and just -* before mbox_chan_received_data() which might call pcc_send_data() -* where the flag is set again to start new transfer. This is -* required to avoid any possible race in updatation of this flag. +* Clear this flag after updating the interrupt ack register and before +* notifying the client and mailbox core. mbox_chan_txdone() may submit +* the next queued transfer and set the flag again. Use WRITE_ONCE() for +* the lockless update observed by the send and interrupt paths. */ - pchan->chan_in_use = false; +WRITE_ONCE (pchan->chan_in_use, false);mbox_chan_received_data (chan,NULL );check_and_ack (pchan, chan);
@@ -448,9 +452,18 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)if (ret)return ret; +/* +* Set chan_in_use before ringing the doorbell so a fast completion +* interrupt is not mistaken for a shared interrupt from another +* subspace. Use WRITE_ONCE() for the lockless flag update. The +* ordered I/O accessor used to ring the doorbell orders this store +* before the platform is notified. +*/ +if (pchan->plat_irq >0 ) +WRITE_ONCE (pchan->chan_in_use, true); ret =pcc_chan_reg_read_modify_write (&pchan->db); -if (!ret && pchan->plat_irq >0 ) - pchan->chan_in_use = true; +if (ret && pchan->plat_irq >0 ) +WRITE_ONCE (pchan->chan_in_use, false);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1232/1424 null_blk: use DEFINE_MUTEX for the file-scope mutex
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zizhi Wo <[email protected]>
[ Upstream commit 017dac7670909eaea3eb36e6b3b5a8be9ce0a14d ]
In null_init(), mutex_init(&lock) currently happens after configfs_register_subsystem(), which exposes the nullb subsystem to userspace. A racing mkdir() into /sys/kernel/config/nullb/ can reach null_find_dev_by_name() -> mutex_lock(&lock) before the mutex is initialized, trigger warning:
[ 123.137788] DEBUG_LOCKS_WARN_ON(lock->magic != lock) [ 123.137796] WARNING: kernel/locking/mutex.c:159 at mutex_lock+0x171/0x1c0, CPU#13: mkdir/1301 [ 123.140090] Modules linked in: null_blk(+) nft_fib_inet nft_fib_ipv4 ...... [ 123.154926] Call Trace: [ 123.155172] <TASK> [ 123.155419] ? __pfx_mutex_lock+0x10/0x10 [ 123.156181] ? __pfx__raw_spin_lock+0x10/0x10 [ 123.156571] nullb_group_make_group+0x20/0x100 [null_blk] [ 123.157011] configfs_mkdir+0x47b/0xc70 [ 123.157337] ? __pfx_configfs_mkdir+0x10/0x10 [ 123.157719] ? may_create_dentry+0x242/0x2e0 [ 123.158061] vfs_mkdir+0x2a9/0x6c0 [ 123.158352] filename_mkdirat+0x3dc/0x500 [ 123.158710] ? __pfx_filename_mkdirat+0x10/0x10 [ 123.159070] ? strncpy_from_user+0x3a/0x1d0 [ 123.159413] __x64_sys_mkdir+0x6b/0x90 [ 123.159760] do_syscall_64+0xea/0x600
Replace the runtime mutex_init(&lock) with a static DEFINE_MUTEX(lock) declaration to fix this issue.
--- drivers/block/null_blk/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/block/null_blk/main.c +1 -3
@@ -66,7 +66,7 @@ struct nullb_page {#define NULLB_PAGE_FREE (MAP_SZ - 2)static LIST_HEAD (nullb_list); -static struct mutex lock; +static DEFINE_MUTEX (lock);static int null_major;static DEFINE_IDA (nullb_indexes);static struct blk_mq_tag_set tag_set;
@@ -2327,8 +2327,6 @@ static int __init null_init(void)if (ret) goto err_tagset; -mutex_init (&lock); - null_major =register_blkdev (0 ,"nullb" );if (null_major <0 ) { ret = null_major;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1233/1424 null_blk: add configfs variable shared_tags
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shin'ichiro Kawasaki <[email protected]>
[ Upstream commit 14509b748ff58df3f0980b1cd70ade0e4a805e99 ]
Allow setting shared_tags through configfs, which could only be set as a module parameter. For that purpose, delay tag_set initialization from null_init() to null_add_dev(). Refer tag_set.ops as the flag to check if tag_set is initialized or not.
The following parameters can not be set through configfs yet:
timeout
requeue
init_hctx
Stable-dep-of: c9d293d6bb05 ("null_blk: register configfs subsystem after creating default devices")
--- drivers/block/null_blk/main.c | 38 ++++++++++++++++--------------- drivers/block/null_blk/null_blk.h | 1 + 2 files changed, 21 insertions(+), 18 deletions(-)
drivers/block/null_blk/main.c +20 -18
@@ -165,8 +165,8 @@ static bool g_blocking;module_param_named (blocking, g_blocking, bool,0444 );MODULE_PARM_DESC (blocking,"Register as a blocking blk-mq driver device" ); -static bool shared_tags; -module_param (shared_tags, bool,0444 ); +static bool g_shared_tags; +module_param_named (shared_tags, g_shared_tags, bool,0444 );MODULE_PARM_DESC (shared_tags,"Share tag set between devices for blk-mq" );static bool g_shared_tag_bitmap;
@@ -438,6 +438,7 @@ NULLB_DEVICE_ATTR(zone_max_open, uint, NULL);NULLB_DEVICE_ATTR (zone_max_active, uint,NULL );NULLB_DEVICE_ATTR (virt_boundary, bool,NULL );NULLB_DEVICE_ATTR (no_sched, bool,NULL ); +NULLB_DEVICE_ATTR (shared_tags, bool,NULL );NULLB_DEVICE_ATTR (shared_tag_bitmap, bool,NULL );static ssize_t nullb_device_power_show (struct config_item *item,char *page)
@@ -587,6 +588,7 @@ static struct configfs_attribute *nullb_device_attrs[] = { &nullb_device_attr_zone_offline, &nullb_device_attr_virt_boundary, &nullb_device_attr_no_sched, + &nullb_device_attr_shared_tags, &nullb_device_attr_shared_tag_bitmap, NULL, };
@@ -679,10 +681,11 @@ static ssize_t memb_group_features_show(struct config_item *item, char *page)"badblocks,blocking,blocksize,cache_size," "completion_nsec,discard,home_node,hw_queue_depth," "irqmode,max_sectors,mbps,memory_backed,no_sched," -"poll_queues,power,queue_mode,shared_tag_bitmap,size," -"submit_queues,use_per_node_hctx,virt_boundary,zoned," -"zone_capacity,zone_max_active,zone_max_open," - "zone_nr_conv,zone_offline,zone_readonly,zone_size\n"); +"poll_queues,power,queue_mode,shared_tag_bitmap," +"shared_tags,size,submit_queues,use_per_node_hctx," +"virt_boundary,zoned,zone_capacity,zone_max_active," +"zone_max_open,zone_nr_conv,zone_offline,zone_readonly," + "zone_size\n"); }CONFIGFS_ATTR_RO (memb_group_, features);
@@ -764,6 +767,7 @@ static struct nullb_device *null_alloc_dev(void) dev->zone_max_active = g_zone_max_active; dev->virt_boundary = g_virt_boundary; dev->no_sched = g_no_sched; + dev->shared_tags = g_shared_tags; dev->shared_tag_bitmap = g_shared_tag_bitmap;return dev; }
@@ -2130,7 +2134,14 @@ static int null_add_dev(struct nullb_device *dev) goto out_free_nullb;if (dev->queue_mode ==NULL_Q_MQ ) { -if (shared_tags) { +if (dev->shared_tags) { +if (!tag_set.ops) { + rv =null_init_tag_set (NULL , &tag_set); +if (rv) { + tag_set.ops =NULL ; + goto out_cleanup_queues; + } + } nullb->tag_set = &tag_set; rv =0 ; }else {
@@ -2314,18 +2325,12 @@ static int __init null_init(void) g_submit_queues =1 ; } -if (g_queue_mode ==NULL_Q_MQ && shared_tags) { - ret =null_init_tag_set (NULL , &tag_set); -if (ret) -return ret; - } -config_group_init (&nullb_subsys.su_group);mutex_init (&nullb_subsys.su_mutex); ret =configfs_register_subsystem (&nullb_subsys);if (ret) - goto err_tagset; +return ret; null_major =register_blkdev (0 ,"nullb" );if (null_major <0 ) {
@@ -2350,9 +2355,6 @@ static int __init null_init(void)unregister_blkdev (null_major,"nullb" ); err_conf:configfs_unregister_subsystem (&nullb_subsys); -err_tagset: -if (g_queue_mode ==NULL_Q_MQ && shared_tags) -blk_mq_free_tag_set (&tag_set);return ret; }
@@ -2371,7 +2373,7 @@ static void __exit null_exit(void) }mutex_unlock (&lock); -if (g_queue_mode ==NULL_Q_MQ && shared_tags) +if (tag_set.ops)blk_mq_free_tag_set (&tag_set);mutex_destroy (&lock);
drivers/block/null_blk/null_blk.h +1 -0
@@ -119,6 +119,7 @@ struct nullb_device {bool zoned;/* if device is zoned */ bool virt_boundary;/* virtual boundary on/off for the device */ bool no_sched;/* no IO scheduler for the device */ +bool shared_tags;/* share tag set between devices for blk-mq */ bool shared_tag_bitmap;/* use hostwide shared tags */ };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1234/1424 null_blk: register configfs subsystem after creating default devices
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zizhi Wo <[email protected]>
[ Upstream commit c9d293d6bb0575fcb1f3408129453187e2a28a4e ]
In null_init(), configfs_register_subsystem() currently runs before register_blkdev(), so when null_blk is built as a module, a racing mkdir()
+ poweron from userspace can reach null_add_dev() while null_major is still
0. __add_disk() then hits WARN_ON(disk->minors) (major=0 with minors!=0) and fails:
[root@fedora ~]# [ 2366.521436] WARNING: block/genhd.c:476 at __add_disk+0x8a7/0xde0,
[ 2366.523552] Modules linked in: null_blk(+) nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib [ 2366.529081] CPU: 26 UID: 0 PID: 1600 Comm: sh Not tainted 7.2.0-rc1+ #66 PREEMPT(full) ...... [ 2366.547251] Call Trace: [ 2366.547575] <TASK> [ 2366.547831] ? _raw_spin_lock+0x84/0xe0 [ 2366.548260] add_disk_fwnode+0x114/0x560 [ 2366.548739] null_add_dev+0x102d/0x1b80 [null_blk] [ 2366.549310] ? __pfx_null_add_dev+0x10/0x10 [null_blk] [ 2366.549906] ? mutex_lock+0xde/0x1c0 [ 2366.550361] ? __pfx_mutex_lock+0x10/0x10 [ 2366.550827] nullb_device_power_store+0x1e7/0x280 [null_blk] [ 2366.551499] ? __pfx_nullb_device_power_store+0x10/0x10 [null_blk] [ 2366.552177] ? __kmalloc_cache_noprof+0x1f5/0x470 [ 2366.552748] ? configfs_write_iter+0x35c/0x4e0 [ 2366.553242] configfs_write_iter+0x286/0x4e0 [ 2366.553787] vfs_write+0x52d/0xd00 [ 2366.554169] ? __pfx_vfs_write+0x10/0x10 [ 2366.554679] ? __pfx___css_rstat_updated+0x10/0x10 [ 2366.555196] ? fdget_pos+0x1cf/0x4c0 [ 2366.555649] ksys_write+0xfc/0x1d0
......
Additionally, the err_dev path destroys all devices on nullb_list while configfs is still registered. If a racing mkdir() + poweron puts a user device on the list, null_destroy_dev()->null_free_dev() kfrees the user device's nullb_device but /sys/kernel/config/nullb/<name> is still reachable. Any userspace access to the item will trigger a UAF.
For simplicity, move configfs_register_subsystem() to the end to solve the problems above.
--- drivers/block/null_blk/main.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
drivers/block/null_blk/main.c +6 -10
@@ -2328,15 +2328,9 @@ static int __init null_init(void)config_group_init (&nullb_subsys.su_group);mutex_init (&nullb_subsys.su_mutex); - ret =configfs_register_subsystem (&nullb_subsys); -if (ret) -return ret; - null_major =register_blkdev (0 ,"nullb" ); -if (null_major <0 ) { - ret = null_major; - goto err_conf; - } +if (null_major <0 ) +return null_major;for (i =0 ; i < nr_devices; i++) { ret =null_create_dev ();
@@ -2344,6 +2338,10 @@ static int __init null_init(void) goto err_dev; } + ret =configfs_register_subsystem (&nullb_subsys); +if (ret) + goto err_dev; +pr_info ("module loaded\n" );return 0 ;
@@ -2353,8 +2351,6 @@ static int __init null_init(void)null_destroy_dev (nullb); }unregister_blkdev (null_major,"nullb" ); -err_conf: -configfs_unregister_subsystem (&nullb_subsys);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1235/1424 null_blk: free global tag_set on init error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zizhi Wo <[email protected]>
[ Upstream commit 5a1c5ff3a49ba93a1fd0b70537e7a0164071760d ]
If shared_tags is enabled, null_setup_tagset() allocates the global tag_set via null_init_global_tag_set(). If device creation later fails, err_dev destroys the default devices and calls unregister_blkdev(), but never frees the global tag_set. Since module init failed, null_exit() is never invoked, so the global tag_set's tags and maps are permanently leaked.
Free the global tag_set in err_dev, matching null_exit() which does if (tag_set.ops) blk_mq_free_tag_set(&tag_set).
--- drivers/block/null_blk/main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/block/null_blk/main.c +2 -0
@@ -2351,6 +2351,8 @@ static int __init null_init(void)null_destroy_dev (nullb); }unregister_blkdev (null_major,"nullb" ); +if (tag_set.ops) +blk_mq_free_tag_set (&tag_set);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1236/1424 null_blk: reject per-device queue resize for shared tag set
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zizhi Wo <[email protected]>
[ Upstream commit 1cdfe2fa62b48728a9b436fbbd3dbe4c11593e24 ]
When shared_tags is enabled, null_setup_tagset() makes the device use the global tag_set, whose driver_data stays NULL. null_map_queues() therefore falls back to the module-wide g_submit_queues/g_poll_queues instead of any per-device value.
Resizing submit_queues or poll_queues via configfs on such a device calls blk_mq_update_nr_hw_queues() on the shared set, shrinking set->nr_hw_queues. __blk_mq_realloc_hw_ctxs() only grows the q->queue_hw_ctx[] allocation, so on shrink it merely exits and NULLs the now-excess hctx slots. null_map_queues(), however, keeps mapping CPUs with the unchanged g_submit_queues/g_poll_queues, so mq_map[] ends up pointing at those NULLed hctx slots. blk_mq_map_swqueue() then dereferences the NULL hctx (hctx->cpumask), crashing the kernel:
[ 460.218374] KASAN: null-ptr-deref in range [0x0000000000000098-0x000000000000009f] [ 460.219003] CPU: 24 UID: 0 PID: 1492 Comm: sh Not tainted 7.2.0-rc2+ #67 PREEMPT(full) [ 460.219792] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc41 04/01/2014 [ 460.220452] RIP: 0010:blk_mq_map_swqueue+0x4db/0x1430 ...... [ 460.228977] Call Trace: [ 460.229175] <TASK> [ 460.229354] blk_mq_update_nr_hw_queues+0xd49/0x11c0 [ 460.229779] ? __pfx_blk_mq_update_nr_hw_queues+0x10/0x10 [ 460.230200] nullb_update_nr_hw_queues+0x1a9/0x370 [null_blk] [ 460.230694] nullb_device_submit_queues_store+0xd9/0x170 [null_blk] [ 460.231190] ? __pfx_nullb_device_submit_queues_store+0x10/0x10 [null_blk] [ 460.231776] ? configfs_write_iter+0x35c/0x4e0 [ 460.232122] configfs_write_iter+0x286/0x4e0 [ 460.232460] vfs_write+0x52d/0xd00 [ 460.232779] ? __x64_sys_openat+0x108/0x1d0 [ 460.233106] ? __pfx_vfs_write+0x10/0x10 [ 460.233413] ? fdget_pos+0x1cf/0x4c0 [ 460.233745] ? fput_close+0x133/0x190 [ 460.234038] ? __pfx_expand_files+0x10/0x10 [ 460.234368] ksys_write+0xfc/0x1d0
Reproducer:
modprobe null_blk shared_tags=1 submit_queues=64 poll_queues=1 mkdir /sys/kernel/config/nullb/dev
echo 1 > /sys/kernel/config/nullb/dev/power
echo 1 > /sys/kernel/config/nullb/dev/submit_queues
A per-device resize of a shared tag set is meaningless anyway, so reject it with -EINVAL in nullb_update_nr_hw_queues() when the device is bound to the global tag_set.
--- drivers/block/null_blk/main.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/block/null_blk/main.c +9 -0
@@ -353,6 +353,15 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev,if (!dev->nullb)return 0 ; +/* +* A shared tag_set is mapped via the module-wide queue counts, so a +* per-device resize is meaningless. On shrink it would also leave +* mq_map[] pointing at NULLed hctx slots, causing a NULL deref in +* blk_mq_map_swqueue(). Reject it. +*/ +if (dev->shared_tags) +return -EINVAL ; +/* * Make sure at least one submit queue exists. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1237/1424 null_blk: serialize configfs attribute stores with the lock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zizhi Wo <[email protected]>
[ Upstream commit 7e7fff51808237703a3a1df6dd5cae1dfd1db86d ]
The NULLB_DEVICE_ATTR _store takes no lock: apply_fn attributes (submit_queues, poll_queues) get dev->NAME written again after apply_fn returns, outside its lock; APPLY=NULL attributes are entirely lockless. configfs only serializes stores per-open-file, so concurrent stores on separate fds race.
For apply_fn attributes, once one store's apply_fn has reconfigured the hardware, a second (losing) store can still overwrite dev->NAME afterwards. This leaves dev->submit_queues out of sync with the live queue count, which is later caught by the WARN_ON_ONCE() in null_map_queues().
For !apply_fn attributes, power_store()'s null_add_dev() validates and builds the device under "lock" but only sets CONFIGURED afterwards. A store slipping in during this window can change a field mid-setup -- for example, zone_nr_conv can be pushed above nr_zones after it has already been clamped, leading to an out-of-bounds dev->zones[] access.
Take "lock" in the macro around the apply_fn call, the CONFIGURED test and the field write, and move it out of nullb_apply_submit_queues()/ nullb_apply_poll_queues() so both paths are covered once. This serializes stores with power_store's setup and with each other.
--- drivers/block/null_blk/main.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
drivers/block/null_blk/main.c +3 -14
@@ -331,6 +331,7 @@ nullb_device_##NAME##_store(struct config_item *item, const char *page, \ ret = nullb_device_##TYPE##_attr_store(&new_value, page, count);\ if (ret < 0) \ return ret; \ + guard(mutex)(&lock); \ if (apply_fn) \ ret = apply_fn(dev, new_value); \ else if (test_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags)) \
@@ -401,25 +402,13 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev,static int nullb_apply_submit_queues (struct nullb_device *dev,unsigned int submit_queues) { -int ret; - -mutex_lock (&lock); - ret =nullb_update_nr_hw_queues (dev, submit_queues, dev->poll_queues); -mutex_unlock (&lock); - -return ret; +return nullb_update_nr_hw_queues (dev, submit_queues, dev->poll_queues); }static int nullb_apply_poll_queues (struct nullb_device *dev,unsigned int poll_queues) { -int ret; - -mutex_lock (&lock); - ret =nullb_update_nr_hw_queues (dev, dev->submit_queues, poll_queues); -mutex_unlock (&lock); - -return ret; +return nullb_update_nr_hw_queues (dev, dev->submit_queues, poll_queues); }NULLB_DEVICE_ATTR (size, ulong,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1238/1424 null_blk: serialize configfs attribute updates with device setup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Cassel <[email protected]>
[ Upstream commit 4e1f23f9c33c156be7e313b40695af5a3a834739 ]
The attribute store methods generated with NULLB_DEVICE_ATTR() refuse to change the configuration of a live device by testing NULLB_DEV_FL_CONFIGURED, but that flag is only set by nullb_device_power_store() after null_add_dev() has returned, and the store methods take no lock at all. configfs only serializes writes to the same open file (buffer->mutex), so a write to any attribute can run concurrently with null_add_dev() and change the device configuration while it is being used.
null_add_dev() reads the configuration several times, e.g. dev->zoned is read once to set up the queue limits and once to initialize the zone resources:
CPU0: echo 1 > nullb0/power CPU1: echo 1 > nullb0/zoned
nullb_device_power_store()
mutex_lock(&lock)
null_add_dev()
if (dev->zoned) -> false
/* no BLK_FEAT_ZONED */ nullb_device_zoned_store()
test_bit(FL_CONFIGURED) -> 0
dev->zoned = true
blk_mq_alloc_disk()
/* queue is not zoned */
if (nullb->dev->zoned) -> true
null_register_zoned_dev()
blk_revalidate_disk_zones()blk_revalidate_disk_zones() is then called for a queue that does not have BLK_FEAT_ZONED set, which triggers its WARN_ON_ONCE() and fails the device setup with -EIO:
WARNING: CPU: 2 PID: 322 at block/blk-zoned.c:2357 blk_revalidate_disk_zones+0x4c/0x560
Clearing dev->zoned in the same window is worse: the queue is created with BLK_FEAT_ZONED but the zone resources are never initialized, so add_disk() succeeds for a zoned disk that has no zones. And a store that lands after the last dev->zoned test leaves dev->zoned set while dev->zones is still NULL, which null_process_zoned_cmd() dereferences on the first write.
Fix this by taking the global lock, which nullb_device_power_store() already holds across null_add_dev() and null_del_dev(), around both the NULLB_DEV_FL_CONFIGURED test and the update of the device configuration. The submit_queues and poll_queues apply callbacks are now called with that lock held, so remove the locking they did themselves.
Since the store methods can run as soon as configfs_register_subsystem() returns, that is, before null_init() gets to mutex_init(&lock), also initialize the lock statically with DEFINE_MUTEX().
--- drivers/block/null_blk/main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/block/null_blk/main.c +11 -3
@@ -311,7 +311,15 @@ static ssize_t nullb_device_bool_attr_store(bool *val, const char *page,return count; } -/* The following macro should only be used with TYPE = {uint, ulong, bool}. */ +/* +* The following macro should only be used with TYPE = {uint, ulong, bool}. +* +* The device configuration is modified under the global lock to serialize +* attribute changes against null_add_dev() and null_del_dev(): without this, +* an attribute could be changed while null_add_dev() is running, that is, +* before NULLB_DEV_FL_CONFIGURED is set, which would let null_add_dev() +* observe inconsistent values for the device configuration. +*/ #define NULLB_DEVICE_ATTR (NAME ,TYPE ,APPLY ) \ static ssize_t \ nullb_device_##NAME##_show(struct config_item *item, char *page) \
@@ -351,6 +359,8 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev,struct blk_mq_tag_set *set;int ret, nr_hw_queues; +lockdep_assert_held (&lock); +if (!dev->nullb)return 0 ;
@@ -2371,8 +2381,6 @@ static void __exit null_exit(void)if (tag_set.ops)blk_mq_free_tag_set (&tag_set); - -mutex_destroy (&lock); }module_init (null_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1239/1424 block: mtip32xx: synchronize ioctls with device removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 68940f841d013192086a0f6d7cfbac2cd079e228 ]
The ioctl handlers only test REMOVE_PENDING before entering mtip_hw_ioctl(). Removal can set that bit immediately afterwards and free dd->port in mtip_hw_exit() while an ioctl still dereferences it. An already open block device can reach the handlers while del_gendisk() is in progress.
Serialize both native and compat ioctls with removal. Set REMOVE_PENDING before taking the mutex so new callers fail after an in-flight ioctl has drained, and hold the mutex until the port has been torn down.
--- drivers/block/mtip32xx/mtip32xx.c | 7 +++++++ drivers/block/mtip32xx/mtip32xx.h | 2 ++ 2 files changed, 9 insertions(+)
drivers/block/mtip32xx/mtip32xx.c +7 -0
@@ -3053,6 +3053,8 @@ static int mtip_block_ioctl(struct block_device *dev,if (!dd)return -ENOTTY ; +guard (mutex)(&dd->ioctl_mutex); +if (unlikely (test_bit (MTIP_DDF_REMOVE_PENDING_BIT , &dd->dd_flag)))return -ENOTTY ;
@@ -3091,6 +3093,8 @@ static int mtip_block_compat_ioctl(struct block_device *dev,if (!dd)return -ENOTTY ; +guard (mutex)(&dd->ioctl_mutex); +if (unlikely (test_bit (MTIP_DDF_REMOVE_PENDING_BIT , &dd->dd_flag)))return -ENOTTY ;
@@ -3716,6 +3720,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, dd =kzalloc_node (sizeof (struct driver_data ),GFP_KERNEL , my_node);if (!dd)return -ENOMEM ; +mutex_init (&dd->ioctl_mutex);/* Attach the private data to this PCI device. */ pci_set_drvdata (pdev, dd);
@@ -3888,6 +3893,7 @@ static void mtip_pci_remove(struct pci_dev *pdev) }set_bit (MTIP_DDF_REMOVE_PENDING_BIT , &dd->dd_flag); +mutex_lock (&dd->ioctl_mutex);if (test_bit (MTIP_DDF_INIT_DONE_BIT , &dd->dd_flag))del_gendisk (dd->disk);
@@ -3916,6 +3922,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)/* De-initialize the protocol layer. */ mtip_hw_exit (dd); +mutex_unlock (&dd->ioctl_mutex);if (dd->isr_workq) {destroy_workqueue (dd->isr_workq);
drivers/block/mtip32xx/mtip32xx.h +2 -0
@@ -12,6 +12,7 @@#define __MTIP32XX_H__#include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/rwsem.h> #include <linux/ata.h> #include <linux/interrupt.h>
@@ -432,6 +433,7 @@ struct driver_data {struct request_queue *queue;/* Our request queue. */ struct blk_mq_tag_set tags;/* blk_mq tags */ +struct mutex ioctl_mutex;struct mtip_port *port;/* Pointer to the port data structure. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1240/1424 hwmon: (emc1403) Add support for EMC1442
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Delphine CC Chiu <[email protected]>
[ Upstream commit 9350163aff24530f2aa3357ee1c7bd8771a443e4 ]
Add support for EMC1442 which is compatible with EMC1402.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- drivers/hwmon/emc1403.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/hwmon/emc1403.c +5 -1
@@ -346,6 +346,9 @@ static int emc1403_detect(struct i2c_client *client,case 0x27 :strscpy (info->type,"emc1424" ,I2C_NAME_SIZE );break ; +case 0x60 : +strscpy (info->type,"emc1442" ,I2C_NAME_SIZE ); +break ;default :return -ENODEV ; }
@@ -430,7 +433,7 @@ static int emc1403_probe(struct i2c_client *client) }static const unsigned short emc1403_address_list[] = { -0x18 ,0x1c ,0x29 ,0x4c ,0x4d ,0x5c ,I2C_CLIENT_END +0x18 ,0x1c ,0x29 ,0x3c ,0x4c ,0x4d ,0x5c ,I2C_CLIENT_END };/* Last digit of chip name indicates number of channels */
@@ -444,6 +447,7 @@ static const struct i2c_device_id emc1403_idtable[] = { { "emc1422", emc1402 }, { "emc1423", emc1403 }, { "emc1424", emc1404 }, + { "emc1442", emc1402 }, { } };MODULE_DEVICE_TABLE (i2c, emc1403_idtable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1241/1424 hwmon: (emc1403) Convert to with_info API
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 1094360dc860e3578b3ec1889b05c88462ff189e ]
Convert driver to register with the hwmon subsystem using devm_hwmon_device_register_with_info() instead of devm_hwmon_device_register_with_groups() to simplify the code and to reduce its size. As side effect, this also fixes a couple of overflow problems when writing limit and hysteresis registers.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- drivers/hwmon/emc1403.c | 623 +++++++++++++++++++++------------------- 1 file changed, 332 insertions(+), 291 deletions(-)
drivers/hwmon/emc1403.c +332 -291
@@ -27,60 +27,26 @@enum emc1403_chip { emc1402, emc1403, emc1404 };struct thermal_data { +enum emc1403_chip chip;struct regmap *regmap;struct mutex mutex; -const struct attribute_group *groups[4 ]; }; -static ssize_t temp_show (struct device *dev,struct device_attribute *attr, -char *buf) +static ssize_t power_state_show (struct device *dev,struct device_attribute *attr,char *buf) { -struct sensor_device_attribute *sda =to_sensor_dev_attr (attr);struct thermal_data *data =dev_get_drvdata (dev);unsigned int val;int retval; - retval =regmap_read (data->regmap, sda->index, &val); + retval =regmap_read (data->regmap,0x03 , &val);if (retval <0 )return retval; -return sprintf (buf,"%d000\n" , val); +return sprintf (buf,"%d\n" , !!(val &BIT (6 ))); } -static ssize_t bit_show (struct device *dev,struct device_attribute *attr, -char *buf) +static ssize_t power_state_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) { -struct sensor_device_attribute_2 *sda =to_sensor_dev_attr_2 (attr); -struct thermal_data *data =dev_get_drvdata (dev); -unsigned int val; -int retval; - - retval =regmap_read (data->regmap, sda->nr, &val); -if (retval <0 ) -return retval; -return sprintf (buf,"%d\n" , !!(val & sda->index)); -} - -static ssize_t temp_store (struct device *dev,struct device_attribute *attr, -const char *buf,size_t count) -{ -struct sensor_device_attribute *sda =to_sensor_dev_attr (attr); -struct thermal_data *data =dev_get_drvdata (dev); -unsigned long val; -int retval; - -if (kstrtoul (buf,10 , &val)) -return -EINVAL ; - retval =regmap_write (data->regmap, sda->index, -DIV_ROUND_CLOSEST (val,1000 )); -if (retval <0 ) -return retval; -return count; -} - -static ssize_t bit_store (struct device *dev,struct device_attribute *attr, -const char *buf,size_t count) -{ -struct sensor_device_attribute_2 *sda =to_sensor_dev_attr_2 (attr);struct thermal_data *data =dev_get_drvdata (dev);unsigned long val;int retval;
@@ -88,233 +54,20 @@ static ssize_t bit_store(struct device *dev, struct device_attribute *attr,if (kstrtoul (buf,10 , &val))return -EINVAL ; - retval =regmap_update_bits (data->regmap, sda->nr, sda->index, - val ? sda->index :0 ); + retval =regmap_update_bits (data->regmap,0x03 ,BIT (6 ), + val ?BIT (6 ) :0 );if (retval <0 )return retval;return count; } -static ssize_t show_hyst_common (struct device *dev, -struct device_attribute *attr,char *buf, -bool is_min) -{ -struct sensor_device_attribute *sda =to_sensor_dev_attr (attr); -struct thermal_data *data =dev_get_drvdata (dev); -struct regmap *regmap = data->regmap; -unsigned int limit; -unsigned int hyst; -int retval; - - retval =regmap_read (regmap, sda->index, &limit); -if (retval <0 ) -return retval; - - retval =regmap_read (regmap,0x21 , &hyst); -if (retval <0 ) -return retval; - -return sprintf (buf,"%d000\n" , is_min ? limit + hyst : limit - hyst); -} - -static ssize_t hyst_show (struct device *dev,struct device_attribute *attr, -char *buf) -{ -return show_hyst_common (dev, attr, buf, false); -} - -static ssize_t min_hyst_show (struct device *dev, -struct device_attribute *attr,char *buf) -{ -return show_hyst_common (dev, attr, buf, true); -} - -static ssize_t hyst_store (struct device *dev,struct device_attribute *attr, -const char *buf,size_t count) -{ -struct sensor_device_attribute *sda =to_sensor_dev_attr (attr); -struct thermal_data *data =dev_get_drvdata (dev); -struct regmap *regmap = data->regmap; -unsigned int limit; -int retval; -int hyst; -unsigned long val; - -if (kstrtoul (buf,10 , &val)) -return -EINVAL ; - -mutex_lock (&data->mutex); - retval =regmap_read (regmap, sda->index, &limit); -if (retval <0 ) - goto fail; - - hyst = limit *1000 - val; - hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,255 ); - retval =regmap_write (regmap,0x21 , hyst); -if (retval ==0 ) - retval = count; -fail: -mutex_unlock (&data->mutex); -return retval; -} - -/* -* Sensors. We pass the actual i2c register to the methods. -*/ - -static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 0x06); -static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 0x05); -static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, 0x20); -static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0x00); -static SENSOR_DEVICE_ATTR_2_RO(temp1_min_alarm, bit, 0x36, 0x01); -static SENSOR_DEVICE_ATTR_2_RO(temp1_max_alarm, bit, 0x35, 0x01); -static SENSOR_DEVICE_ATTR_2_RO(temp1_crit_alarm, bit, 0x37, 0x01); -static SENSOR_DEVICE_ATTR_RO(temp1_min_hyst, min_hyst, 0x06); -static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, hyst, 0x05); -static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, hyst, 0x20); - -static SENSOR_DEVICE_ATTR_RW(temp2_min, temp, 0x08); -static SENSOR_DEVICE_ATTR_RW(temp2_max, temp, 0x07); -static SENSOR_DEVICE_ATTR_RW(temp2_crit, temp, 0x19); -static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 0x01); -static SENSOR_DEVICE_ATTR_2_RO(temp2_fault, bit, 0x1b, 0x02); -static SENSOR_DEVICE_ATTR_2_RO(temp2_min_alarm, bit, 0x36, 0x02); -static SENSOR_DEVICE_ATTR_2_RO(temp2_max_alarm, bit, 0x35, 0x02); -static SENSOR_DEVICE_ATTR_2_RO(temp2_crit_alarm, bit, 0x37, 0x02); -static SENSOR_DEVICE_ATTR_RO(temp2_min_hyst, min_hyst, 0x08); -static SENSOR_DEVICE_ATTR_RO(temp2_max_hyst, hyst, 0x07); -static SENSOR_DEVICE_ATTR_RO(temp2_crit_hyst, hyst, 0x19); - -static SENSOR_DEVICE_ATTR_RW(temp3_min, temp, 0x16); -static SENSOR_DEVICE_ATTR_RW(temp3_max, temp, 0x15); -static SENSOR_DEVICE_ATTR_RW(temp3_crit, temp, 0x1A); -static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 0x23); -static SENSOR_DEVICE_ATTR_2_RO(temp3_fault, bit, 0x1b, 0x04); -static SENSOR_DEVICE_ATTR_2_RO(temp3_min_alarm, bit, 0x36, 0x04); -static SENSOR_DEVICE_ATTR_2_RO(temp3_max_alarm, bit, 0x35, 0x04); -static SENSOR_DEVICE_ATTR_2_RO(temp3_crit_alarm, bit, 0x37, 0x04); -static SENSOR_DEVICE_ATTR_RO(temp3_min_hyst, min_hyst, 0x16); -static SENSOR_DEVICE_ATTR_RO(temp3_max_hyst, hyst, 0x15); -static SENSOR_DEVICE_ATTR_RO(temp3_crit_hyst, hyst, 0x1A); - -static SENSOR_DEVICE_ATTR_RW(temp4_min, temp, 0x2D); -static SENSOR_DEVICE_ATTR_RW(temp4_max, temp, 0x2C); -static SENSOR_DEVICE_ATTR_RW(temp4_crit, temp, 0x30); -static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 0x2A); -static SENSOR_DEVICE_ATTR_2_RO(temp4_fault, bit, 0x1b, 0x08); -static SENSOR_DEVICE_ATTR_2_RO(temp4_min_alarm, bit, 0x36, 0x08); -static SENSOR_DEVICE_ATTR_2_RO(temp4_max_alarm, bit, 0x35, 0x08); -static SENSOR_DEVICE_ATTR_2_RO(temp4_crit_alarm, bit, 0x37, 0x08); -static SENSOR_DEVICE_ATTR_RO(temp4_min_hyst, min_hyst, 0x2D); -static SENSOR_DEVICE_ATTR_RO(temp4_max_hyst, hyst, 0x2C); -static SENSOR_DEVICE_ATTR_RO(temp4_crit_hyst, hyst, 0x30); - -static SENSOR_DEVICE_ATTR_2_RW(power_state, bit, 0x03, 0x40); - -static struct attribute *emc1402_attrs[] = { - &sensor_dev_attr_temp1_min.dev_attr.attr, - &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_crit.dev_attr.attr, - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, - - &sensor_dev_attr_temp2_min.dev_attr.attr, - &sensor_dev_attr_temp2_max.dev_attr.attr, - &sensor_dev_attr_temp2_crit.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp2_min_hyst.dev_attr.attr, - &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, - - &sensor_dev_attr_power_state.dev_attr.attr, -NULL -}; - -static const struct attribute_group emc1402_group = { - .attrs = emc1402_attrs, -}; +static DEVICE_ATTR_RW (power_state);static struct attribute *emc1403_attrs[] = { - &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, - - &sensor_dev_attr_temp2_fault.dev_attr.attr, - &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, - - &sensor_dev_attr_temp3_min.dev_attr.attr, - &sensor_dev_attr_temp3_max.dev_attr.attr, - &sensor_dev_attr_temp3_crit.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp3_fault.dev_attr.attr, - &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, - &sensor_dev_attr_temp3_min_hyst.dev_attr.attr, - &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, -NULL -}; - -static const struct attribute_group emc1403_group = { - .attrs = emc1403_attrs, -}; - -static struct attribute *emc1404_attrs[] = { - &sensor_dev_attr_temp4_min.dev_attr.attr, - &sensor_dev_attr_temp4_max.dev_attr.attr, - &sensor_dev_attr_temp4_crit.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp4_fault.dev_attr.attr, - &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, - &sensor_dev_attr_temp4_min_hyst.dev_attr.attr, - &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, + &dev_attr_power_state.attr,NULL }; - -static const struct attribute_group emc1404_group = { - .attrs = emc1404_attrs, -}; - -/* -* EMC14x2 uses a different register and different bits to report alarm and -* fault status. For simplicity, provide a separate attribute group for this -* chip series. -* Since we can not re-use the same attribute names, create a separate attribute -* array. -*/ -static struct sensor_device_attribute_2 emc1402_alarms[] = { -SENSOR_ATTR_2_RO (temp1_min_alarm, bit,0x02 ,0x20 ), -SENSOR_ATTR_2_RO (temp1_max_alarm, bit,0x02 ,0x40 ), -SENSOR_ATTR_2_RO (temp1_crit_alarm, bit,0x02 ,0x01 ), - -SENSOR_ATTR_2_RO (temp2_fault, bit,0x02 ,0x04 ), -SENSOR_ATTR_2_RO (temp2_min_alarm, bit,0x02 ,0x08 ), -SENSOR_ATTR_2_RO (temp2_max_alarm, bit,0x02 ,0x10 ), -SENSOR_ATTR_2_RO (temp2_crit_alarm, bit,0x02 ,0x02 ), -}; - -static struct attribute *emc1402_alarm_attrs[] = { - &emc1402_alarms[0 ].dev_attr.attr, - &emc1402_alarms[1 ].dev_attr.attr, - &emc1402_alarms[2 ].dev_attr.attr, - &emc1402_alarms[3 ].dev_attr.attr, - &emc1402_alarms[4 ].dev_attr.attr, - &emc1402_alarms[5 ].dev_attr.attr, - &emc1402_alarms[6 ].dev_attr.attr, -NULL , -}; - -static const struct attribute_group emc1402_alarm_group = { - .attrs = emc1402_alarm_attrs, -}; +ATTRIBUTE_GROUPS (emc1403);static int emc1403_detect (struct i2c_client *client,struct i2c_board_info *info)
@@ -389,51 +142,310 @@ static const struct regmap_config emc1403_regmap_config = { .volatile_reg = emc1403_regmap_is_volatile, }; -static const struct i2c_device_id emc1403_idtable[]; +enum emc1403_reg_map {temp_min, temp_max, temp_crit, temp_input}; -static int emc1403_probe (struct i2c_client *client) +static u8 ema1403_temp_map[] = { + [hwmon_temp_min] = temp_min, + [hwmon_temp_max] = temp_max, + [hwmon_temp_crit] = temp_crit, + [hwmon_temp_input] = temp_input, +}; + +static u8 emc1403_temp_regs[][4 ] = { + [0 ] = { + [temp_min] =0x06 , + [temp_max] =0x05 , + [temp_crit] =0x20 , + [temp_input] =0x00 , + }, + [1 ] = { + [temp_min] =0x08 , + [temp_max] =0x07 , + [temp_crit] =0x19 , + [temp_input] =0x01 , + }, + [2 ] = { + [temp_min] =0x16 , + [temp_max] =0x15 , + [temp_crit] =0x1a , + [temp_input] =0x23 , + }, + [3 ] = { + [temp_min] =0x2d , + [temp_max] =0x2c , + [temp_crit] =0x30 , + [temp_input] =0x2a , + }, +}; + +static int __emc1403_get_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) { -struct thermal_data *data; -struct device *hwmon_dev; -const struct i2c_device_id *id =i2c_match_id (emc1403_idtable, client); +unsigned int regval; +int ret; - data =devm_kzalloc (&client->dev,sizeof (struct thermal_data ), -GFP_KERNEL ); -if (data ==NULL ) -return -ENOMEM ; + ret =regmap_read (data->regmap, emc1403_temp_regs[channel][map], ®val); +if (ret <0 ) +return ret; + *val = regval *1000 ; - data->regmap =devm_regmap_init_i2c (client, &emc1403_regmap_config); -if (IS_ERR (data->regmap)) -return PTR_ERR (data->regmap); +return 0 ; +} -mutex_init (&data->mutex); +static int emc1403_get_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) +{ +int ret; + +mutex_lock (&data->mutex); + ret =__emc1403_get_temp (data, channel, map, val); +mutex_unlock (&data->mutex); + +return ret; +} + +static int emc1403_get_hyst (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) +{ +int hyst, ret; +long limit; + +mutex_lock (&data->mutex); + ret =__emc1403_get_temp (data, channel, map, &limit); +if (ret <0 ) + goto unlock; + ret =regmap_read (data->regmap,0x21 , &hyst); +if (ret <0 ) + goto unlock; +if (map == temp_min) + *val = limit + hyst *1000 ; +else + *val = limit - hyst *1000 ; +unlock: +mutex_unlock (&data->mutex); +return ret; +} + +static int emc1403_temp_read (struct thermal_data *data,u32 attr,int channel,long *val) +{ +unsigned int regval; +int ret; + +switch (attr) { +case hwmon_temp_min: +case hwmon_temp_max: +case hwmon_temp_crit: +case hwmon_temp_input: + ret =emc1403_get_temp (data, channel, ema1403_temp_map[attr], val); +break ; +case hwmon_temp_min_hyst: + ret =emc1403_get_hyst (data, channel, temp_min, val); +break ; +case hwmon_temp_max_hyst: + ret =emc1403_get_hyst (data, channel, temp_max, val); +break ; +case hwmon_temp_crit_hyst: + ret =emc1403_get_hyst (data, channel, temp_crit, val); +break ; +case hwmon_temp_min_alarm: +if (data->chip == emc1402) { + ret =regmap_read (data->regmap,0x02 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (5 -2 * channel)); + }else { + ret =regmap_read (data->regmap,0x36 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (channel)); + } +break ; +case hwmon_temp_max_alarm: +if (data->chip == emc1402) { + ret =regmap_read (data->regmap,0x02 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (6 -2 * channel)); + }else { + ret =regmap_read (data->regmap,0x35 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (channel)); + } +break ; +case hwmon_temp_crit_alarm: +if (data->chip == emc1402) { + ret =regmap_read (data->regmap,0x02 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (channel)); + }else { + ret =regmap_read (data->regmap,0x37 , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (channel)); + } +break ; +case hwmon_temp_fault: + ret =regmap_read (data->regmap,0x1b , ®val); +if (ret <0 ) +break ; + *val = !!(regval &BIT (channel)); +break ; +default : +return -EOPNOTSUPP ; + } +return ret; +} + +static int emc1403_read (struct device *dev,enum hwmon_sensor_types type, +u32 attr,int channel,long *val) +{ +struct thermal_data *data =dev_get_drvdata (dev); -switch (id->driver_data) { -case emc1404: - data->groups[2 ] = &emc1404_group; - fallthrough; -case emc1403: - data->groups[1 ] = &emc1403_group; - fallthrough; -case emc1402: - data->groups[0 ] = &emc1402_group; +switch (type) { +case hwmon_temp: +return emc1403_temp_read (data, attr, channel, val); +default : +return -EOPNOTSUPP ; } +} -if (id->driver_data == emc1402) - data->groups[1 ] = &emc1402_alarm_group; +static int emc1403_set_hyst (struct thermal_data *data,long val) +{ +int hyst, ret; +long limit; - hwmon_dev =devm_hwmon_device_register_with_groups (&client->dev, - client->name, data, - data->groups); -if (IS_ERR (hwmon_dev)) -return PTR_ERR (hwmon_dev); + val =clamp_val (val,0 ,255000 ); -dev_info (&client->dev,"%s Thermal chip found\n" , id->name); -return 0 ; +mutex_lock (&data->mutex); + ret =__emc1403_get_temp (data,0 , temp_crit, &limit); +if (ret <0 ) + goto unlock; + + hyst = limit - val; + hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,255 ); + ret =regmap_write (data->regmap,0x21 , hyst); +unlock: +mutex_unlock (&data->mutex); +return ret; } -static const unsigned short emc1403_address_list[] = { -0x18 ,0x1c ,0x29 ,0x3c ,0x4c ,0x4d ,0x5c ,I2C_CLIENT_END +static int emc1403_set_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long val) +{ +unsigned int regval; +int ret; + + val =clamp_val (val,0 ,255000 ); + +mutex_lock (&data->mutex); + regval =DIV_ROUND_CLOSEST (val,1000 ); + ret =regmap_write (data->regmap, emc1403_temp_regs[channel][map], regval); +mutex_unlock (&data->mutex); +return ret; +} + +static int emc1403_temp_write (struct thermal_data *data,u32 attr,int channel,long val) +{ +switch (attr) { +case hwmon_temp_min: +case hwmon_temp_max: +case hwmon_temp_crit: +return emc1403_set_temp (data, channel, ema1403_temp_map[attr], val); +case hwmon_temp_crit_hyst: +return emc1403_set_hyst (data, val); +default : +return -EOPNOTSUPP ; + } +} + +static int emc1403_write (struct device *dev,enum hwmon_sensor_types type, +u32 attr,int channel,long val) +{ +struct thermal_data *data =dev_get_drvdata (dev); + +switch (type) { +case hwmon_temp: +return emc1403_temp_write (data, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static umode_t emc1403_temp_is_visible (const void *_data,u32 attr,int channel) +{ +const struct thermal_data *data = _data; + +if (data->chip == emc1402 && channel >1 ) +return 0 ; +if (data->chip == emc1403 && channel >2 ) +return 0 ; + +switch (attr) { +case hwmon_temp_input: +case hwmon_temp_min_alarm: +case hwmon_temp_max_alarm: +case hwmon_temp_crit_alarm: +case hwmon_temp_fault: +case hwmon_temp_min_hyst: +case hwmon_temp_max_hyst: +return 0444 ; +case hwmon_temp_min: +case hwmon_temp_max: +case hwmon_temp_crit: +return 0644 ; +case hwmon_temp_crit_hyst: +if (channel ==0 ) +return 0644 ; +return 0444 ; +default : +return 0 ; + } +} + +static umode_t emc1403_is_visible (const void *data,enum hwmon_sensor_types type, +u32 attr,int channel) +{ +switch (type) { +case hwmon_temp: +return emc1403_temp_is_visible (data, attr, channel); +default : +return 0 ; + } +} + +static const struct hwmon_channel_info *const emc1403_info[] = { +HWMON_CHANNEL_INFO (temp, +HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | +HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM | +HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM , +HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | +HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM | +HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT , +HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | +HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM | +HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT , +HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | +HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM | +HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT + ), +NULL +}; + +static const struct hwmon_ops emc1403_hwmon_ops = { + .is_visible = emc1403_is_visible, + .read = emc1403_read, + .write = emc1403_write, +}; + +static const struct hwmon_chip_info emc1403_chip_info = { + .ops = &emc1403_hwmon_ops, + .info = emc1403_info, };/* Last digit of chip name indicates number of channels */
@@ -452,6 +464,35 @@ static const struct i2c_device_id emc1403_idtable[] = { };MODULE_DEVICE_TABLE (i2c, emc1403_idtable); +static int emc1403_probe (struct i2c_client *client) +{ +struct thermal_data *data; +struct device *hwmon_dev; +const struct i2c_device_id *id =i2c_match_id (emc1403_idtable, client); + + data =devm_kzalloc (&client->dev,sizeof (struct thermal_data ), +GFP_KERNEL ); +if (!data) +return -ENOMEM ; + + data->chip = id->driver_data; + data->regmap =devm_regmap_init_i2c (client, &emc1403_regmap_config); +if (IS_ERR (data->regmap)) +return PTR_ERR (data->regmap); + +mutex_init (&data->mutex); + + hwmon_dev =devm_hwmon_device_register_with_info (&client->dev, + client->name, data, + &emc1403_chip_info, + emc1403_groups); +return PTR_ERR_OR_ZERO (hwmon_dev); +} + +static const unsigned short emc1403_address_list[] = { +0x18 ,0x1c ,0x29 ,0x3c ,0x4c ,0x4d ,0x5c ,I2C_CLIENT_END +}; +static struct i2c_driver sensor_emc1403 = { .class =I2C_CLASS_HWMON , .driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1242/1424 hwmon: (emc1403) Support 11 bit accuracy
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit e77b204ad4d01d3aee5e18fe33dc6d7a09953308 ]
Various temperature and limit registers support 11 bit accuracy. Add support for it.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- drivers/hwmon/emc1403.c | 55 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-)
drivers/hwmon/emc1403.c +52 -3
@@ -178,17 +178,52 @@ static u8 emc1403_temp_regs[][4] = { }, }; +static s8 emc1403_temp_regs_low[][4 ] = { + [0 ] = { + [temp_min] =-1 , + [temp_max] =-1 , + [temp_crit] =-1 , + [temp_input] =0x29 , + }, + [1 ] = { + [temp_min] =0x14 , + [temp_max] =0x13 , + [temp_crit] =-1 , + [temp_input] =0x10 , + }, + [2 ] = { + [temp_min] =0x18 , + [temp_max] =0x17 , + [temp_crit] =-1 , + [temp_input] =0x24 , + }, + [3 ] = { + [temp_min] =0x2f , + [temp_max] =0x2e , + [temp_crit] =-1 , + [temp_input] =0x2b , + }, +}; +static int __emc1403_get_temp (struct thermal_data *data,int channel,enum emc1403_reg_map map,long *val) {unsigned int regval;int ret; +s8 reg; ret =regmap_read (data->regmap, emc1403_temp_regs[channel][map], ®val);if (ret <0 )return ret; *val = regval *1000 ; + reg = emc1403_temp_regs_low[channel][map]; +if (reg >=0 ) { + ret =regmap_read (data->regmap, reg, ®val); +if (ret <0 ) +return ret; + *val += (regval >>5 ) *125 ; + }return 0 ; }
@@ -336,12 +371,26 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, {unsigned int regval;int ret; +u8 regh; +s8 regl; - val =clamp_val (val,0 ,255000 ); + regh = emc1403_temp_regs[channel][map]; + regl = emc1403_temp_regs_low[channel][map];mutex_lock (&data->mutex); - regval =DIV_ROUND_CLOSEST (val,1000 ); - ret =regmap_write (data->regmap, emc1403_temp_regs[channel][map], regval); +if (regl >=0 ) { + val =clamp_val (val,0 ,255875 ); + regval =DIV_ROUND_CLOSEST (val,125 ); + ret =regmap_write (data->regmap, regh, regval >>3 ); +if (ret <0 ) + goto unlock; + ret =regmap_write (data->regmap, regl, (regval &0x07 ) <<5 ); + }else { + val =clamp_val (val,0 ,255000 ); + regval =DIV_ROUND_CLOSEST (val,1000 ); + ret =regmap_write (data->regmap, regh, regval); + } +unlock:mutex_unlock (&data->mutex);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1243/1424 hwmon: (emc1403) Add support for EMC1428 and EMC1438.
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lars Petter Mostad <[email protected]>
[ Upstream commit c82337843dd7c0723e7ce2b86e5ed89d71f1c7c3 ]
EMC1428 and EMC1438 are similar to EMC14xx, but have eight temperature channels, as well as signed data and limit registers. Chips currently supported by this driver have unsigned registers only.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- Documentation/hwmon/emc1403.rst | 17 ++++- drivers/hwmon/emc1403.c | 121 +++++++++++++++++++++++++++++--- 2 files changed, 124 insertions(+), 14 deletions(-)
Documentation/hwmon/emc1403.rst +14 -3
@@ -45,6 +45,17 @@ Supported chips: - https://ww1.microchip.com/downloads/en/DeviceDoc/1423_1424.pdf + * SMSC / Microchip EMC1428, EMC1438 + + Addresses scanned: I2C 0x18, 0x4c, 0x4d + + Prefix: 'emc1428', 'emc1438' + + Datasheets: + + - https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005275A.pdf + - https://ww1.microchip.com/downloads/en/DeviceDoc/EMC1438%20DS%20Rev.%201.0%20(04-29-10).pdf + Author: Kalhan Trisal <[email protected]
@@ -53,10 +64,10 @@ Description ----------- The Standard Microsystems Corporation (SMSC) / Microchip EMC14xx chips -contain up to four temperature sensors. EMC14x2 support two sensors +contain up to eight temperature sensors. EMC14x2 support two sensors (one internal, one external). EMC14x3 support three sensors (one internal, -two external), and EMC14x4 support four sensors (one internal, three -external). +two external), EMC14x4 support four sensors (one internal, three external), +and EMC14x8 support eight sensors (one internal, seven external). The chips implement three limits for each sensor: low (tempX_min), high (tempX_max) and critical (tempX_crit.) The chips also implement an
drivers/hwmon/emc1403.c +110 -11
208 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1244/1424 hwmon: (emc1403) Rely on subsystem locking
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 61e9b50ffa2390a2927051d335b2ba04b8f791ce ]
Attribute access is now serialized in the hardware monitoring core, so locking in the driver code is no longer necessary. Drop it.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- drivers/hwmon/emc1403.c | 46 +++++++++-------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-)
drivers/hwmon/emc1403.c +10 -36
@@ -17,7 +17,6 @@#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/mutex.h> #include <linux/regmap.h> #define THERMAL_PID_REG 0xfd
@@ -29,7 +28,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };struct thermal_data {enum emc1403_chip chip;struct regmap *regmap; -struct mutex mutex; };static ssize_t power_state_show (struct device *dev,struct device_attribute *attr,char *buf)
@@ -267,8 +265,8 @@ static s8 emc1403_temp_regs_low[][4] = { }, }; -static int __emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) +static int emc1403_get_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) {unsigned int regvalh;unsigned int regvall =0 ;
@@ -294,38 +292,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel,return 0 ; } -static int emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) -{ -int ret; - -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, val); -mutex_unlock (&data->mutex); - -return ret; -} -static int emc1403_get_hyst (struct thermal_data *data,int channel,enum emc1403_reg_map map,long *val) {int hyst, ret;long limit; -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, &limit); + ret =emc1403_get_temp (data, channel, map, &limit);if (ret <0 ) - goto unlock; +return ret; ret =regmap_read (data->regmap,0x21 , &hyst);if (ret <0 ) - goto unlock; +return ret;if (map == temp_min) *val = limit + hyst *1000 ;else *val = limit - hyst *1000 ; -unlock: -mutex_unlock (&data->mutex); -return ret; +return 0 ; }static int emc1403_temp_read (struct thermal_data *data,u32 attr,int channel,long *val)
@@ -423,20 +406,16 @@ static int emc1403_set_hyst(struct thermal_data *data, long val)else val =clamp_val (val,0 ,255000 ); -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data,0 , temp_crit, &limit); + ret =emc1403_get_temp (data,0 , temp_crit, &limit);if (ret <0 ) - goto unlock; +return ret; hyst = limit - val;if (data->chip == emc1428) hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,127 );else hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,255 ); - ret =regmap_write (data->regmap,0x21 , hyst); -unlock: -mutex_unlock (&data->mutex); -return ret; +return regmap_write (data->regmap,0x21 , hyst); } static int emc1403_set_temp(struct thermal_data *data, int channel,
@@ -450,7 +429,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regh = emc1403_temp_regs[channel][map]; regl = emc1403_temp_regs_low[channel][map]; -mutex_lock (&data->mutex);if (regl >=0 ) {if (data->chip == emc1428) val =clamp_val (val,-128000 ,127875 );
@@ -459,7 +437,7 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,125 ); ret =regmap_write (data->regmap, regh, (regval >>3 ) &0xff );if (ret <0 ) - goto unlock; +return ret; ret =regmap_write (data->regmap, regl, (regval &0x07 ) <<5 ); }else {if (data->chip == emc1428)
@@ -469,8 +447,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,1000 ); ret =regmap_write (data->regmap, regh, regval); } -unlock: -mutex_unlock (&data->mutex);return ret; }
@@ -628,8 +604,6 @@ static int emc1403_probe(struct i2c_client *client)if (IS_ERR (data->regmap))return PTR_ERR (data->regmap); -mutex_init (&data->mutex); - hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, data, &emc1403_chip_info,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1245/1424 hwmon: (emc1403) Drop hysteresis for low limit temperature
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marius Cristea <[email protected]>
[ Upstream commit 75f2c0b3690702c90863c2e138cb5520670845ea ]
Remove the hysteresis for low temperature limit, in hardware the hysteresis is applied only to the maxim limit and the critical limit temperature.
--- Documentation/hwmon/emc1403.rst | 8 ++++---- drivers/hwmon/emc1403.c | 27 +++++++++++---------------- 2 files changed, 15 insertions(+), 20 deletions(-)
Documentation/hwmon/emc1403.rst +4 -4
@@ -71,10 +71,10 @@ and EMC14x8 support eight sensors (one internal, seven external). The chips implement three limits for each sensor: low (tempX_min), high (tempX_max) and critical (tempX_crit.) The chips also implement an -hysteresis mechanism which applies to all limits. The relative difference -is stored in a single register on the chip, which means that the relative -difference between the limit and its hysteresis is always the same for -all three limits. +hysteresis mechanism which applies to high and critical limits. The relative +difference is stored in a single register on the chip, which means that the +relative difference between the limit and its hysteresis is always the same +for high and critical limits. This implementation detail implies the following:
drivers/hwmon/emc1403.c +11 -16
@@ -304,10 +304,9 @@ static int emc1403_get_hyst(struct thermal_data *data, int channel, ret =regmap_read (data->regmap,0x21 , &hyst);if (ret <0 )return ret; -if (map == temp_min) - *val = limit + hyst *1000 ; -else - *val = limit - hyst *1000 ; + + *val = limit - hyst *1000 ; +return 0 ; }
@@ -323,9 +322,6 @@ static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, lcase hwmon_temp_input: ret =emc1403_get_temp (data, channel, ema1403_temp_map[attr], val);break ; -case hwmon_temp_min_hyst: - ret =emc1403_get_hyst (data, channel, temp_min, val); -break ;case hwmon_temp_max_hyst: ret =emc1403_get_hyst (data, channel, temp_max, val);break ;
@@ -494,7 +490,6 @@ static umode_t emc1403_temp_is_visible(const void *_data, u32 attr, int channel)case hwmon_temp_max_alarm:case hwmon_temp_crit_alarm:case hwmon_temp_fault: -case hwmon_temp_min_hyst:case hwmon_temp_max_hyst:return 0444 ;case hwmon_temp_min:
@@ -524,35 +519,35 @@ static umode_t emc1403_is_visible(const void *data, enum hwmon_sensor_types typestatic const struct hwmon_channel_info *const emc1403_info[] = {HWMON_CHANNEL_INFO (temp,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1246/1424 ksmbd: Do not skip lock checks for single-byte ranges
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit d40c24634fe077a0dc91fd11fccf44ce12b454d5 ]
check_lock_range() uses inclusive ranges. Its callers pass the end offset as start + length - 1, so start == end represents a valid single-byte range rather than an empty range.
The start == end shortcut therefore skips mandatory byte-range lock checks for one-byte reads, writes, copychunk operations and one-byte truncate ranges. A conflicting lock covering that byte is not checked and the operation is allowed to proceed.
Remove the shortcut. The truncate size == inode->i_size case is already handled by only calling check_lock_range() when the new size differs from the current file size.
--- fs/smb/server/vfs.c | 3 --- 1 file changed, 3 deletions(-)
fs/smb/server/vfs.c +0 -3
@@ -333,9 +333,6 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,struct file_lock_context *ctx =locks_inode_context (file_inode (filp));int error =0 ; -if (start == end) -return 0 ; -if (!ctx ||list_empty_careful (&ctx->flc_posix))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1247/1424 smb: server: fix leak of ksmbd_ipc_login_request_ext() returned buffer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Enzo Matsumiya <[email protected]>
[ Upstream commit 1c3ebf832d010c08afe1359215d4121cb1ed2de5 ]
Free it unconditionally after ksmbd_alloc_user() calls.
kmemleak splat:
unreferenced object 0xffff888103b83540 (size 192):
comm "pool-0", pid 16970, jiffies 4377290937
hex dump (first 32 bytes):
00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc 408ccc66):
__kvmalloc_node_noprof+0x730/0x920
handle_generic_event+0xec/0x1a0 [ksmbd]
genl_family_rcv_msg_doit+0xe0/0x130
genl_rcv_msg+0x181/0x290
netlink_rcv_skb+0x4f/0x100
genl_rcv+0x28/0x40
netlink_unicast+0x1e6/0x2c0
netlink_sendmsg+0x20a/0x450
____sys_sendmsg+0x2e8/0x310
___sys_sendmsg+0x78/0xc0
__sys_sendmsg+0x63/0xc0
do_syscall_64+0xa1/0x670
entry_SYSCALL_64_after_hwframe+0x76/0x7e--- fs/smb/server/auth.c | 1 + fs/smb/server/mgmt/user_config.c | 1 + 2 files changed, 2 insertions(+)
fs/smb/server/auth.c +1 -0
@@ -547,6 +547,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, resp_ext =ksmbd_ipc_login_request_ext (resp->login_response.account); user =ksmbd_alloc_user (&resp->login_response, resp_ext); +kvfree (resp_ext);if (!user) {ksmbd_debug (AUTH ,"login failure\n" ); retval = -ENOMEM ;
fs/smb/server/mgmt/user_config.c +1 -0
@@ -26,6 +26,7 @@ struct ksmbd_user *ksmbd_login_user(const char *account) resp_ext =ksmbd_ipc_login_request_ext (account); user =ksmbd_alloc_user (resp, resp_ext); +kvfree (resp_ext); out:kvfree (resp);return user;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1248/1424 ksmbd: validate ipc response length before dereferencing its fields
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunseong Kim <[email protected]>
[ Upstream commit e9b33376bd07bca4175f7bcc2d6034ef250f8181 ]
ipc_validate_msg() computes the expected message size by reading length fields out of the response buffer supplied by the userspace ksmbd daemon (payload_sz, session_key_len, ngroups, ...). Those fields are read before the buffer is verified to be large enough to contain the struct they belong to, so a short response makes the read land past the end of the allocation.
handle_response() sizes entry->response purely from the netlink attribute length (nla_len()) and only guards the leading handle read, so the daemon can install a response as small as the kmalloc-8 object seen below. When ipc_msg_send_request() then calls ipc_validate_msg() for a KSMBD_EVENT_RPC_REQUEST, the cast to struct ksmbd_rpc_command reads resp->payload_sz at offset 8 of an 8-byte allocation:
[ 3697.841381] ================================================================== [ 3697.844099] BUG: KASAN: slab-out-of-bounds in ipc_msg_send_request+0x763/0x800 [ 3697.846604] Read of size 4 at addr ffff888105f95910 by task kworker/4:3/20682 [ 3697.849061] [ 3697.849801] CPU: 4 UID: 0 PID: 20682 Comm: kworker/4:3 Not tainted 7.2.0-rc3-next-20260717-virtme #117 PREEMPT(lazy) [ 3697.850077] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 3697.850303] Workqueue: ksmbd-io handle_ksmbd_work [ 3697.850592] Call Trace: [ 3697.850794] <TASK> [ 3697.850952] __dump_stack+0x21/0x60 [ 3697.851239] dump_stack_lvl+0xc2/0x100 [ 3697.851528] print_address_description+0x77/0x200 [ 3697.851816] ? ipc_msg_send_request+0x763/0x800 [ 3697.852024] print_report+0x58/0x70 [ 3697.852316] kasan_report+0x117/0x150 [ 3697.852585] ? down_write+0x146/0x1f0 [ 3697.852809] ? ipc_msg_send_request+0x763/0x800 [ 3697.853082] ipc_msg_send_request+0x763/0x800 [ 3697.853385] ? __pfx_ipc_msg_send_request+0x10/0x10 [ 3697.853604] ? kasan_unpoison+0x48/0x70 [ 3697.853936] ? __pfx___up_read+0x10/0x10 [ 3697.854221] ksmbd_rpc_ioctl+0x380/0x520 [ 3697.854542] ? __pfx_ksmbd_rpc_ioctl+0x10/0x10 [ 3697.854757] ? kasan_unpoison+0x48/0x70 [ 3697.854962] ? copy_from_kernel_nofault+0x32c/0x4e0 [ 3697.855166] ? kasan_unpoison+0x48/0x70 [ 3697.855416] fsctl_pipe_transceive+0x139/0x7a0 [ 3697.855705] ? __pfx_copy_from_kernel_nofault+0x10/0x10 [ 3697.855937] ? __pfx_fsctl_pipe_transceive+0x10/0x10 [ 3697.856388] ? __sanitizer_cov_trace_switch+0x7b/0x140 [ 3697.856620] smb2_ioctl+0x1141/0x3420 [ 3697.856994] ? __pfx_smb2_ioctl+0x10/0x10 [ 3697.857182] ? get_smb2_cmd_val+0xe3/0x1c0 [ 3697.857655] handle_ksmbd_work+0x9ad/0x15e0 [ 3697.858034] ? __pfx_handle_ksmbd_work+0x10/0x10 [ 3697.858251] ? lock_release+0xf7/0x360 [ 3697.858466] ? process_scheduled_works+0x954/0x1600 [ 3697.858698] ? process_scheduled_works+0x954/0x1600 [ 3697.858905] process_scheduled_works+0xc22/0x1600 [ 3697.859368] ? __pfx_process_scheduled_works+0x10/0x10 [ 3697.859637] ? __pfx_assign_work+0x10/0x10 [ 3697.859896] ? lock_is_held_type+0x7b/0x110 [ 3697.860146] worker_thread+0x975/0xee0 [ 3697.860524] ? __pfx_do_raw_spin_lock+0x10/0x10 [ 3697.860830] ? __kthread_parkme+0x21e/0x260 [ 3697.861105] kthread+0x3a6/0x490 [ 3697.861423] ? __pfx_worker_thread+0x10/0x10 [ 3697.861643] ? __pfx_kthread+0x10/0x10 [ 3697.861878] ret_from_fork+0x55a/0xa20 [ 3697.862194] ? __pfx_ret_from_fork+0x10/0x10 [ 3697.862480] ? __pfx_kthread+0x10/0x10 [ 3697.862714] ret_from_fork_asm+0x1a/0x30 [ 3697.862965] </TASK> [ 3697.863039] [ 3697.938882] Allocated by task 20761: [ 3697.940257] kasan_save_track+0x3e/0x80 [ 3697.941782] __kasan_kmalloc+0x72/0x90 [ 3697.943228] __kvmalloc_node_noprof+0x3e9/0x6a0 [ 3697.944948] handle_generic_event+0x59b/0x750 [ 3697.946592] genl_family_rcv_msg_doit+0x3d6/0x560 [ 3697.946977] genl_rcv_msg+0x67c/0x900 [ 3697.947224] netlink_rcv_skb+0x286/0x580 [ 3697.947488] genl_rcv+0x2d/0x80 [ 3697.947706] netlink_unicast+0x937/0xb70 [ 3697.947993] netlink_sendmsg+0x977/0xc10 [ 3697.948268] __sock_sendmsg+0x264/0x2d0 [ 3697.948536] __sys_sendto+0x4de/0x690 [ 3697.948789] __x64_sys_sendto+0x173/0x380 [ 3697.949069] do_syscall_64+0x13d/0x420 [ 3697.949328] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 3697.949662] [ 3697.949779] The buggy address belongs to the object at ffff888105f95908 [ 3697.949779] which belongs to the cache kmalloc-8 of size 8 [ 3697.950550] The buggy address is located 0 bytes to the right of [ 3697.950550] allocated 8-byte region [ffff888105f95908, ffff888105f95910) [ 3697.951455] [ 3697.951574] The buggy address belongs to the physical page: [ 3697.951958] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888105f951b8 pfn:0x105f95 [ 3697.952571] flags: 0x100000000000200(workingset|node=0|zone=2) [ 3697.952973] page_type: f5(slab) [ 3697.953198] raw: 0100000000000200 ffff888100042640 ffffea0004063610 ffff888100040588 [ 3697.953707] raw: ffff888105f951b8 00000000001c000e 00000000f5000000 0000000000000000 [ 3697.954240] page dumped because: kasan: bad access detected [ 3697.954616] [ 3697.954734] Memory state around the buggy address: [ 3697.955063] ffff888105f95800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fa [ 3697.955534] ffff888105f95880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956006] >ffff888105f95900: fc 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956477] ^ [ 3697.956728] ffff888105f95980: fc fc fc fa fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.957202] ffff888105f95a00: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc [ 3697.957671] ==================================================================
The final "entry->msg_sz != msg_sz" comparison cannot help: the offending read has already happened by the time it runs. Every case in the switch shares this pattern.
Floor entry->msg_sz against the base struct of each event type before dereferencing any of its length fields. On failure ipc_msg_send_request() already frees the response and returns NULL, so callers stay safe.
The malformed message originates from the ksmbd.mountd daemon over genl netlink rather than a remote SMB client, so triggering it requires a buggy or compromised daemon; it is still an out-of-bounds read the validator is meant to prevent.
--- fs/smb/server/transport_ipc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/smb/server/transport_ipc.c +12 -0
@@ -498,6 +498,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_rpc_command *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_rpc_command )) +return -EINVAL ; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), resp->payload_sz, &msg_sz))return -EINVAL ;
@@ -507,6 +510,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_spnego_authen_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_spnego_authen_response )) +return -EINVAL ; + msg_sz =sizeof (struct ksmbd_spnego_authen_response ) + resp->session_key_len + resp->spnego_blob_len;break ;
@@ -515,6 +521,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_share_config_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_share_config_response )) +return -EINVAL ; +if (resp->payload_sz) {if (resp->payload_sz < resp->veto_list_sz)return -EINVAL ;
@@ -529,6 +538,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_login_response_ext *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_login_response_ext )) +return -EINVAL ; +if (resp->ngroups) {if (resp->ngroups <0 || resp->ngroups >NGROUPS_MAX ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1249/1424 ksmbd: do not advertise unimplemented CA support
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit eebdd3f1157e35a50df5ff2d3d9a305901df3254 ]
ksmbd durable handles are currently in-memory state. There is no persistent open recovery, cluster ownership epoch, fencing, or failover implementation behind the continuous-availability share flag.
Do not advertise SMB2 persistent-handle or continuous-availability capabilities until those guarantees exist. A client requesting DH2Q then falls back to the existing durable V2 behavior rather than being promised a persistent handle that cannot survive a server failure.
Stable-dep-of: 06c7b1d731bc ("ksmbd: free preauth sessions on connection teardown")
--- fs/smb/server/smb2ops.c | 9 +++++---- fs/smb/server/smb2pdu.c | 11 +++++------ 2 files changed, 10 insertions(+), 10 deletions(-)
fs/smb/server/smb2ops.c +5 -4
@@ -262,8 +262,10 @@ void init_smb3_02_server(struct ksmbd_conn *conn)if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; +/* +* Durable handles are in-memory only. Do not advertise persistent +* handles until CA recovery and fencing are implemented. +*/ }/**
@@ -286,8 +288,7 @@ int init_smb3_11_server(struct ksmbd_conn *conn)if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; +/* See init_smb3_02_server(): persistent handles require CA recovery. */ INIT_LIST_HEAD (&conn->preauth_sess_table);return 0 ;
fs/smb/server/smb2pdu.c +5 -6
@@ -2036,12 +2036,11 @@ int smb2_tree_connect(struct ksmbd_work *work)write_unlock (&sess->tree_conns_lock); rsp->StructureSize =cpu_to_le16 (16 ); out_err1: -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share && -test_share_config_flag (share, -KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY )) - rsp->Capabilities =SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY ; -else - rsp->Capabilities =0 ; +/* +* A configured CA share is not continuously available until persistent +* open recovery, ownership fencing, and failover are implemented. +*/ + rsp->Capabilities =0 ; rsp->Reserved =0 ;/* default manual caching */ rsp->ShareFlags =SMB2_SHAREFLAG_MANUAL_CACHING ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1250/1424 ksmbd: free preauth sessions on connection teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 06c7b1d731bc105a8644f1b70165ba8b9416cbab ]
SMB3.1.1 multichannel binding preserves the preauthentication hash in a preauth_session between the NTLM negotiate and authenticate requests. The binding NTLM negotiate allocates this object and returns STATUS_MORE_PROCESSING_REQUIRED. If the client disconnects before it sends the authenticate request, neither the authenticate nor error cleanup paths free the object.
Release any remaining preauthentication sessions when tearing down the connection. Initialize the list when allocating the connection so that this cleanup is safe regardless of the negotiated dialect.
--- fs/smb/server/connection.c | 3 +++ fs/smb/server/mgmt/user_session.c | 11 +++++++++++ fs/smb/server/mgmt/user_session.h | 1 + fs/smb/server/smb2ops.c | 2 -- 4 files changed, 15 insertions(+), 2 deletions(-)
fs/smb/server/connection.c +3 -0
@@ -11,6 +11,7 @@#include "server.h" #include "smb_common.h" #include "mgmt/ksmbd_ida.h" +#include "mgmt/user_session.h" #include "connection.h" #include "transport_tcp.h" #include "transport_rdma.h"
@@ -123,6 +124,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)kvfree (conn->request_buf);kfree (conn->preauth_info);kfree (conn->mechToken); +ksmbd_preauth_session_destroy (conn);ksmbd_conn_put (conn); }
@@ -161,6 +163,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)init_waitqueue_head (&conn->r_count_q);INIT_LIST_HEAD (&conn->requests);INIT_LIST_HEAD (&conn->async_requests); +INIT_LIST_HEAD (&conn->preauth_sess_table);spin_lock_init (&conn->request_lock);spin_lock_init (&conn->credits_lock);ida_init (&conn->async_ida);
fs/smb/server/mgmt/user_session.c +11 -0
@@ -370,6 +370,17 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,return sess; } +void ksmbd_preauth_session_destroy (struct ksmbd_conn *conn) +{ +struct preauth_session *sess, *tmp; + +list_for_each_entry_safe (sess, tmp, &conn->preauth_sess_table, + preauth_entry) { +list_del (&sess->preauth_entry); +kfree (sess); + } +} +void destroy_previous_session (struct ksmbd_conn *conn,struct ksmbd_user *user,u64 id) {
fs/smb/server/mgmt/user_session.h +1 -0
@@ -100,6 +100,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, struct ksmbd_user *user, u64 id);struct preauth_session *ksmbd_preauth_session_alloc (struct ksmbd_conn *conn,u64 sess_id); +void ksmbd_preauth_session_destroy (struct ksmbd_conn *conn);struct preauth_session *ksmbd_preauth_session_lookup (struct ksmbd_conn *conn,unsigned long long id);
fs/smb/server/smb2ops.c +0 -2
@@ -289,8 +289,6 @@ int init_smb3_11_server(struct ksmbd_conn *conn) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ;/* See init_smb3_02_server(): persistent handles require CA recovery. */ - -INIT_LIST_HEAD (&conn->preauth_sess_table);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1251/1424 smb/server: fix invalid pointer dereference in ksmbd_stop_durable_scavenger()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit bef46b604732d83f8da29f782868de4d25bf972c ]
See the procedure below:
ksmbd_launch_ksmbd_durable_scavenger
durable_scavenger_running = true
server_conf.dh_task = kthread_run() // fail, dh_task is an ERR_PTR()
server_ctrl_handle_reset
ksmbd_stop_durable_scavenger kthread_stop(server_conf.dh_task) // invalid pointer
--- fs/smb/server/vfs_cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/smb/server/vfs_cache.c +4 -1
@@ -1103,9 +1103,12 @@ void ksmbd_launch_ksmbd_durable_scavenger(void) server_conf.dh_task =kthread_run (ksmbd_durable_scavenger, (void *)NULL ,"ksmbd-durable-scavenger" ); -if (IS_ERR (server_conf.dh_task)) +if (IS_ERR (server_conf.dh_task)) {pr_err ("cannot start conn thread, err : %ld\n" ,PTR_ERR (server_conf.dh_task)); + server_conf.dh_task =NULL ; + durable_scavenger_running = false; + }mutex_unlock (&durable_scavenger_lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1252/1424 smb/server: preserve error status in smb2_handle_negotiate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit 73541bd2bab77e7e8e89b1edb5d342f4190dd4d0 ]
smb2_handle_negotiate() records specific failures such as STATUS_INVALID_PARAMETER or STATUS_NOT_SUPPORTED.
--- fs/smb/server/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +2 -2
@@ -1163,7 +1163,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) GFP_KERNEL);if (!conn->preauth_info) { rc = -ENOMEM ; - rsp->hdr.Status =STATUS_INVALID_PARAMETER ; + rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ; goto err_out; }
@@ -1260,7 +1260,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)ksmbd_conn_set_need_setup (conn); err_out: -if (rc) +if (rc && rsp->hdr.Status ==STATUS_SUCCESS ) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;if (!rc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1253/1424 lwt_bpf: Restore reserved headroom after xmit program
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit 5fe7007aed9ad069b2bd77e5d0c875c64f5c0269 ]
ip_finish_output2() expands an skb to LL_RESERVED_SPACE(dev) before LWT xmit. An LWT_XMIT BPF program can then modify the skb head and still return BPF_OK, so bpf_xmit() rechecks the remaining headroom before the skb continues to neighbour output.
That recheck uses dst->dev->hard_header_len. This is not enough for the neighbour cached-header path: neigh_hh_output() copies the cached hardware header using the aligned hh_cache size, HH_DATA_MOD for short headers or HH_DATA_ALIGN(hh_len) otherwise.
On Ethernet, hard_header_len is 14 but the cached copy needs 16 bytes. If an LWT_XMIT BPF program calls bpf_skb_change_head(skb, 1, 0), the skb can still have 15 bytes of headroom after the program. The existing check accepts that, after which neigh_hh_output() hits its headroom warning and drops the skb.
Use LL_RESERVED_SPACE(dst->dev) in the post-BPF headroom check to match the reservation made before LWT xmit.
--- net/core/lwt_bpf.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
net/core/lwt_bpf.c +9 -6
@@ -158,10 +158,10 @@ static int bpf_output(struct net *net, struct sock *sk, struct sk_buff *skb)return dst->lwtstate->orig_output (net, sk, skb); } -static int xmit_check_hhlen (struct sk_buff *skb,int hh_len) +static int xmit_check_headroom (struct sk_buff *skb,int hroom) { -if (skb_headroom (skb) < hh_len) { -int nhead =HH_DATA_ALIGN (hh_len -skb_headroom (skb)); +if (skb_headroom (skb) < hroom) { +int nhead = hroom -skb_headroom (skb);if (pskb_expand_head (skb, nhead,0 ,GFP_ATOMIC ))return -ENOMEM ;
@@ -273,7 +273,7 @@ static int bpf_xmit(struct sk_buff *skb) bpf =bpf_lwt_lwtunnel (dst->lwtstate);if (bpf->xmit.prog) { -int hh_len = dst->dev->hard_header_len; +int hroom =LL_RESERVED_SPACE (dst->dev);__be16 proto = skb->protocol;int ret;
@@ -289,9 +289,12 @@ static int bpf_xmit(struct sk_buff *skb)return -EINVAL ; }/* If the header was expanded, headroom might be too -* small for L2 header to come, expand as needed. +* small for the L2 header to come, expand as needed. +* neigh_hh_output() copies the cached header in +* HH_DATA_MOD aligned chunks, so match the reservation +* made before LWT xmit. */ - ret =xmit_check_hhlen (skb, hh_len); + ret =xmit_check_headroom (skb, hroom);if (unlikely (ret))return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1254/1424 m68k: nfcon: Do not call console_is_registered() in nfcon_device()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andreas Schwab <[email protected]>
[ Upstream commit 2f8e3cad53b5c36ab0ed5d3195bfc55c59ea61a5 ]
Since 7c2af0f634f1 ("tty: tty_io: use console_list_lock for list synchronization") show_cons_active() calls the .device() method under the console_list_lock, but console_is_registered() tries to acquire console_list_lock as well, causing a deadlock. It should not be necessary to check console_is_registered() here since the function should not be called in the fist place when the console is not registered.
--- arch/m68k/emu/nfcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/m68k/emu/nfcon.c +1 -1
@@ -49,7 +49,7 @@ static void nfcon_write(struct console *con, const char *str,static struct tty_driver *nfcon_device (struct console *con,int *index) { *index =0 ; -return console_is_registered (con) ? nfcon_tty_driver :NULL ; +return nfcon_tty_driver; }static struct console nf_console = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1255/1424 bpf: Reject negative optlen in cgroup getsockopt hook
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit 1b5aacd5b2419b0790e955e466d389a61c79b4b1 ]
A cgroup getsockopt BPF program can shrink ctx->optlen after the kernel getsockopt handler has run. The kernel-buffer variant, used by TCP_ZEROCOPY_RECEIVE, only rejects values larger than the original length.
If BPF writes a negative optlen, that value is accepted and propagated back to the TCP getsockopt code. It can then be passed to copy_to_sockptr() as a size_t and trigger the hardened usercopy bytes > INT_MAX warning.
Reject negative ctx.optlen in __cgroup_bpf_run_filter_getsockopt_kern(), matching the lower-bound validation already present in the sockptr-based getsockopt hook.
--- kernel/bpf/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/cgroup.c +1 -1
@@ -2061,7 +2061,7 @@ int __cgroup_bpf_run_filter_getsockopt_kern(struct sock *sk, int level,if (ret <0 )return ret; -if (ctx.optlen > *optlen) +if (ctx.optlen > *optlen || ctx.optlen <0 )return -EFAULT ;/* BPF programs can shrink the buffer, export the modifications.
Signature · 1 line
2.53.0