5.11.22-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 141/329 PCI: endpoint: Fix missing destroy_workqueue()
In reply to Greg Kroah-HartmanFrom: Yang Yingliang <[email protected]>
[ Upstream commit acaef7981a218813e3617edb9c01837808de063c ]
Add the missing destroy_workqueue() before return from pci_epf_test_init() in the error handling case and add destroy_workqueue() in pci_epf_test_exit().
--- drivers/pci/endpoint/functions/pci-epf-test.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/pci/endpoint/functions/pci-epf-test.c +3 -0
@@ -922,6 +922,7 @@ static int __init pci_epf_test_init(void) ret =pci_epf_register_driver (&test_driver);if (ret) { +destroy_workqueue (kpcitest_workqueue);pr_err ("Failed to register pci epf test driver --> %d\n" , ret);return ret; }
@@ -932,6 +933,8 @@ module_init(pci_epf_test_init); static void __exit pci_epf_test_exit(void) { +if (kpcitest_workqueue) +destroy_workqueue (kpcitest_workqueue);pci_epf_unregister_driver (&test_driver); }module_exit (pci_epf_test_exit);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 142/329 remoteproc: pru: Fixup interrupt-parent logic for fw events
In reply to Greg Kroah-HartmanFrom: Suman Anna <[email protected]>
[ Upstream commit 6d1f2803cb6b414c2e45fa64d1fdad6b581e1e88 ]
The PRU firmware interrupt mapping logic in pru_handle_intrmap() uses of_irq_find_parent() with PRU device node to get a handle to the PRUSS Interrupt Controller at present. This logic however requires that the PRU nodes always define a interrupt-parent property. This property is neither a required/defined property as per the PRU remoteproc binding, nor is relevant from a DT node point of view without any associated interrupts. The current logic finds a wrong interrupt controller and fails to perform proper mapping without any interrupt-parent property in the PRU nodes.
Fix this logic to always find and use the sibling interrupt controller. Also, while at this, fix the acquired interrupt controller device node reference properly.
--- drivers/remoteproc/pru_rproc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/remoteproc/pru_rproc.c +12 -3
@@ -284,7 +284,7 @@ static int pru_handle_intrmap(struct rproc *rproc)struct pru_rproc *pru = rproc->priv;struct pru_irq_rsc *rsc = pru->pru_interrupt_map;struct irq_fwspec fwspec; -struct device_node *irq_parent; +struct device_node *parent, *irq_parent;int i, ret =0 ;/* not having pru_interrupt_map is not an error */
@@ -312,9 +312,16 @@ static int pru_handle_intrmap(struct rproc *rproc)/* * parse and fill in system event to interrupt channel and -* channel-to-host mapping +* channel-to-host mapping. The interrupt controller to be used +* for these mappings for a given PRU remoteproc is always its +* corresponding sibling PRUSS INTC node. */ - irq_parent =of_irq_find_parent (pru->dev->of_node); + parent =of_get_parent (dev_of_node (pru->dev)); +if (!parent) +return -ENODEV ; + + irq_parent =of_get_child_by_name (parent,"interrupt-controller" ); +of_node_put (parent);if (!irq_parent) {kfree (pru->mapped_irq);return -ENODEV ;
@@ -337,11 +344,13 @@ static int pru_handle_intrmap(struct rproc *rproc) goto map_fail; } } +of_node_put (irq_parent);return ret; map_fail:pru_dispose_irq_mapping (pru); +of_node_put (irq_parent);return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 143/329 remoteproc: pru: Fix wrong success return value for fw events
In reply to Greg Kroah-HartmanFrom: Suman Anna <[email protected]>
[ Upstream commit 1fe72bcfac087dba5ab52778e0646ed9e145cd32 ]
The irq_create_fwspec_mapping() returns a proper virq value on success and 0 upon any failure. The pru_handle_intrmap() treats this as an error and disposes all firmware event mappings correctly, but is returning this incorrect value as is, letting the pru_rproc_start() interpret it as a success and boot the PRU.
Fix this by returning an error value back upon any such failure. While at this, revise the error trace to print some meaningful info about the failed event.
--- drivers/remoteproc/pru_rproc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/remoteproc/pru_rproc.c +4 -2
@@ -339,8 +339,10 @@ static int pru_handle_intrmap(struct rproc *rproc) pru->mapped_irq[i] =irq_create_fwspec_mapping (&fwspec);if (!pru->mapped_irq[i]) { -dev_err (dev,"failed to get virq\n" ); - ret = pru->mapped_irq[i]; +dev_err (dev,"failed to get virq for fw mapping %d: event %d chnl %d host %d\n" , + i, fwspec.param[0 ], fwspec.param[1 ], + fwspec.param[2 ]); + ret = -EINVAL ; goto map_fail; } }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 144/329 remoteproc: pru: Fix and cleanup firmware interrupt mapping logic
In reply to Greg Kroah-HartmanFrom: Suman Anna <[email protected]>
[ Upstream commit 880a66e026fbe6a17cd59fe0ee942bbad62a6c26 ]
The PRU firmware interrupt mappings are configured and unconfigured in .start() and .stop() callbacks respectively using the variables 'evt_count' and a 'mapped_irq' pointer. These variables are modified only during these callbacks but are not re-initialized/reset properly during unwind or failure paths. These stale values caused a kernel crash while stopping a PRU remoteproc running a different firmware with no events on a subsequent run after a previous run that was running a firmware with events.
Fix this crash by ensuring that the evt_count is 0 and the mapped_irq pointer is set to NULL in pru_dispose_irq_mapping(). Also, reset these variables properly during any failures in the .start() callback. While at this, the pru_dispose_irq_mapping() callsites are all made to look the same, moving any conditional logic to inside the function.
--- drivers/remoteproc/pru_rproc.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
drivers/remoteproc/pru_rproc.c +17 -5
@@ -266,12 +266,17 @@ static void pru_rproc_create_debug_entries(struct rproc *rproc)static void pru_dispose_irq_mapping (struct pru_rproc *pru) { -while (pru->evt_count--) { +if (!pru->mapped_irq) +return ; + +while (pru->evt_count) { + pru->evt_count--;if (pru->mapped_irq[pru->evt_count] >0 )irq_dispose_mapping (pru->mapped_irq[pru->evt_count]); }kfree (pru->mapped_irq); + pru->mapped_irq =NULL ; }/*
@@ -307,8 +312,10 @@ static int pru_handle_intrmap(struct rproc *rproc) pru->evt_count = rsc->num_evts; pru->mapped_irq =kcalloc (pru->evt_count,sizeof (unsigned int ),GFP_KERNEL ); -if (!pru->mapped_irq) +if (!pru->mapped_irq) { + pru->evt_count =0 ;return -ENOMEM ; + }/* * parse and fill in system event to interrupt channel and
@@ -317,13 +324,19 @@ static int pru_handle_intrmap(struct rproc *rproc)* corresponding sibling PRUSS INTC node. */ parent =of_get_parent (dev_of_node (pru->dev)); -if (!parent) +if (!parent) { +kfree (pru->mapped_irq); + pru->mapped_irq =NULL ; + pru->evt_count =0 ;return -ENODEV ; + } irq_parent =of_get_child_by_name (parent,"interrupt-controller" );of_node_put (parent);if (!irq_parent) {kfree (pru->mapped_irq); + pru->mapped_irq =NULL ; + pru->evt_count =0 ;return -ENODEV ; }
@@ -398,8 +411,7 @@ static int pru_rproc_stop(struct rproc *rproc)pru_control_write_reg (pru,PRU_CTRL_CTRL , val);/* dispose irq mapping - new firmware can provide new mapping */ -if (pru->mapped_irq) -pru_dispose_irq_mapping (pru); +pru_dispose_irq_mapping (pru);return 0 ; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 145/329 pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
In reply to Greg Kroah-HartmanFrom: Nikola Livic <[email protected]>
[ Upstream commit ed34695e15aba74f45247f1ee2cf7e09d449f925 ]
We (adam zabrocki, alexander matrosov, alexander tereshkin, maksym bazalii) observed the check:
if (fh->size > sizeof(struct nfs_fh))
should not use the size of the nfs_fh struct which includes an extra two bytes from the size field.
struct nfs_fh {
unsigned short size;
unsigned char data[NFS_MAXFHSIZE];
}but should determine the size from data[NFS_MAXFHSIZE] so the memcpy will not write 2 bytes beyond destination. The proposed fix is to compare against the NFS_MAXFHSIZE directly, as is done elsewhere in fs code base.
--- fs/nfs/flexfilelayout/flexfilelayout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/flexfilelayout/flexfilelayout.c +1 -1
@@ -106,7 +106,7 @@ static int decode_nfs_fh(struct xdr_stream *xdr, struct nfs_fh *fh)if (unlikely (!p))return -ENOBUFS ; fh->size =be32_to_cpup (p++); -if (fh->size >sizeof (struct nfs_fh )) { +if (fh->size >NFS_MAXFHSIZE ) {printk (KERN_ERR "NFS flexfiles: Too big fh received %d\n" , fh->size);return -EOVERFLOW ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 146/329 NFSv4.2 fix handling of sr_eof in SEEKs reply
In reply to Greg Kroah-HartmanFrom: Olga Kornievskaia <[email protected]>
[ Upstream commit 73f5c88f521a630ea1628beb9c2d48a2e777a419 ]
Currently the client ignores the value of the sr_eof of the SEEK operation. According to the spec, if the server didn't find the requested extent and reached the end of the file, the server would return sr_eof=true. In case the request for DATA and no data was found (ie in the middle of the hole), then the lseek expects that ENXIO would be returned.
--- fs/nfs/nfs42proc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/nfs/nfs42proc.c +4 -1
@@ -665,7 +665,10 @@ static loff_t _nfs42_proc_llseek(struct file *filep,if (status)return status; -return vfs_setpos (filep, res.sr_offset, inode->i_sb->s_maxbytes); +if (whence ==SEEK_DATA && res.sr_eof) +return -NFS4ERR_NXIO ; +else +return vfs_setpos (filep, res.sr_offset, inode->i_sb->s_maxbytes); }loff_t nfs42_proc_llseek (struct file *filep,loff_t offset,int whence)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 147/329 SUNRPC: Move fault injection call sites
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 7638e0bfaed1b653d3ca663e560e9ffb44bb1030 ]
I've hit some crashes that occur in the xprt_rdma_inject_disconnect path. It appears that, for some provides, rdma_disconnect() can take so long that the transport can disconnect and release its hardware resources while rdma_disconnect() is still running, resulting in a UAF in the provider.
The transport's fault injection method may depend on the stability of transport data structures. That means it needs to be invoked only from contexts that hold the transport write lock.
--- net/sunrpc/clnt.c | 1 - net/sunrpc/xprt.c | 6 ++++-- net/sunrpc/xprtrdma/transport.c | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-)
net/sunrpc/clnt.c +0 -1
@@ -1799,7 +1799,6 @@ call_allocate(struct rpc_task *task) status = xprt->ops->buf_alloc (task);trace_rpc_buf_alloc (task, status); -xprt_inject_disconnect (xprt);if (status ==0 )return ;if (status != -ENOMEM ) {
net/sunrpc/xprt.c +4 -2
@@ -1483,7 +1483,10 @@ bool xprt_prepare_transmit(struct rpc_task *task)void xprt_end_transmit (struct rpc_task *task) { -xprt_release_write (task->tk_rqstp->rq_xprt, task); +struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; + +xprt_inject_disconnect (xprt); +xprt_release_write (xprt, task); }/**
@@ -1885,7 +1888,6 @@ void xprt_release(struct rpc_task *task)spin_unlock (&xprt->transport_lock);if (req->rq_buffer) xprt->ops->buf_free (task); -xprt_inject_disconnect (xprt);xdr_free_bvec (&req->rq_rcv_buf);xdr_free_bvec (&req->rq_snd_buf);if (req->rq_cred !=NULL )
net/sunrpc/xprtrdma/transport.c +4 -2
@@ -262,8 +262,10 @@ xprt_rdma_connect_worker(struct work_struct *work)* xprt_rdma_inject_disconnect - inject a connection fault * @xprt: transport context * -* If @xprt is connected, disconnect it to simulate spurious connection -* loss. +* If @xprt is connected, disconnect it to simulate spurious +* connection loss. Caller must hold @xprt's send lock to +* ensure that data structures and hardware resources are +* stable during the rdma_disconnect() call. */ static void xprt_rdma_inject_disconnect (struct rpc_xprt *xprt)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 148/329 SUNRPC: Remove trace_xprt_transmit_queued
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 6cf23783f750634e10daeede48b0f5f5d64ebf3a ]
This tracepoint can crash when dereferencing snd_task because when some transports connect, they put a cookie in that field instead of a pointer to an rpc_task.
BUG: KASAN: use-after-free in trace_event_raw_event_xprt_writelock_event+0x141/0x18e [sunrpc] Read of size 2 at addr ffff8881a83bd3a0 by task git/331872 CPU: 11 PID: 331872 Comm: git Tainted: G S 5.12.0-rc2-00007-g3ab6e585a7f9 #1453 Hardware name: Supermicro SYS-6028R-T/X10DRi, BIOS 1.1a 10/16/2015 Call Trace: dump_stack+0x9c/0xcf print_address_description.constprop.0+0x18/0x239 kasan_report+0x174/0x1b0 trace_event_raw_event_xprt_writelock_event+0x141/0x18e [sunrpc] xprt_prepare_transmit+0x8e/0xc1 [sunrpc] call_transmit+0x4d/0xc6 [sunrpc]
--- include/trace/events/sunrpc.h | 1 - net/sunrpc/xprt.c | 2 -- 2 files changed, 3 deletions(-)
include/trace/events/sunrpc.h +0 -1
@@ -1141,7 +1141,6 @@ DECLARE_EVENT_CLASS(xprt_writelock_event,DEFINE_WRITELOCK_EVENT (reserve_xprt);DEFINE_WRITELOCK_EVENT (release_xprt); -DEFINE_WRITELOCK_EVENT (transmit_queued); DECLARE_EVENT_CLASS(xprt_cong_event, TP_PROTO(
net/sunrpc/xprt.c +0 -2
@@ -1469,8 +1469,6 @@ bool xprt_prepare_transmit(struct rpc_task *task)struct rpc_xprt *xprt = req->rq_xprt;if (!xprt_lock_write (xprt, task)) { -trace_xprt_transmit_queued (xprt, task); -/* Race breaker: someone may have transmitted us */ if (!test_bit (RPC_TASK_NEED_XMIT , &task->tk_runstate)) rpc_wake_up_queued_task_set_status(&xprt->sending,
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 149/329 SUNRPC: Handle major timeout in xprt_adjust_timeout()
In reply to Greg Kroah-HartmanFrom: Chris Dion <[email protected]>
[ Upstream commit 09252177d5f924f404551b4b4eded5daa7f04a3a ]
Currently if a major timeout value is reached, but the minor value has not been reached, an ETIMEOUT will not be sent back to the caller. This can occur if the v4 server is not responding to requests and retrans is configured larger than the default of two.
For example, A TCP mount with a configured timeout value of 50 and a retransmission count of 3 to a v4 server which is not responding:
1. Initial value and increment set to 5s, maxval set to 20s, retries at 3
2. Major timeout is set to 20s, minor timeout set to 5s initially
3. xport_adjust_timeout() is called after 5s, retry with 10s timeout, minor timeout is bumped to 10s
4. And again after another 10s, 15s total time with minor timeout set to 15s
5. After 20s total time xport_adjust_timeout is called as major timeout is reached, but skipped because the minor timeout is not reached
- After this time the cpu spins continually calling xport_adjust_timeout() and returning 0 for 10 seconds. As seen on perf sched:
39243.913182 [0005] mount.nfs[3794] 4607.938 0.017 9746.863
6. This continues until the 15s minor timeout condition is reached (in this case for 10 seconds). After which the ETIMEOUT is processed back to the caller, the cpu spinning stops, and normal operations continue
--- net/sunrpc/xprt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/sunrpc/xprt.c +2 -2
@@ -698,9 +698,9 @@ int xprt_adjust_timeout(struct rpc_rqst *req)const struct rpc_timeout *to = req->rq_task->tk_client->cl_timeout;int status =0 ; -if (time_before (jiffies, req->rq_minortimeo)) -return status;if (time_before (jiffies, req->rq_majortimeo)) { +if (time_before (jiffies, req->rq_minortimeo)) +return status;if (to->to_exponential) req->rq_timeout <<=1 ;else
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 150/329 thermal/drivers/tsens: Fix missing put_device error
In reply to Greg Kroah-HartmanFrom: Guangqing Zhu <[email protected]>
[ Upstream commit f4136863e8899fa0554343201b78b9e197c78a78 ]
Fixes coccicheck error:
drivers/thermal/qcom/tsens.c:759:4-10: ERROR: missing put_device; call of_find_device_by_node on line 715, but without a corresponding object release within this function.
--- drivers/thermal/qcom/tsens.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/thermal/qcom/tsens.c +4 -2
@@ -755,8 +755,10 @@ int __init init_common(struct tsens_priv *priv)for (i =VER_MAJOR ; i <=VER_STEP ; i++) { priv->rf[i] =devm_regmap_field_alloc (dev, priv->srot_map, priv->fields[i]); -if (IS_ERR (priv->rf[i])) -return PTR_ERR (priv->rf[i]); +if (IS_ERR (priv->rf[i])) { + ret =PTR_ERR (priv->rf[i]); + goto err_put_device; + } } ret =regmap_field_read (priv->rf[VER_MINOR ], &ver_minor);if (ret)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 151/329 NFSv4.x: Dont return NFS4ERR_NOMATCHING_LAYOUT if were unmounting
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit 8926cc8302819be9e67f70409ed001ecb2c924a9 ]
If the NFS super block is being unmounted, then we currently may end up telling the server that we've forgotten the layout while it is actually still in use by the client.
In that case, just assume that the client will soon return the layout anyway, and so return NFS4ERR_DELAY in response to the layout recall.
--- fs/nfs/callback_proc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
fs/nfs/callback_proc.c +9 -8
@@ -137,12 +137,12 @@ static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp,list_for_each_entry_rcu (lo, &server->layouts, plh_layouts) {if (!pnfs_layout_is_valid (lo))continue ; -if (stateid !=NULL && - !nfs4_stateid_match_other (stateid, &lo->plh_stateid)) +if (!nfs4_stateid_match_other (stateid, &lo->plh_stateid))continue ; -if (!nfs_sb_active (server->super)) -continue ; - inode =igrab (lo->plh_inode); +if (nfs_sb_active (server->super)) + inode =igrab (lo->plh_inode); +else + inode =ERR_PTR (-EAGAIN );rcu_read_unlock ();if (inode)return inode;
@@ -176,9 +176,10 @@ static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp,continue ;if (nfsi->layout != lo)continue ; -if (!nfs_sb_active (server->super)) -continue ; - inode =igrab (lo->plh_inode); +if (nfs_sb_active (server->super)) + inode =igrab (lo->plh_inode); +else + inode =ERR_PTR (-EAGAIN );rcu_read_unlock ();if (inode)return inode;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 152/329 nfsd: ensure new clients break delegations
In reply to Greg Kroah-HartmanFrom: J. Bruce Fields <[email protected]>
[ Upstream commit 217fd6f625af591e2866bebb8cda778cf85bea2e ]
If nfsd already has an open file that it plans to use for IO from another, it may not need to do another vfs open, but it still may need to break any delegations in case the existing opens are for another client.
Symptoms are that we may incorrectly fail to break a delegation on a write open from a different client, when the delegation-holding client already has a write open.
--- fs/nfsd/nfs4state.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +19 -5
@@ -4874,6 +4874,11 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,if (nf)nfsd_file_put (nf); + status =nfserrno (nfsd_open_break_lease (cur_fh->fh_dentry->d_inode, + access)); +if (status) + goto out_put_access; + status =nfsd4_truncate (rqstp, cur_fh, open);if (status) goto out_put_access;
@@ -6856,11 +6861,20 @@ out:static __be32 nfsd_test_lock (struct svc_rqst *rqstp,struct svc_fh *fhp,struct file_lock *lock) {struct nfsd_file *nf; -__be32 err =nfsd_file_acquire (rqstp, fhp,NFSD_MAY_READ , &nf); -if (!err) { - err =nfserrno (vfs_test_lock (nf->nf_file, lock)); -nfsd_file_put (nf); - } +__be32 err; + + err =nfsd_file_acquire (rqstp, fhp,NFSD_MAY_READ , &nf); +if (err) +return err; +fh_lock (fhp);/* to block new leases till after test_lock: */ + err =nfserrno (nfsd_open_break_lease (fhp->fh_dentry->d_inode, +NFSD_MAY_READ )); +if (err) + goto out; + err =nfserrno (vfs_test_lock (nf->nf_file, lock)); +out: +fh_unlock (fhp); +nfsd_file_put (nf);return err; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 153/329 rtc: fsl-ftm-alarm: add MODULE_TABLE()
In reply to Greg Kroah-HartmanFrom: Michael Walle <[email protected]>
[ Upstream commit 7fcb86185978661c9188397d474f90364745b8d9 ]
The module doesn't load automatically. Fix it by adding the missing MODULE_TABLE().
--- drivers/rtc/rtc-fsl-ftm-alarm.c | 1 + 1 file changed, 1 insertion(+)
drivers/rtc/rtc-fsl-ftm-alarm.c +1 -0
@@ -310,6 +310,7 @@ static const struct of_device_id ftm_rtc_match[] = { { .compatible = "fsl,lx2160a-ftm-alarm", }, { }, }; +MODULE_DEVICE_TABLE (of, ftm_rtc_match);static const struct acpi_device_id ftm_imx_acpi_ids[] = { {"NXP0014" ,},
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 154/329 dmaengine: idxd: Fix potential null dereference on pointer status
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
[ Upstream commit 28ac8e03c43dfc6a703aa420d18222540b801120 ]
There are calls to idxd_cmd_exec that pass a null status pointer however a recent commit has added an assignment to *status that can end up with a null pointer dereference. The function expects a null status pointer sometimes as there is a later assignment to *status where status is first null checked. Fix the issue by null checking status before making the assignment.
Addresses-Coverity: ("Explicit null dereferenced")
--- drivers/dma/idxd/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/idxd/device.c +2 -1
@@ -451,7 +451,8 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,if (idxd_device_is_halted (idxd)) {dev_warn (&idxd->pdev->dev,"Device is HALTED!\n" ); - *status =IDXD_CMDSTS_HW_ERR ; +if (status) + *status =IDXD_CMDSTS_HW_ERR ;return ; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 155/329 dmaengine: idxd: fix dma device lifetime
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 397862855619271296e46d10f7dfa7bafe71eb81 ]
The devm managed lifetime is incompatible with 'struct device' objects that resides in idxd context. This is one of the series that clean up the idxd driver 'struct device' lifetime. Remove embedding of dma_device and dma_chan in idxd since it's not the only interface that idxd will use. The freeing of the dma_device will be managed by the ->release() function.
--- drivers/dma/idxd/device.c | 2 - drivers/dma/idxd/dma.c | 77 ++++++++++++++++++++++++++++++++------- drivers/dma/idxd/idxd.h | 18 +++++++-- 3 files changed, 79 insertions(+), 18 deletions(-)
drivers/dma/idxd/device.c +0 -2
@@ -186,8 +186,6 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq) desc->id = i; desc->wq = wq; desc->cpu =-1 ; -dma_async_tx_descriptor_init (&desc->txd, &wq->dma_chan); - desc->txd.tx_submit = idxd_dma_tx_submit; }return 0 ;
drivers/dma/idxd/dma.c +64 -13
127 lines not on this page · raw message
drivers/dma/idxd/idxd.h +15 -3
@@ -14,6 +14,9 @@extern struct kmem_cache *idxd_desc_pool; +struct idxd_device ; +struct idxd_wq ; +#define IDXD_REG_TIMEOUT 50#define IDXD_DRAIN_TIMEOUT 5000
@@ -96,6 +99,11 @@ enum idxd_complete_type { IDXD_COMPLETE_DEV_FAIL, }; +struct idxd_dma_chan { +struct dma_chan chan; +struct idxd_wq *wq; +}; +struct idxd_wq {void __iomem *portal;struct device conf_dev;
@@ -125,7 +133,7 @@ struct idxd_wq {int compls_size;struct idxd_desc **descs;struct sbitmap_queue sbq; -struct dma_chan dma_chan; +struct idxd_dma_chan *idxd_chan;char name[WQ_NAME_SIZE +1 ];u64 max_xfer_bytes;u32 max_batch_size;
@@ -162,6 +170,11 @@ enum idxd_device_flag { IDXD_FLAG_PASID_ENABLED, }; +struct idxd_dma_dev { +struct idxd_device *idxd; +struct dma_device dma; +}; +struct idxd_device {enum idxd_type type;struct device conf_dev;
@@ -210,7 +223,7 @@ struct idxd_device {int num_wq_irqs;struct idxd_irq_entry *irq_entries; -struct dma_device dma_dev; +struct idxd_dma_dev *idxd_dma;struct workqueue_struct *wq;struct work_struct work; };
@@ -363,7 +376,6 @@ void idxd_unregister_dma_channel(struct idxd_wq *wq);void idxd_parse_completion_status (u8 status,enum dmaengine_tx_result *res);void idxd_dma_complete_txd (struct idxd_desc *desc,enum idxd_complete_type comp_type); -dma_cookie_t idxd_dma_tx_submit (struct dma_async_tx_descriptor *tx);/* cdev */ int idxd_cdev_register (void );
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 156/329 dmaengine: idxd: cleanup pci interrupt vector allocation management
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 5fc8e85ff12ce0530ac658686902a0ee64600f56 ]
The devm managed lifetime is incompatible with 'struct device' objects that resides in idxd context. This is one of the series that clean up the idxd driver 'struct device' lifetime. Remove devm managed pci interrupt vectors and replace with unmanged allocators.
--- drivers/dma/idxd/device.c | 4 +-- drivers/dma/idxd/idxd.h | 2 +- drivers/dma/idxd/init.c | 64 +++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 40 deletions(-)
drivers/dma/idxd/device.c +2 -2
@@ -19,7 +19,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,/* Interrupt control bits */ void idxd_mask_msix_vector (struct idxd_device *idxd,int vec_id) { -struct irq_data *data =irq_get_irq_data (idxd->msix_entries[vec_id].vector); +struct irq_data *data =irq_get_irq_data (idxd->irq_entries[vec_id].vector);pci_msi_mask_irq (data); }
@@ -36,7 +36,7 @@ void idxd_mask_msix_vectors(struct idxd_device *idxd)void idxd_unmask_msix_vector (struct idxd_device *idxd,int vec_id) { -struct irq_data *data =irq_get_irq_data (idxd->msix_entries[vec_id].vector); +struct irq_data *data =irq_get_irq_data (idxd->irq_entries[vec_id].vector);pci_msi_unmask_irq (data); }
drivers/dma/idxd/idxd.h +1 -1
@@ -36,6 +36,7 @@ struct idxd_device_driver {struct idxd_irq_entry {struct idxd_device *idxd;int id; +int vector;struct llist_head pending_llist;struct list_head work_list;/*
@@ -219,7 +220,6 @@ struct idxd_device {union sw_err_reg sw_err;wait_queue_head_t cmd_waitq; -struct msix_entry *msix_entries;int num_wq_irqs;struct idxd_irq_entry *irq_entries;
drivers/dma/idxd/init.c +27 -37
128 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 157/329 dmaengine: idxd: removal of pcim managed mmio mapping
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit a39c7cd0438ee2f0b859ee1eb86cdc52217d2223 ]
The devm managed lifetime is incompatible with 'struct device' objects that resides in idxd context. This is one of the series that clean up the idxd driver 'struct device' lifetime. Remove pcim_* management of the PCI device and the ioremap of MMIO BAR and replace with unmanaged versions. This is for consistency of removing all the pcim/devm based calls.
--- drivers/dma/idxd/init.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-)
drivers/dma/idxd/init.c +23 -10
@@ -378,32 +378,36 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)struct idxd_device *idxd;int rc; - rc =pcim_enable_device (pdev); + rc =pci_enable_device (pdev);if (rc)return rc;dev_dbg (dev,"Alloc IDXD context\n" ); idxd =idxd_alloc (pdev); -if (!idxd) -return -ENOMEM ; +if (!idxd) { + rc = -ENOMEM ; + goto err_idxd_alloc; + }dev_dbg (dev,"Mapping BARs\n" ); - idxd->reg_base =pcim_iomap (pdev,IDXD_MMIO_BAR ,0 ); -if (!idxd->reg_base) -return -ENOMEM ; + idxd->reg_base =pci_iomap (pdev,IDXD_MMIO_BAR ,0 ); +if (!idxd->reg_base) { + rc = -ENOMEM ; + goto err_iomap; + }dev_dbg (dev,"Set DMA masks\n" ); rc =pci_set_dma_mask (pdev,DMA_BIT_MASK (64 ));if (rc) rc =pci_set_dma_mask (pdev,DMA_BIT_MASK (32 ));if (rc) -return rc; + goto err; rc =pci_set_consistent_dma_mask (pdev,DMA_BIT_MASK (64 ));if (rc) rc =pci_set_consistent_dma_mask (pdev,DMA_BIT_MASK (32 ));if (rc) -return rc; + goto err;idxd_set_type (idxd);
@@ -417,13 +421,13 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rc =idxd_probe (idxd);if (rc) {dev_err (dev,"Intel(R) IDXD DMA Engine init failed\n" ); -return -ENODEV ; + goto err; } rc =idxd_setup_sysfs (idxd);if (rc) {dev_err (dev,"IDXD sysfs setup failed\n" ); -return -ENODEV ; + goto err; } idxd->state =IDXD_DEV_CONF_READY ;
@@ -432,6 +436,13 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) idxd->hw.version);return 0 ; + + err: +pci_iounmap (pdev, idxd->reg_base); + err_iomap: + err_idxd_alloc: +pci_disable_device (pdev); +return rc; }static void idxd_flush_pending_llist (struct idxd_irq_entry *ie)
@@ -487,6 +498,8 @@ static void idxd_shutdown(struct pci_dev *pdev)idxd_msix_perm_clear (idxd);pci_free_irq_vectors (pdev); +pci_iounmap (pdev, idxd->reg_base); +pci_disable_device (pdev);destroy_workqueue (idxd->wq); }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 158/329 dma: idxd: use DEFINE_MUTEX() for mutex lock
In reply to Greg Kroah-HartmanFrom: Zheng Yongjun <[email protected]>
[ Upstream commit e2fcd6e427c2fae92b366b24759f95d77b6f7bc7 ]
mutex lock can be initialized automatically with DEFINE_MUTEX() rather than explicitly calling mutex_init().
--- drivers/dma/idxd/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/dma/idxd/init.c +1 -2
@@ -31,7 +31,7 @@ MODULE_AUTHOR("Intel Corporation");bool support_enqcmd;static struct idr idxd_idrs[IDXD_TYPE_MAX ]; -static struct mutex idxd_idr_lock; +static DEFINE_MUTEX (idxd_idr_lock);static struct pci_device_id idxd_pci_tbl[] = {/* DSA ver 1.0 platforms */
@@ -543,7 +543,6 @@ static int __init idxd_init_module(void)else support_enqcmd = true; -mutex_init (&idxd_idr_lock);for (i =0 ; i <IDXD_TYPE_MAX ; i++)idr_init (&idxd_idrs[i]);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 159/329 dmaengine: idxd: use ida for device instance enumeration
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit f7f7739847bd68b3c3103fd1b50d943038bd14c7 ]
The idr is only used for an device id, never to lookup context from that id. Switch to plain ida.
--- drivers/dma/idxd/init.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
drivers/dma/idxd/init.c +6 -11
@@ -30,8 +30,7 @@ MODULE_AUTHOR("Intel Corporation");bool support_enqcmd; -static struct idr idxd_idrs[IDXD_TYPE_MAX ]; -static DEFINE_MUTEX (idxd_idr_lock); +static struct ida idxd_idas[IDXD_TYPE_MAX ];static struct pci_device_id idxd_pci_tbl[] = {/* DSA ver 1.0 platforms */
@@ -342,12 +341,10 @@ static int idxd_probe(struct idxd_device *idxd)dev_dbg (dev,"IDXD interrupt setup complete.\n" ); -mutex_lock (&idxd_idr_lock); - idxd->id =idr_alloc (&idxd_idrs[idxd->type], idxd,0 ,0 ,GFP_KERNEL ); -mutex_unlock (&idxd_idr_lock); + idxd->id =ida_alloc (&idxd_idas[idxd->type],GFP_KERNEL );if (idxd->id <0 ) { rc = -ENOMEM ; - goto err_idr_fail; + goto err_ida_fail; } idxd->major =idxd_cdev_get_major (idxd);
@@ -355,7 +352,7 @@ static int idxd_probe(struct idxd_device *idxd)dev_dbg (dev,"IDXD device %d probed successfully\n" , idxd->id);return 0 ; - err_idr_fail: + err_ida_fail:idxd_mask_error_interrupts (idxd);idxd_mask_msix_vectors (idxd); err_setup:
@@ -512,9 +509,7 @@ static void idxd_remove(struct pci_dev *pdev)idxd_shutdown (pdev);if (device_pasid_enabled (idxd))idxd_disable_system_pasid (idxd); -mutex_lock (&idxd_idr_lock); -idr_remove (&idxd_idrs[idxd->type], idxd->id); -mutex_unlock (&idxd_idr_lock); +ida_free (&idxd_idas[idxd->type], idxd->id); }static struct pci_driver idxd_pci_driver = {
@@ -544,7 +539,7 @@ static int __init idxd_init_module(void) support_enqcmd = true;for (i =0 ; i <IDXD_TYPE_MAX ; i++) -idr_init (&idxd_idrs[i]); +ida_init (&idxd_idas[i]); err =idxd_register_bus_type ();if (err <0 )
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 160/329 dmaengine: idxd: fix idxd conf_dev struct device lifetime
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 47c16ac27d4cb664cee53ee0b9b7e2f907923fb3 ]
The devm managed lifetime is incompatible with 'struct device' objects that resides in idxd context. This is one of the series that clean up the idxd driver 'struct device' lifetime. Fix idxd->conf_dev 'struct device' lifetime. Address issues flagged by CONFIG_DEBUG_KOBJECT_RELEASE. Add release functions in order to free the allocated memory at the appropriate time.
--- drivers/dma/idxd/idxd.h | 36 ++++++++++------ drivers/dma/idxd/init.c | 56 ++++++++++++++++-------- drivers/dma/idxd/sysfs.c | 92 ++++++++++++++-------------------------- 3 files changed, 94 insertions(+), 90 deletions(-)
drivers/dma/idxd/idxd.h +22 -14
@@ -8,6 +8,7 @@#include <linux/percpu-rwsem.h> #include <linux/wait.h> #include <linux/cdev.h> +#include <linux/idr.h> #include "registers.h" #define IDXD_DRIVER_VERSION "1.00"
@@ -255,6 +256,23 @@ extern struct bus_type dsa_bus_type;extern struct bus_type iax_bus_type;extern bool support_enqcmd; +extern struct device_type dsa_device_type; +extern struct device_type iax_device_type; + +static inline bool is_dsa_dev (struct device *dev) +{ +return dev->type == &dsa_device_type; +} + +static inline bool is_iax_dev (struct device *dev) +{ +return dev->type == &iax_device_type; +} + +static inline bool is_idxd_dev (struct device *dev) +{ +return is_dsa_dev (dev) ||is_iax_dev (dev); +}static inline bool wq_dedicated (struct idxd_wq *wq) {
@@ -292,18 +310,6 @@ static inline int idxd_get_wq_portal_full_offset(int wq_id,return ((wq_id *4 ) <<PAGE_SHIFT ) +idxd_get_wq_portal_offset (prot); } -static inline void idxd_set_type (struct idxd_device *idxd) -{ -struct pci_dev *pdev = idxd->pdev; - -if (pdev->device ==PCI_DEVICE_ID_INTEL_DSA_SPR0 ) - idxd->type =IDXD_TYPE_DSA ; -else if (pdev->device ==PCI_DEVICE_ID_INTEL_IAX_SPR0 ) - idxd->type =IDXD_TYPE_IAX ; -else - idxd->type =IDXD_TYPE_UNKNOWN ; -} -static inline void idxd_wq_get (struct idxd_wq *wq) { wq->client_count++;
@@ -319,14 +325,16 @@ static inline int idxd_wq_refcount(struct idxd_wq *wq)return wq->client_count; }; +struct ida *idxd_ida (struct idxd_device *idxd);const char *idxd_get_dev_name (struct idxd_device *idxd);int idxd_register_bus_type (void );void idxd_unregister_bus_type (void ); -int idxd_setup_sysfs (struct idxd_device *idxd); -void idxd_cleanup_sysfs (struct idxd_device *idxd); +int idxd_register_devices (struct idxd_device *idxd); +void idxd_unregister_devices (struct idxd_device *idxd);int idxd_register_driver (void );void idxd_unregister_driver (void );struct bus_type *idxd_get_bus_type (struct idxd_device *idxd); +struct device_type *idxd_get_device_type (struct idxd_device *idxd);/* device interrupt control */ void idxd_msix_perm_setup (struct idxd_device *idxd);
drivers/dma/idxd/init.c +39 -17
121 lines not on this page · raw message
drivers/dma/idxd/sysfs.c +33 -59
143 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 161/329 dmaengine: idxd: fix wq conf_dev struct device lifetime
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 7c5dd23e57c14cf7177b8a5e0fd08916e0c60005 ]
Remove devm_* allocation and fix wq->conf_dev 'struct device' lifetime. Address issues flagged by CONFIG_DEBUG_KOBJECT_RELEASE. Add release functions in order to free the allocated memory for the wq context at device destruction time.
--- drivers/dma/idxd/device.c | 6 +-- drivers/dma/idxd/idxd.h | 20 +++++++- drivers/dma/idxd/init.c | 105 ++++++++++++++++++++++++++++---------- drivers/dma/idxd/irq.c | 6 +-- drivers/dma/idxd/sysfs.c | 100 ++++++++++++++++-------------------- 5 files changed, 146 insertions(+), 91 deletions(-)
drivers/dma/idxd/device.c +3 -3
@@ -520,7 +520,7 @@ void idxd_device_wqs_clear_state(struct idxd_device *idxd)lockdep_assert_held (&idxd->dev_lock);for (i =0 ; i < idxd->max_wqs; i++) { -struct idxd_wq *wq = &idxd->wqs[i]; +struct idxd_wq *wq = idxd->wqs[i];if (wq->state ==IDXD_WQ_ENABLED ) {idxd_wq_disable_cleanup (wq);
@@ -738,7 +738,7 @@ static int idxd_wqs_config_write(struct idxd_device *idxd)int i, rc;for (i =0 ; i < idxd->max_wqs; i++) { -struct idxd_wq *wq = &idxd->wqs[i]; +struct idxd_wq *wq = idxd->wqs[i]; rc =idxd_wq_config_write (wq);if (rc <0 )
@@ -816,7 +816,7 @@ static int idxd_wqs_setup(struct idxd_device *idxd) }for (i =0 ; i < idxd->max_wqs; i++) { - wq = &idxd->wqs[i]; + wq = idxd->wqs[i]; group = wq->group;if (!wq->group)
drivers/dma/idxd/idxd.h +19 -1
@@ -194,7 +194,7 @@ struct idxd_device {spinlock_t dev_lock;/* spinlock for device */ struct completion *cmd_done;struct idxd_group *groups; -struct idxd_wq *wqs; +struct idxd_wq **wqs;struct idxd_engine *engines;struct iommu_sva *sva;
@@ -258,6 +258,7 @@ extern struct bus_type iax_bus_type;extern bool support_enqcmd;extern struct device_type dsa_device_type;extern struct device_type iax_device_type; +extern struct device_type idxd_wq_device_type;static inline bool is_dsa_dev (struct device *dev) {
@@ -274,6 +275,23 @@ static inline bool is_idxd_dev(struct device *dev)return is_dsa_dev (dev) ||is_iax_dev (dev); } +static inline bool is_idxd_wq_dev (struct device *dev) +{ +return dev->type == &idxd_wq_device_type; +} + +static inline bool is_idxd_wq_dmaengine (struct idxd_wq *wq) +{ +if (wq->type ==IDXD_WQT_KERNEL &&strcmp (wq->name,"dmaengine" ) ==0 ) +return true; +return false; +} + +static inline bool is_idxd_wq_cdev (struct idxd_wq *wq) +{ +return wq->type ==IDXD_WQT_USER ; +} +static inline bool wq_dedicated (struct idxd_wq *wq) {return test_bit (WQ_FLAG_DEDICATED , &wq->flags);
drivers/dma/idxd/init.c +77 -28
151 lines not on this page · raw message
drivers/dma/idxd/irq.c +3 -3
@@ -45,7 +45,7 @@ static void idxd_device_reinit(struct work_struct *work) goto out;for (i =0 ; i < idxd->max_wqs; i++) { -struct idxd_wq *wq = &idxd->wqs[i]; +struct idxd_wq *wq = idxd->wqs[i];if (wq->state ==IDXD_WQ_ENABLED ) { rc =idxd_wq_enable (wq);
@@ -130,7 +130,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)if (idxd->sw_err.valid && idxd->sw_err.wq_idx_valid) {int id = idxd->sw_err.wq_idx; -struct idxd_wq *wq = &idxd->wqs[id]; +struct idxd_wq *wq = idxd->wqs[id];if (wq->type ==IDXD_WQT_USER )wake_up_interruptible (&wq->idxd_cdev.err_queue);
@@ -138,7 +138,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)int i;for (i =0 ; i < idxd->max_wqs; i++) { -struct idxd_wq *wq = &idxd->wqs[i]; +struct idxd_wq *wq = idxd->wqs[i];if (wq->type ==IDXD_WQT_USER )wake_up_interruptible (&wq->idxd_cdev.err_queue);
drivers/dma/idxd/sysfs.c +44 -56
196 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 162/329 dmaengine: idxd: fix engine conf_dev lifetime
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 75b911309060f42ba94bbbf46f5f497d35d5cd02 ]
Remove devm_* allocation and fix engine->conf_dev 'struct device' lifetime. Address issues flagged by CONFIG_DEBUG_KOBJECT_RELEASE. Add release functions in order to free the allocated memory at the engine conf_dev destruction time.
--- drivers/dma/idxd/device.c | 2 +- drivers/dma/idxd/idxd.h | 3 +- drivers/dma/idxd/init.c | 60 +++++++++++++++++++++++++------- drivers/dma/idxd/sysfs.c | 72 +++++++++++++++++++-------------------- 4 files changed, 86 insertions(+), 51 deletions(-)
drivers/dma/idxd/device.c +1 -1
@@ -786,7 +786,7 @@ static int idxd_engines_setup(struct idxd_device *idxd) }for (i =0 ; i < idxd->max_engines; i++) { - eng = &idxd->engines[i]; + eng = idxd->engines[i]; group = eng->group;if (!group)
drivers/dma/idxd/idxd.h +2 -1
@@ -195,7 +195,7 @@ struct idxd_device {struct completion *cmd_done;struct idxd_group *groups;struct idxd_wq **wqs; -struct idxd_engine *engines; +struct idxd_engine **engines;struct iommu_sva *sva;unsigned int pasid;
@@ -259,6 +259,7 @@ extern bool support_enqcmd;extern struct device_type dsa_device_type;extern struct device_type iax_device_type;extern struct device_type idxd_wq_device_type; +extern struct device_type idxd_engine_device_type;static inline bool is_dsa_dev (struct device *dev) {
drivers/dma/idxd/init.c +47 -13
84 lines not on this page · raw message
drivers/dma/idxd/sysfs.c +36 -36
127 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 163/329 dmaengine: idxd: fix group conf_dev lifetime
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit defe49f96012ca91e8e673cb95b5c30b4a3735e8 ]
Remove devm_* allocation and fix group->conf_dev 'struct device' lifetime. Address issues flagged by CONFIG_DEBUG_KOBJECT_RELEASE. Add release functions in order to free the allocated memory at the group->conf_dev destruction time.
--- drivers/dma/idxd/device.c | 8 ++--- drivers/dma/idxd/idxd.h | 3 +- drivers/dma/idxd/init.c | 68 ++++++++++++++++++++++++++++++--------- drivers/dma/idxd/sysfs.c | 68 +++++++++++++++++---------------------- 4 files changed, 88 insertions(+), 59 deletions(-)
drivers/dma/idxd/device.c +4 -4
@@ -659,7 +659,7 @@ static int idxd_groups_config_write(struct idxd_device *idxd) ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET));for (i =0 ; i < idxd->max_groups; i++) { -struct idxd_group *group = &idxd->groups[i]; +struct idxd_group *group = idxd->groups[i];idxd_group_config_write (group); }
@@ -754,7 +754,7 @@ static void idxd_group_flags_setup(struct idxd_device *idxd)/* TC-A 0 and TC-B 1 should be defaults */ for (i =0 ; i < idxd->max_groups; i++) { -struct idxd_group *group = &idxd->groups[i]; +struct idxd_group *group = idxd->groups[i];if (group->tc_a ==-1 ) group->tc_a = group->grpcfg.flags.tc_a =0 ;
@@ -781,7 +781,7 @@ static int idxd_engines_setup(struct idxd_device *idxd)struct idxd_group *group;for (i =0 ; i < idxd->max_groups; i++) { - group = &idxd->groups[i]; + group = idxd->groups[i]; group->grpcfg.engines =0 ; }
@@ -810,7 +810,7 @@ static int idxd_wqs_setup(struct idxd_device *idxd)struct device *dev = &idxd->pdev->dev;for (i =0 ; i < idxd->max_groups; i++) { - group = &idxd->groups[i]; + group = idxd->groups[i];for (j =0 ; j <4 ; j++) group->grpcfg.wqs[j] =0 ; }
drivers/dma/idxd/idxd.h +2 -1
@@ -193,7 +193,7 @@ struct idxd_device {spinlock_t dev_lock;/* spinlock for device */ struct completion *cmd_done; -struct idxd_group *groups; +struct idxd_group **groups;struct idxd_wq **wqs;struct idxd_engine **engines;
@@ -260,6 +260,7 @@ extern struct device_type dsa_device_type;extern struct device_type iax_device_type;extern struct device_type idxd_wq_device_type;extern struct device_type idxd_engine_device_type; +extern struct device_type idxd_group_device_type;static inline bool is_dsa_dev (struct device *dev) {
drivers/dma/idxd/init.c +52 -16
92 lines not on this page · raw message
drivers/dma/idxd/sysfs.c +30 -38
127 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 164/329 dmaengine: idxd: fix cdev setup and free device lifetime issues
In reply to Greg Kroah-HartmanFrom: Dave Jiang <[email protected]>
[ Upstream commit 04922b7445a1950b86f130a1fe8c52cc27b3e30b ]
The char device setup and cleanup has device lifetime issues regarding when parts are initialized and cleaned up. The initialization of struct device is done incorrectly. device_initialize() needs to be called on the 'struct device' and then additional changes can be added. The ->release() function needs to be setup via device_type before dev_set_name() to allow proper cleanup. The change re-parents the cdev under the wq->conf_dev to get natural reference inheritance. No known dependency on the old device path exists.
--- drivers/dma/idxd/cdev.c | 129 ++++++++++++++------------------------- drivers/dma/idxd/idxd.h | 7 ++- drivers/dma/idxd/init.c | 2 +- drivers/dma/idxd/irq.c | 4 +- drivers/dma/idxd/sysfs.c | 10 ++- 5 files changed, 63 insertions(+), 89 deletions(-)
drivers/dma/idxd/cdev.c +47 -82
@@ -39,15 +39,15 @@ struct idxd_user_context {struct iommu_sva *sva; }; -enum idxd_cdev_cleanup { -CDEV_NORMAL =0 , -CDEV_FAILED , -}; -static void idxd_cdev_dev_release (struct device *dev) { -dev_dbg (dev,"releasing cdev device\n" ); -kfree (dev); + struct idxd_cdev *idxd_cdev = container_of(dev, struct idxd_cdev, dev); +struct idxd_cdev_context *cdev_ctx; +struct idxd_wq *wq = idxd_cdev->wq; + + cdev_ctx = &ictx[wq->idxd->type]; +ida_simple_remove (&cdev_ctx->minor_ida, idxd_cdev->minor); +kfree (idxd_cdev); }static struct device_type idxd_cdev_device_type = {
@@ -62,14 +62,11 @@ static inline struct idxd_cdev *inode_idxd_cdev(struct inode *inode) return container_of(cdev, struct idxd_cdev, cdev); } -static inline struct idxd_wq *idxd_cdev_wq (struct idxd_cdev *idxd_cdev) -{ - return container_of(idxd_cdev, struct idxd_wq, idxd_cdev); -} -static inline struct idxd_wq *inode_wq (struct inode *inode) { -return idxd_cdev_wq (inode_idxd_cdev (inode)); +struct idxd_cdev *idxd_cdev =inode_idxd_cdev (inode); + +return idxd_cdev->wq; }static int idxd_cdev_open (struct inode *inode,struct file *filp)
@@ -220,11 +217,10 @@ static __poll_t idxd_cdev_poll(struct file *filp,struct idxd_user_context *ctx = filp->private_data;struct idxd_wq *wq = ctx->wq;struct idxd_device *idxd = wq->idxd; -struct idxd_cdev *idxd_cdev = &wq->idxd_cdev;unsigned long flags;__poll_t out =0 ; -poll_wait (filp, &idxd_cdev->err_queue, wait); +poll_wait (filp, &wq->err_queue, wait);spin_lock_irqsave (&idxd->dev_lock, flags);if (idxd->sw_err.valid) out =EPOLLIN |EPOLLRDNORM ;
@@ -246,98 +242,67 @@ int idxd_cdev_get_major(struct idxd_device *idxd)return MAJOR (ictx[idxd->type].devt); } -static int idxd_wq_cdev_dev_setup (struct idxd_wq *wq) +int idxd_wq_add_cdev (struct idxd_wq *wq) {struct idxd_device *idxd = wq->idxd; -struct idxd_cdev *idxd_cdev = &wq->idxd_cdev; -struct idxd_cdev_context *cdev_ctx; +struct idxd_cdev *idxd_cdev; +struct cdev *cdev;struct device *dev; -int minor, rc; +struct idxd_cdev_context *cdev_ctx; +int rc, minor; - idxd_cdev->dev =kzalloc (sizeof (*idxd_cdev->dev),GFP_KERNEL ); -if (!idxd_cdev->dev) + idxd_cdev =kzalloc (sizeof (*idxd_cdev),GFP_KERNEL ); +if (!idxd_cdev)return -ENOMEM ; - dev = idxd_cdev->dev; - dev->parent = &idxd->pdev->dev; -dev_set_name (dev,"%s/wq%u.%u" ,idxd_get_dev_name (idxd), - idxd->id, wq->id); - dev->bus =idxd_get_bus_type (idxd); - + idxd_cdev->wq = wq; + cdev = &idxd_cdev->cdev; + dev = &idxd_cdev->dev; cdev_ctx = &ictx[wq->idxd->type]; minor =ida_simple_get (&cdev_ctx->minor_ida,0 ,MINORMASK ,GFP_KERNEL );if (minor <0 ) { - rc = minor; -kfree (dev); - goto ida_err; - } - - dev->devt =MKDEV (MAJOR (cdev_ctx->devt), minor); - dev->type = &idxd_cdev_device_type; - rc =device_register (dev); -if (rc <0 ) { -dev_err (&idxd->pdev->dev,"device register failed\n" ); - goto dev_reg_err; +kfree (idxd_cdev); +return minor; } idxd_cdev->minor = minor; -return 0 ; - - dev_reg_err: -ida_simple_remove (&cdev_ctx->minor_ida,MINOR (dev->devt)); -put_device (dev); - ida_err: - idxd_cdev->dev =NULL ; -return rc; -} - -static void idxd_wq_cdev_cleanup (struct idxd_wq *wq, -enum idxd_cdev_cleanup cdev_state) -{ -struct idxd_cdev *idxd_cdev = &wq->idxd_cdev; -struct idxd_cdev_context *cdev_ctx; - - cdev_ctx = &ictx[wq->idxd->type]; -if (cdev_state ==CDEV_NORMAL ) -cdev_del (&idxd_cdev->cdev); -device_unregister (idxd_cdev->dev); -/* -* The device_type->release() will be called on the device and free -* the allocated struct device. We can just forget it. -*/ -ida_simple_remove (&cdev_ctx->minor_ida, idxd_cdev->minor); - idxd_cdev->dev =NULL ; - idxd_cdev->minor =-1 ; -} - -int idxd_wq_add_cdev (struct idxd_wq *wq) -{ -struct idxd_cdev *idxd_cdev = &wq->idxd_cdev; -struct cdev *cdev = &idxd_cdev->cdev; -struct device *dev; -int rc; +device_initialize (dev); + dev->parent = &wq->conf_dev; + dev->bus =idxd_get_bus_type (idxd); + dev->type = &idxd_cdev_device_type; + dev->devt =MKDEV (MAJOR (cdev_ctx->devt), minor); - rc =idxd_wq_cdev_dev_setup (wq); + rc =dev_set_name (dev,"%s/wq%u.%u" ,idxd_get_dev_name (idxd), + idxd->id, wq->id);if (rc <0 ) -return rc; + goto err; - dev = idxd_cdev->dev; + wq->idxd_cdev = idxd_cdev;cdev_init (cdev, &idxd_cdev_fops); -cdev_set_parent (cdev, &dev->kobj); - rc =cdev_add (cdev, dev->devt,1 ); + rc =cdev_device_add (cdev, dev);if (rc) {dev_dbg (&wq->idxd->pdev->dev,"cdev_add failed: %d\n" , rc); -idxd_wq_cdev_cleanup (wq,CDEV_FAILED ); -return rc; + goto err; } -init_waitqueue_head (&idxd_cdev->err_queue);return 0 ; + + err: +put_device (dev); + wq->idxd_cdev =NULL ; +return rc; }void idxd_wq_del_cdev (struct idxd_wq *wq) { -idxd_wq_cdev_cleanup (wq,CDEV_NORMAL ); +struct idxd_cdev *idxd_cdev; +struct idxd_cdev_context *cdev_ctx; + + cdev_ctx = &ictx[wq->idxd->type]; + idxd_cdev = wq->idxd_cdev; + wq->idxd_cdev =NULL ; +cdev_device_del (&idxd_cdev->cdev, &idxd_cdev->dev); +put_device (&idxd_cdev->dev); }int idxd_cdev_register (void )
drivers/dma/idxd/idxd.h +4 -3
@@ -80,10 +80,10 @@ enum idxd_wq_type { };struct idxd_cdev { +struct idxd_wq *wq;struct cdev cdev; -struct device *dev; +struct device dev;int minor; -struct wait_queue_head err_queue; };#define IDXD_ALLOCATED_BATCH_SIZE 128U
@@ -109,7 +109,8 @@ struct idxd_dma_chan {struct idxd_wq {void __iomem *portal;struct device conf_dev; -struct idxd_cdev idxd_cdev; +struct idxd_cdev *idxd_cdev; +struct wait_queue_head err_queue;struct idxd_device *idxd;int id;enum idxd_wq_type type;
drivers/dma/idxd/init.c +1 -1
@@ -172,7 +172,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd) }mutex_init (&wq->wq_lock); - wq->idxd_cdev.minor =-1 ; +init_waitqueue_head (&wq->err_queue); wq->max_xfer_bytes = idxd->max_xfer_bytes; wq->max_batch_size = idxd->max_batch_size; wq->wqcfg =kzalloc_node (idxd->wqcfg_size,GFP_KERNEL ,dev_to_node (dev));
drivers/dma/idxd/irq.c +2 -2
@@ -133,7 +133,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)struct idxd_wq *wq = idxd->wqs[id];if (wq->type ==IDXD_WQT_USER ) -wake_up_interruptible (&wq->idxd_cdev.err_queue); +wake_up_interruptible (&wq->err_queue); }else {int i;
@@ -141,7 +141,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)struct idxd_wq *wq = idxd->wqs[i];if (wq->type ==IDXD_WQT_USER ) -wake_up_interruptible (&wq->idxd_cdev.err_queue); +wake_up_interruptible (&wq->err_queue); } }
drivers/dma/idxd/sysfs.c +9 -1
@@ -1169,8 +1169,16 @@ static ssize_t wq_cdev_minor_show(struct device *dev, struct device_attribute *attr, char *buf) { struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); +int minor =-1 ; -return sprintf (buf,"%d\n" , wq->idxd_cdev.minor); +mutex_lock (&wq->wq_lock); +if (wq->idxd_cdev) + minor = wq->idxd_cdev->minor; +mutex_unlock (&wq->wq_lock); + +if (minor ==-1 ) +return -ENXIO ; +return sysfs_emit (buf,"%d\n" , minor); } static struct device_attribute dev_attr_wq_cdev_minor =
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 165/329 SUNRPC: fix ternary sign expansion bug in tracing
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit cb579086536f6564f5846f89808ec394ef8b8621 ]
This code is supposed to pass negative "err" values for tracing but it passes positive values instead. The problem is that the trace_svcsock_tcp_send() function takes a long but "err" is an int and "sent" is a u32. The negative is first type promoted to u32 so it becomes a high positive then it is promoted to long and it stays positive.
Fix this by casting "err" directly to long.
--- net/sunrpc/svcsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sunrpc/svcsock.c +1 -1
@@ -1176,7 +1176,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp) goto out_notconn; err =svc_tcp_sendmsg (svsk->sk_sock, &msg, xdr, marker, &sent);xdr_free_bvec (xdr); -trace_svcsock_tcp_send (xprt, err <0 ? err : sent); +trace_svcsock_tcp_send (xprt, err <0 ? (long )err : sent);if (err <0 || sent != (xdr->len +sizeof (marker))) goto out_close;mutex_unlock (&xprt->xpt_mutex);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 166/329 SUNRPC: Fix null pointer dereference in svc_rqst_free()
In reply to Greg Kroah-HartmanFrom: Yunjian Wang <[email protected]>
[ Upstream commit b9f83ffaa0c096b4c832a43964fe6bff3acffe10 ]
When alloc_pages_node() returns null in svc_rqst_alloc(), the null rq_scratch_page pointer will be dereferenced when calling put_page() in svc_rqst_free(). Fix it by adding a null check.
Addresses-Coverity: ("Dereference after null check")
--- net/sunrpc/svc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sunrpc/svc.c +2 -1
@@ -846,7 +846,8 @@ void svc_rqst_free(struct svc_rqst *rqstp) {svc_release_buffer (rqstp); -put_page (rqstp->rq_scratch_page); +if (rqstp->rq_scratch_page) +put_page (rqstp->rq_scratch_page);kfree (rqstp->rq_resp);kfree (rqstp->rq_argp);kfree (rqstp->rq_auth_data);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 167/329 pwm: atmel: Fix duty cycle calculation in .get_state()
In reply to Greg Kroah-HartmanFrom: Uwe Kleine-König <[email protected]>
[ Upstream commit 453e8b3d8e36ddcb283b3d1698864a03ea45599a ]
The CDTY register contains the number of inactive cycles. .apply() does this correctly, however .get_state() got this wrong.
--- drivers/pwm/pwm-atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pwm/pwm-atmel.c +1 -1
@@ -319,7 +319,7 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, cdty =atmel_pwm_ch_readl (atmel_pwm, pwm->hwpwm, atmel_pwm->data->regs.duty); - tmp = (u64 )cdty *NSEC_PER_SEC ; + tmp = (u64)(cprd - cdty) *NSEC_PER_SEC ; tmp <<= pres; state->duty_cycle =DIV64_U64_ROUND_UP (tmp, rate);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 168/329 xprtrdma: Avoid Receive Queue wrapping
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 32e6b68167f1d446111c973d57e6f52aee11897a ]
Commit e340c2d6ef2a ("xprtrdma: Reduce the doorbell rate (Receive)") increased the number of Receive WRs that are posted by the client, but did not increase the size of the Receive Queue allocated during transport set-up.
This is usually not an issue because RPCRDMA_BACKWARD_WRS is defined as (32) when SUNRPC_BACKCHANNEL is defined. In cases where it isn't, there is a real risk of Receive Queue wrapping.
--- net/sunrpc/xprtrdma/frwr_ops.c | 1 + 1 file changed, 1 insertion(+)
net/sunrpc/xprtrdma/frwr_ops.c +1 -0
@@ -257,6 +257,7 @@ int frwr_query_device(struct rpcrdma_ep *ep, const struct ib_device *device) ep->re_attr.cap.max_send_wr +=1 ;/* for ib_drain_sq */ ep->re_attr.cap.max_recv_wr = ep->re_max_requests; ep->re_attr.cap.max_recv_wr +=RPCRDMA_BACKWARD_WRS ; + ep->re_attr.cap.max_recv_wr +=RPCRDMA_MAX_RECV_BATCH ; ep->re_attr.cap.max_recv_wr +=1 ;/* for ib_drain_rq */ ep->re_max_rdma_segs =
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 169/329 xprtrdma: Fix cwnd update ordering
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 35d8b10a25884050bb3b0149b62c3818ec59f77c ]
After a reconnect, the reply handler is opening the cwnd (and thus enabling more RPC Calls to be sent) /before/ rpcrdma_post_recvs() can post enough Receive WRs to receive their replies. This causes an RNR and the new connection is lost immediately.
The race is most clearly exposed when KASAN and disconnect injection are enabled. This slows down rpcrdma_rep_create() enough to allow the send side to post a bunch of RPC Calls before the Receive completion handler can invoke ib_post_recv().
--- net/sunrpc/xprtrdma/rpc_rdma.c | 3 ++- net/sunrpc/xprtrdma/verbs.c | 10 +++++----- net/sunrpc/xprtrdma/xprt_rdma.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +2 -1
@@ -1459,9 +1459,10 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) credits =1 ;/* don't deadlock */ else if (credits > r_xprt->rx_ep->re_max_requests) credits = r_xprt->rx_ep->re_max_requests; +rpcrdma_post_recvs (r_xprt, credits + (buf->rb_bc_srv_max_requests <<1 ), + false);if (buf->rb_credits != credits)rpcrdma_update_cwnd (r_xprt, credits); -rpcrdma_post_recvs (r_xprt, false); req =rpcr_to_rdmar (rqst);if (unlikely (req->rl_reply))
net/sunrpc/xprtrdma/verbs.c +5 -5
@@ -535,7 +535,7 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)* outstanding Receives. */ rpcrdma_ep_get (ep); -rpcrdma_post_recvs (r_xprt, true); +rpcrdma_post_recvs (r_xprt,1 , true); rc =rdma_connect (ep->re_id, &ep->re_remote_cma);if (rc)
@@ -1364,21 +1364,21 @@ int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)/** * rpcrdma_post_recvs - Refill the Receive Queue * @r_xprt: controlling transport instance -* @temp: mark Receive buffers to be deleted after use +* @needed: current credit grant +* @temp: mark Receive buffers to be deleted after one use * */ -void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,bool temp) +void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,int needed,bool temp) {struct rpcrdma_buffer *buf = &r_xprt->rx_buf;struct rpcrdma_ep *ep = r_xprt->rx_ep;struct ib_recv_wr *wr, *bad_wr;struct rpcrdma_rep *rep; -int needed, count, rc; +int count, rc; rc =0 ; count =0 ; - needed = buf->rb_credits + (buf->rb_bc_srv_max_requests <<1 );if (likely (ep->re_receive_count > needed)) goto out; needed -= ep->re_receive_count;
net/sunrpc/xprtrdma/xprt_rdma.h +1 -1
@@ -460,7 +460,7 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt);void rpcrdma_xprt_disconnect (struct rpcrdma_xprt *r_xprt);int rpcrdma_post_sends (struct rpcrdma_xprt *r_xprt,struct rpcrdma_req *req); -void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,bool temp); +void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,int needed,bool temp);/* * Buffer calls - xprtrdma/verbs.c
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 170/329 xprtrdma: rpcrdma_mr_pop() already does list_del_init()
In reply to Greg Kroah-HartmanFrom: Chuck Lever <[email protected]>
[ Upstream commit 1363e6388c363d0433f9aa4e2f33efe047572687 ]
The rpcrdma_mr_pop() earlier in the function has already cleared out mr_list, so it must not be done again in the error path.
--- net/sunrpc/xprtrdma/frwr_ops.c | 1 - 1 file changed, 1 deletion(-)
net/sunrpc/xprtrdma/frwr_ops.c +0 -1
@@ -582,7 +582,6 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) mr = container_of(frwr, struct rpcrdma_mr, frwr); bad_wr = bad_wr->next; -list_del_init (&mr->mr_list);frwr_mr_recycle (mr); } }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 171/329 swiotlb: Fix the type of index
In reply to Greg Kroah-HartmanFrom: Claire Chang <[email protected]>
[ Upstream commit 95b079d8215b83b37fa59341fda92fcb9392f14a ]
Fix the type of index from unsigned int to int since find_slots() might return -1.
--- kernel/dma/swiotlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/dma/swiotlb.c +2 -1
@@ -579,7 +579,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, enum dma_data_direction dir, unsigned long attrs) {unsigned int offset =swiotlb_align_offset (dev, orig_addr); -unsigned int index, i; +unsigned int i; +int index;phys_addr_t tlb_addr;if (no_iotlb_memory)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 172/329 ceph: fix inode leak on getattr error in __fh_to_dentry
In reply to Greg Kroah-HartmanFrom: Jeff Layton <[email protected]>
[ Upstream commit 1775c7ddacfcea29051c67409087578f8f4d751b ]
--- fs/ceph/export.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/ceph/export.c +3 -1
@@ -178,8 +178,10 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)return ERR_CAST (inode);/* We need LINK caps to reliably check i_nlink */ err =ceph_do_getattr (inode,CEPH_CAP_LINK_SHARED , false); -if (err) +if (err) { +iput (inode);return ERR_PTR (err); + }/* -ESTALE if inode as been unlinked and no file is open */ if ((inode->i_nlink ==0 ) && (atomic_read (&inode->i_count) ==1 )) {iput (inode);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 173/329 scsi: qla2xxx: Prevent PRLI in target mode
In reply to Greg Kroah-HartmanFrom: Anastasia Kovaleva <[email protected]>
[ Upstream commit fcb16d9a8ecf1e9bfced0fc654ea4e2caa7517f4 ]
In a case when the initiator in P2P mode by some circumstances does not send PRLI, the target, in a case when the target port's WWPN is less than initiator's, changes the discovery state in DSC_GNL. When gnl completes it sends PRLI to the initiator.
Usually the initiator in P2P mode always sends PRLI. We caught this issue on Linux stable v5.4.6 https://www.spinics.net/lists/stable/msg458515.html.
Fix this particular corner case in the behaviour of the P2P mod target login state machine.
--- drivers/scsi/qla2xxx/qla_init.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/qla2xxx/qla_init.c +3 -0
@@ -1190,6 +1190,9 @@ static int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport) {struct qla_work_evt *e; +if (vha->host->active_mode ==MODE_TARGET ) +return QLA_FUNCTION_FAILED ; + e =qla2x00_alloc_work (vha,QLA_EVT_PRLI );if (!e)return QLA_FUNCTION_FAILED ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 174/329 scsi: ufs: core: Do not put UFS power into LPM if link is broken
In reply to Greg Kroah-HartmanFrom: Can Guo <[email protected]>
[ Upstream commit 23043dd87b153d02eaf676e752d32429be5e5126 ]
During resume, if link is broken due to AH8 failure, make sure ufshcd_resume() does not put UFS power back into LPM.
--- drivers/scsi/ufs/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/ufs/ufshcd.c +2 -2
@@ -8577,7 +8577,7 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba) }else if (!ufshcd_is_ufs_dev_active (hba)) {ufshcd_toggle_vreg (hba->dev, hba->vreg_info.vcc, false); vcc_off = true; -if (!ufshcd_is_link_active (hba)) { +if (ufshcd_is_link_hibern8 (hba) ||ufshcd_is_link_off (hba)) {ufshcd_config_vreg_lpm (hba, hba->vreg_info.vccq);ufshcd_config_vreg_lpm (hba, hba->vreg_info.vccq2); }
@@ -8599,7 +8599,7 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba) !hba->dev_info.is_lu_power_on_wp) { ret =ufshcd_setup_vreg (hba, true); } else if (!ufshcd_is_ufs_dev_active(hba)) { -if (!ret && !ufshcd_is_link_active (hba)) { +if (!ufshcd_is_link_active (hba)) { ret =ufshcd_config_vreg_hpm (hba, hba->vreg_info.vccq);if (ret) goto vcc_disable;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 175/329 scsi: ufs: core: Cancel rpm_dev_flush_recheck_work during system suspend
In reply to Greg Kroah-HartmanFrom: Can Guo <[email protected]>
[ Upstream commit 637822e63b79ee8a729f7ba2645a26cf5a524ee4 ]
During ufs system suspend, leaving rpm_dev_flush_recheck_work running or pending is risky because concurrency may happen between system suspend/resume and runtime resume routine. Fix this by cancelling rpm_dev_flush_recheck_work synchronously during system suspend.
--- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/ufs/ufshcd.c +2 -0
@@ -8972,6 +8972,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)if (!hba->is_powered)return 0 ; +cancel_delayed_work_sync (&hba->rpm_dev_flush_recheck_work); + if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) == hba->curr_dev_pwr_mode) && (ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 176/329 scsi: ufs: core: Narrow down fast path in system suspend path
In reply to Greg Kroah-HartmanFrom: Can Guo <[email protected]>
[ Upstream commit ce4f62f9dd8cf43ac044045ed598a0b80ef33890 ]
If spm_lvl is set to 0 or 1, when system suspend kicks start and HBA is runtime active, system suspend may just bail without doing anything (the fast path), leaving other contexts still running, e.g., clock gating and clock scaling. When system resume kicks start, concurrency can happen between ufshcd_resume() and these contexts, leading to various stability issues.
Add a check against HBA's runtime state and allowing fast path only if HBA is runtime suspended, otherwise let system suspend go ahead call ufshcd_suspend(). This will guarantee that these contexts are stopped by either runtime suspend or system suspend.
--- drivers/scsi/ufs/ufshcd.c | 1 + 1 file changed, 1 insertion(+)
drivers/scsi/ufs/ufshcd.c +1 -0
@@ -8978,6 +8978,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba) hba->curr_dev_pwr_mode) && (ufs_get_pm_lvl_to_link_pwr_state (hba->spm_lvl) == hba->uic_link_state) && +pm_runtime_suspended (hba->dev) && !hba->dev_info.b_rpm_dev_flush_capable) goto out;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 177/329 rtc: ds1307: Fix wday settings for rx8130
In reply to Greg Kroah-HartmanFrom: Nobuhiro Iwamatsu <[email protected]>
[ Upstream commit 204756f016726a380bafe619438ed979088bd04a ]
rx8130 wday specifies the bit position, not BCD.
--- drivers/rtc/rtc-ds1307.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/rtc/rtc-ds1307.c +10 -2
@@ -296,7 +296,11 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_min =bcd2bin (regs[DS1307_REG_MIN ] &0x7f ); tmp = regs[DS1307_REG_HOUR ] &0x3f ; t->tm_hour =bcd2bin (tmp); - t->tm_wday =bcd2bin (regs[DS1307_REG_WDAY ] &0x07 ) -1 ; +/* rx8130 is bit position, not BCD */ +if (ds1307->type == rx_8130) + t->tm_wday =fls (regs[DS1307_REG_WDAY ] &0x7f ); +else + t->tm_wday =bcd2bin (regs[DS1307_REG_WDAY ] &0x07 ) -1 ; t->tm_mday =bcd2bin (regs[DS1307_REG_MDAY ] &0x3f ); tmp = regs[DS1307_REG_MONTH ] &0x1f ; t->tm_mon =bcd2bin (tmp) -1 ;
@@ -343,7 +347,11 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) regs[DS1307_REG_SECS ] =bin2bcd (t->tm_sec); regs[DS1307_REG_MIN ] =bin2bcd (t->tm_min); regs[DS1307_REG_HOUR ] =bin2bcd (t->tm_hour); - regs[DS1307_REG_WDAY ] =bin2bcd (t->tm_wday +1 ); +/* rx8130 is bit position, not BCD */ +if (ds1307->type == rx_8130) + regs[DS1307_REG_WDAY ] =1 << t->tm_wday; +else + regs[DS1307_REG_WDAY ] =bin2bcd (t->tm_wday +1 ); regs[DS1307_REG_MDAY ] =bin2bcd (t->tm_mday); regs[DS1307_REG_MONTH ] =bin2bcd (t->tm_mon +1 );
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 178/329 net: hns3: fix incorrect configuration for igu_egu_hw_err
In reply to Greg Kroah-HartmanFrom: Yufeng Mo <[email protected]>
[ Upstream commit 2867298dd49ee84214b8721521dc7a5a6382520c ]
According to the UM, the type and enable status of igu_egu_hw_err should be configured separately. Currently, the type field is incorrect when disable this error. So fix it by configuring these two fields separately.
--- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c | 3 ++- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +2 -1
@@ -753,8 +753,9 @@ static int hclge_config_igu_egu_hw_err_int(struct hclge_dev *hdev, bool en)/* configure IGU,EGU error interrupts */ hclge_cmd_setup_basic_desc (&desc,HCLGE_IGU_COMMON_INT_EN , false); + desc.data[0 ] =cpu_to_le32 (HCLGE_IGU_ERR_INT_TYPE );if (en) - desc.data[0 ] =cpu_to_le32 (HCLGE_IGU_ERR_INT_EN ); + desc.data[0 ] |=cpu_to_le32 (HCLGE_IGU_ERR_INT_EN ); desc.data[1 ] =cpu_to_le32 (HCLGE_IGU_ERR_INT_EN_MASK );
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +2 -1
@@ -32,7 +32,8 @@#define HCLGE_TQP_ECC_ERR_INT_EN_MASK 0x0FFF#define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN_MASK 0x0F000000#define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN 0x0F000000 -#define HCLGE_IGU_ERR_INT_EN 0x0000066F +#define HCLGE_IGU_ERR_INT_EN 0x0000000F +#define HCLGE_IGU_ERR_INT_TYPE 0x00000660#define HCLGE_IGU_ERR_INT_EN_MASK 0x000F#define HCLGE_IGU_TNL_ERR_INT_EN 0x0002AABF#define HCLGE_IGU_TNL_ERR_INT_EN_MASK 0x003F
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 179/329 net: hns3: initialize the message content in hclge_get_link_mode()
In reply to Greg Kroah-HartmanFrom: Yufeng Mo <[email protected]>
[ Upstream commit 568a54bdf70b143f3e0befa298e22ad469ffc732 ]
The message sent to VF should be initialized, otherwise random value of some contents may cause improper processing by the target. So add a initialization to message in hclge_get_link_mode().
--- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +1 -1
@@ -535,7 +535,7 @@ static void hclge_get_link_mode(struct hclge_vport *vport,unsigned long advertising;unsigned long supported;unsigned long send_data; -u8 msg_data[10 ]; +u8 msg_data[10 ] = {};u8 dest_vfid; advertising = hdev->hw.mac.advertising[0 ];
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 180/329 net: hns3: add check for HNS3_NIC_STATE_INITED in hns3_reset_notify_up_enet()
In reply to Greg Kroah-HartmanFrom: Jian Shen <[email protected]>
[ Upstream commit b4047aac4ec1066bab6c71950623746d7bcf7154 ]
In some cases, the device is not initialized because reset failed. If another task calls hns3_reset_notify_up_enet() before reset retry, it will cause an error since uninitialized pointer access. So add check for HNS3_NIC_STATE_INITED before calling hns3_nic_net_open() in hns3_reset_notify_up_enet().
--- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +5 -0
@@ -4612,6 +4612,11 @@ static int hns3_reset_notify_up_enet(struct hnae3_handle *handle)struct hns3_nic_priv *priv =netdev_priv (kinfo->netdev);int ret =0 ; +if (!test_bit (HNS3_NIC_STATE_INITED , &priv->state)) { +netdev_err (kinfo->netdev,"device is not initialized yet\n" ); +return -EFAULT ; + } +clear_bit (HNS3_NIC_STATE_RESETTING , &priv->state);if (netif_running (kinfo->netdev)) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 181/329 net: hns3: fix for vxlan gpe tx checksum bug
In reply to Greg Kroah-HartmanFrom: Hao Chen <[email protected]>
[ Upstream commit 905416f18fe74bdd4de91bf94ef5a790a36e4b99 ]
When skb->ip_summed is CHECKSUM_PARTIAL, for non-tunnel udp packet, which has a dest port as the IANA assigned, the hardware is expected to do the checksum offload, but the hardware whose version is below V3 will not do the checksum offload when udp dest port is 4790.
So fixes it by doing the checksum in software for this case.
--- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +3 -2
@@ -823,7 +823,7 @@ static int hns3_get_l4_protocol(struct sk_buff *skb, u8 *ol4_proto,* and it is udp packet, which has a dest port as the IANA assigned. * the hardware is expected to do the checksum offload, but the * hardware will not do the checksum offload when udp dest port is -* 4789 or 6081. +* 4789, 4790 or 6081. */ static bool hns3_tunnel_csum_bug (struct sk_buff *skb) {
@@ -841,7 +841,8 @@ static bool hns3_tunnel_csum_bug(struct sk_buff *skb)if (!(!skb->encapsulation && (l4.udp->dest ==htons (IANA_VXLAN_UDP_PORT ) || - l4.udp->dest ==htons (GENEVE_UDP_PORT )))) + l4.udp->dest ==htons (GENEVE_UDP_PORT ) || + l4.udp->dest ==htons (4790 ))))return false;skb_checksum_help (skb);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 182/329 net: hns3: use netif_tx_disable to stop the transmit queue
In reply to Greg Kroah-HartmanFrom: Peng Li <[email protected]>
[ Upstream commit b416e872be06fdace3c36cf5210130509d0f0e72 ]
Currently, netif_tx_stop_all_queues() is used to ensure that the xmit is not running, but for the concurrent case it will not take effect, since netif_tx_stop_all_queues() just sets a flag without locking to indicate that the xmit queue(s) should not be run.
So use netif_tx_disable() to replace netif_tx_stop_all_queues(), it takes the xmit queue lock while marking the queue stopped.
--- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +1 -1
@@ -576,8 +576,8 @@ static int hns3_nic_net_stop(struct net_device *netdev)if (h->ae_algo->ops->set_timer_task) h->ae_algo->ops->set_timer_task (priv->ae_handle, false); -netif_tx_stop_all_queues (netdev);netif_carrier_off (netdev); +netif_tx_disable (netdev);hns3_nic_net_down (netdev);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 183/329 net: hns3: disable phy loopback setting in hclge_mac_start_phy
In reply to Greg Kroah-HartmanFrom: Yufeng Mo <[email protected]>
[ Upstream commit 472497d0bdae890a896013332a0b673f9acdf2bf ]
If selftest and reset are performed at the same time, the phy loopback setting may be still in enable state after the reset, and device cannot link up. So fix this issue by disabling phy loopback before phy_start().
--- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +2 -0
@@ -255,6 +255,8 @@ void hclge_mac_start_phy(struct hclge_dev *hdev)if (!phydev)return ; +phy_loopback (phydev, false); +phy_start (phydev); }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 184/329 sctp: do asoc update earlier in sctp_sf_do_dupcook_a
In reply to Greg Kroah-HartmanFrom: Xin Long <[email protected]>
[ Upstream commit 35b4f24415c854cd718ccdf38dbea6297f010aae ]
There's a panic that occurs in a few of envs, the call trace is as below:
[] general protection fault, ... 0x29acd70f1000a: 0000 [#1] SMP PTI [] RIP: 0010:sctp_ulpevent_notify_peer_addr_change+0x4b/0x1fa [sctp]
[] sctp_assoc_control_transport+0x1b9/0x210 [sctp] [] sctp_do_8_2_transport_strike.isra.16+0x15c/0x220 [sctp] [] sctp_cmd_interpreter.isra.21+0x1231/0x1a10 [sctp] [] sctp_do_sm+0xc3/0x2a0 [sctp] [] sctp_generate_timeout_event+0x81/0xf0 [sctp]
This is caused by a transport use-after-free issue. When processing a duplicate COOKIE-ECHO chunk in sctp_sf_do_dupcook_a(), both COOKIE-ACK and SHUTDOWN chunks are allocated with the transort from the new asoc. However, later in the sideeffect machine, the old asoc is used to send them out and old asoc's shutdown_last_sent_to is set to the transport that SHUTDOWN chunk attached to in sctp_cmd_setup_t2(), which actually belongs to the new asoc. After the new_asoc is freed and the old asoc T2 timeout, the old asoc's shutdown_last_sent_to that is already freed would be accessed in sctp_sf_t2_timer_expire().
Thanks Alexander and Jere for helping dig into this issue.
To fix it, this patch is to do the asoc update first, then allocate the COOKIE-ACK and SHUTDOWN chunks with the 'updated' old asoc. This would make more sense, as a chunk from an asoc shouldn't be sent out with another asoc. We had fixed quite a few issues caused by this.
--- net/sctp/sm_statefuns.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
net/sctp/sm_statefuns.c +20 -5
@@ -1852,20 +1852,35 @@ static enum sctp_disposition sctp_sf_do_dupcook_a( SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));sctp_add_cmd_sf (commands,SCTP_CMD_PURGE_ASCONF_QUEUE ,SCTP_NULL ()); - repl =sctp_make_cookie_ack (new_asoc, chunk); +/* Update the content of current association. */ +if (sctp_assoc_update ((struct sctp_association *)asoc, new_asoc)) { +struct sctp_chunk *abort; + + abort =sctp_make_abort (asoc,NULL ,sizeof (struct sctp_errhdr )); +if (abort) { +sctp_init_cause (abort,SCTP_ERROR_RSRC_LOW ,0 ); +sctp_add_cmd_sf (commands,SCTP_CMD_REPLY ,SCTP_CHUNK (abort)); + } +sctp_add_cmd_sf (commands,SCTP_CMD_SET_SK_ERR ,SCTP_ERROR (ECONNABORTED )); +sctp_add_cmd_sf (commands,SCTP_CMD_ASSOC_FAILED , +SCTP_PERR (SCTP_ERROR_RSRC_LOW )); +SCTP_INC_STATS (net,SCTP_MIB_ABORTEDS ); +SCTP_DEC_STATS (net,SCTP_MIB_CURRESTAB ); + goto nomem; + } + + repl =sctp_make_cookie_ack (asoc, chunk);if (!repl) goto nomem;/* Report association restart to upper layer. */ ev =sctp_ulpevent_make_assoc_change (asoc,0 ,SCTP_RESTART ,0 , - new_asoc->c.sinit_num_ostreams, - new_asoc->c.sinit_max_instreams, + asoc->c.sinit_num_ostreams, + asoc->c.sinit_max_instreams,NULL ,GFP_ATOMIC );if (!ev) goto nomem_ev; -/* Update the content of current association. */ -sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_ASSOC ,SCTP_ASOC (new_asoc));sctp_add_cmd_sf (commands,SCTP_CMD_EVENT_ULP ,SCTP_ULPEVENT (ev)); if ((sctp_state(asoc, SHUTDOWN_PENDING) || sctp_state(asoc, SHUTDOWN_SENT)) &&
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 185/329 RISC-V: Fix error code returned by riscv_hartid_to_cpuid()
In reply to Greg Kroah-HartmanFrom: Anup Patel <[email protected]>
[ Upstream commit 533b4f3a789d49574e7ae0f6ececed153f651f97 ]
We should return a negative error code upon failure in riscv_hartid_to_cpuid() instead of NR_CPUS. This is also aligned with all uses of riscv_hartid_to_cpuid() which expect negative error code upon failure.
--- arch/riscv/kernel/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/kernel/smp.c +1 -1
@@ -54,7 +54,7 @@ int riscv_hartid_to_cpuid(int hartid)return i;pr_err ("Couldn't find cpu id for hartid [%d]\n" , hartid); -return i; +return -ENOENT ; }void riscv_cpuid_to_hartid_mask (const struct cpumask *in,struct cpumask *out)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 186/329 sunrpc: Fix misplaced barrier in call_decode
In reply to Greg Kroah-HartmanFrom: Baptiste Lepers <[email protected]>
[ Upstream commit f8f7e0fb22b2e75be55f2f0c13e229e75b0eac07 ]
Fix a misplaced barrier in call_decode. The struct rpc_rqst is modified as follows by xprt_complete_rqst:
req->rq_private_buf.len = copied;
/* Ensure all writes are done before we update */
/* req->rq_reply_bytes_recvd */smp_wmb();req->rq_reply_bytes_recvd = copied;
And currently read as follows by call_decode:
smp_rmb(); // misplaced
if (!req->rq_reply_bytes_recvd)
goto out;req->rq_rcv_buf.len = req->rq_private_buf.len;
This patch places the smp_rmb after the if to ensure that rq_reply_bytes_recvd and rq_private_buf.len are read in order.
--- net/sunrpc/clnt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/sunrpc/clnt.c +5 -6
@@ -2456,12 +2456,6 @@ call_decode(struct rpc_task *task) task->tk_flags &= ~RPC_CALL_MAJORSEEN ; } -/* -* Ensure that we see all writes made by xprt_complete_rqst() -* before it changed req->rq_reply_bytes_recvd. -*/ -smp_rmb (); -/* * Did we ever call xprt_complete_rqst()? If not, we should assume * the message is incomplete.
@@ -2470,6 +2464,11 @@ call_decode(struct rpc_task *task)if (!req->rq_reply_bytes_recvd) goto out; +/* Ensure that we see all writes made by xprt_complete_rqst() +* before it changed req->rq_reply_bytes_recvd. +*/ +smp_rmb (); + req->rq_rcv_buf.len = req->rq_private_buf.len;trace_rpc_xdr_recvfrom (task, &req->rq_rcv_buf);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 187/329 libbpf: Fix signed overflow in ringbuf_process_ring
In reply to Greg Kroah-HartmanFrom: Brendan Jackman <[email protected]>
[ Upstream commit 2a30f9440640c418bcfbea9b2b344d268b58e0a2 ]
One of our benchmarks running in (Google-internal) CI pushes data through the ringbuf faster htan than userspace is able to consume it. In this case it seems we're actually able to get >INT_MAX entries in a single ring_buffer__consume() call. ASAN detected that cnt overflows in this case.
Fix by using 64-bit counter internally and then capping the result to INT_MAX before converting to the int return type. Do the same for the ring_buffer__poll().
--- tools/lib/bpf/ringbuf.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-)
tools/lib/bpf/ringbuf.c +21 -9
@@ -202,9 +202,11 @@ static inline int roundup_len(__u32 len)return (len +7 ) /8 *8 ; } -static int ringbuf_process_ring (struct ring * r) +static int64_t ringbuf_process_ring (struct ring * r) { -int *len_ptr, len, err, cnt =0 ; +int *len_ptr, len, err; +/* 64-bit to avoid overflow in case of extreme application behavior */ +int64_t cnt =0 ;unsigned long cons_pos, prod_pos;bool got_new_data;void *sample;
@@ -244,12 +246,14 @@ done: }/* Consume available ring buffer(s) data without event polling. -* Returns number of records consumed across all registered ring buffers, or -* negative number if any of the callbacks return error. +* Returns number of records consumed across all registered ring buffers (or +* INT_MAX, whichever is less), or negative number if any of the callbacks +* return error. */ int ring_buffer__consume (struct ring_buffer *rb) { -int i, err, res =0 ; +int64_t err, res =0 ; +int i;for (i =0 ; i < rb->ring_cnt; i++) {struct ring *ring = &rb->rings[i];
@@ -259,18 +263,24 @@ int ring_buffer__consume(struct ring_buffer *rb)return err; res += err; } +if (res >INT_MAX ) +return INT_MAX ;return res; }/* Poll for available data and consume records, if any are available. -* Returns number of records consumed, or negative number, if any of the -* registered callbacks returned error. +* Returns number of records consumed (or INT_MAX, whichever is less), or +* negative number, if any of the registered callbacks returned error. */ int ring_buffer__poll (struct ring_buffer *rb,int timeout_ms) { -int i, cnt, err, res =0 ; +int i, cnt; +int64_t err, res =0 ; cnt =epoll_wait (rb->epoll_fd, rb->events, rb->ring_cnt, timeout_ms); +if (cnt <0 ) +return -errno; +for (i =0 ; i < cnt; i++) {__u32 ring_id = rb->events[i].data.fd;struct ring *ring = &rb->rings[ring_id];
@@ -280,7 +290,9 @@ int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms)return err; res += err; } -return cnt <0 ? -errno : res; +if (res >INT_MAX ) +return INT_MAX ; +return res; }/* Get an fd that can be used to sleep until data is available in the ring(s) */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 188/329 block/rnbd-clt: Change queue_depth type in rnbd_clt_session to size_t
In reply to Greg Kroah-HartmanFrom: Md Haris Iqbal <[email protected]>
[ Upstream commit 80d43cbd46155744ee450d2476ee4fcf2917ae9b ]
The member queue_depth in the structure rnbd_clt_session is read from the rtrs client side using the function rtrs_clt_query, which in turn is read from the rtrs_clt structure. It should really be of type size_t.
--- drivers/block/rnbd/rnbd-clt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/rnbd/rnbd-clt.h +1 -1
@@ -87,7 +87,7 @@ struct rnbd_clt_session {DECLARE_BITMAP (cpu_queues_bm,NR_CPUS );int __percpu *cpu_rr;/* per-cpu var for CPU round-robin */ atomic_t busy; -int queue_depth; +size_t queue_depth;u32 max_io_size;struct blk_mq_tag_set tag_set;struct mutex lock;/* protects state and devs_list */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 189/329 block/rnbd-clt: Check the return value of the function rtrs_clt_query
In reply to Greg Kroah-HartmanFrom: Md Haris Iqbal <[email protected]>
[ Upstream commit 1056ad829ec43f9b705b507c2093b05e2088b0b7 ]
In case none of the paths are in connected state, the function rtrs_clt_query returns an error. In such a case, error out since the values in the rtrs_attrs structure would be garbage.
--- drivers/block/rnbd/rnbd-clt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/block/rnbd/rnbd-clt.c +10 -2
@@ -693,7 +693,11 @@ static void remap_devs(struct rnbd_clt_session *sess)return ; } -rtrs_clt_query (sess->rtrs, &attrs); + err =rtrs_clt_query (sess->rtrs, &attrs); +if (err) { +pr_err ("rtrs_clt_query(\"%s\"): %d\n" , sess->sessname, err); +return ; + }mutex_lock (&sess->lock); sess->max_io_size = attrs.max_io_size;
@@ -1234,7 +1238,11 @@ find_and_get_or_create_sess(const char *sessname, err =PTR_ERR (sess->rtrs); goto wake_up_and_put; } -rtrs_clt_query (sess->rtrs, &attrs); + + err =rtrs_clt_query (sess->rtrs, &attrs); +if (err) + goto close_rtrs; + sess->max_io_size = attrs.max_io_size; sess->queue_depth = attrs.queue_depth;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 190/329 ata: ahci_brcm: Fix use of BCM7216 reset controller
In reply to Greg Kroah-HartmanFrom: Jim Quinlan <[email protected]>
[ Upstream commit e8d6f9e56187c101b325e8d18f1d4032420d08ff ]
This driver may use one of two resets controllers. Keep them in separate variables to keep things simple. The reset controller "rescal" is shared between the AHCI driver and the PCIe driver for the BrcmSTB 7216 chip. Use devm_reset_control_get_optional_shared() to handle this sharing.
--- drivers/ata/ahci_brcm.c | 46 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-)
drivers/ata/ahci_brcm.c +23 -23
@@ -86,7 +86,8 @@ struct brcm_ahci_priv {u32 port_mask;u32 quirks;enum brcm_ahci_version version; -struct reset_control *rcdev; +struct reset_control *rcdev_rescal; +struct reset_control *rcdev_ahci; };static inline u32 brcm_sata_readreg (void __iomem *addr)
@@ -352,8 +353,8 @@ static int brcm_ahci_suspend(struct device *dev)else ret =0 ; -if (priv->version !=BRCM_SATA_BCM7216 ) -reset_control_assert (priv->rcdev); +reset_control_assert (priv->rcdev_ahci); +reset_control_rearm (priv->rcdev_rescal);return ret; }
@@ -365,10 +366,10 @@ static int __maybe_unused brcm_ahci_resume(struct device *dev)struct brcm_ahci_priv *priv = hpriv->plat_data;int ret =0 ; -if (priv->version ==BRCM_SATA_BCM7216 ) - ret =reset_control_reset (priv->rcdev); -else - ret =reset_control_deassert (priv->rcdev); + ret =reset_control_deassert (priv->rcdev_ahci); +if (ret) +return ret; + ret =reset_control_reset (priv->rcdev_rescal);if (ret)return ret;
@@ -434,7 +435,6 @@ static int brcm_ahci_probe(struct platform_device *pdev) {const struct of_device_id *of_id;struct device *dev = &pdev->dev; -const char *reset_name =NULL ;struct brcm_ahci_priv *priv;struct ahci_host_priv *hpriv;struct resource *res;
@@ -456,15 +456,15 @@ static int brcm_ahci_probe(struct platform_device *pdev)if (IS_ERR (priv->top_ctrl))return PTR_ERR (priv->top_ctrl); -/* Reset is optional depending on platform and named differently */ -if (priv->version ==BRCM_SATA_BCM7216 ) - reset_name ="rescal" ; -else - reset_name ="ahci" ; - - priv->rcdev =devm_reset_control_get_optional (&pdev->dev, reset_name); -if (IS_ERR (priv->rcdev)) -return PTR_ERR (priv->rcdev); +if (priv->version ==BRCM_SATA_BCM7216 ) { + priv->rcdev_rescal =devm_reset_control_get_optional_shared ( + &pdev->dev,"rescal" ); +if (IS_ERR (priv->rcdev_rescal)) +return PTR_ERR (priv->rcdev_rescal); + } + priv->rcdev_ahci =devm_reset_control_get_optional (&pdev->dev,"ahci" ); +if (IS_ERR (priv->rcdev_ahci)) +return PTR_ERR (priv->rcdev_ahci); hpriv =ahci_platform_get_resources (pdev,0 );if (IS_ERR (hpriv))
@@ -485,10 +485,10 @@ static int brcm_ahci_probe(struct platform_device *pdev)break ; } -if (priv->version ==BRCM_SATA_BCM7216 ) - ret =reset_control_reset (priv->rcdev); -else - ret =reset_control_deassert (priv->rcdev); + ret =reset_control_reset (priv->rcdev_rescal); +if (ret) +return ret; + ret =reset_control_deassert (priv->rcdev_ahci);if (ret)return ret;
@@ -539,8 +539,8 @@ out_disable_regulators: out_disable_clks:ahci_platform_disable_clks (hpriv); out_reset: -if (priv->version !=BRCM_SATA_BCM7216 ) -reset_control_assert (priv->rcdev); +reset_control_assert (priv->rcdev_ahci); +reset_control_rearm (priv->rcdev_rescal);return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 191/329 PCI: brcmstb: Use reset/rearm instead of deassert/assert
In reply to Greg Kroah-HartmanFrom: Jim Quinlan <[email protected]>
[ Upstream commit bb610757fcd74558ad94fe19993fd4470208dd02 ]
The Broadcom STB PCIe RC uses a reset control "rescal" for certain chips. The "rescal" implements a "pulse reset" so using assert/deassert is wrong for this device. Instead, we use reset/rearm. We need to use rearm so that we can reset it after a suspend/resume cycle; w/o using "rearm", the "rescal" device will only ever fire once.
Of course for suspend/resume to work we also need to put the reset/rearm calls in the suspend and resume routines.
--- drivers/pci/controller/pcie-brcmstb.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/pci/controller/pcie-brcmstb.c +13 -6
@@ -1127,6 +1127,7 @@ static int brcm_pcie_suspend(struct device *dev)brcm_pcie_turn_off (pcie); ret =brcm_phy_stop (pcie); +reset_control_rearm (pcie->rescal);clk_disable_unprepare (pcie->clk);return ret;
@@ -1142,9 +1143,13 @@ static int brcm_pcie_resume(struct device *dev) base = pcie->base;clk_prepare_enable (pcie->clk); + ret =reset_control_reset (pcie->rescal); +if (ret) + goto err_disable_clk; + ret =brcm_phy_start (pcie);if (ret) - goto err; + goto err_reset;/* Take bridge out of reset so we can access the SERDES reg */ pcie->bridge_sw_init_set (pcie,0 );
@@ -1159,14 +1164,16 @@ static int brcm_pcie_resume(struct device *dev) ret =brcm_pcie_setup (pcie);if (ret) - goto err; + goto err_reset;if (pcie->msi)brcm_msi_set_regs (pcie->msi);return 0 ; -err: +err_reset: +reset_control_rearm (pcie->rescal); +err_disable_clk:clk_disable_unprepare (pcie->clk);return ret; }
@@ -1176,7 +1183,7 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie)brcm_msi_remove (pcie);brcm_pcie_turn_off (pcie);brcm_phy_stop (pcie); -reset_control_assert (pcie->rescal); +reset_control_rearm (pcie->rescal);clk_disable_unprepare (pcie->clk); }
@@ -1251,13 +1258,13 @@ static int brcm_pcie_probe(struct platform_device *pdev)return PTR_ERR (pcie->rescal); } - ret =reset_control_deassert (pcie->rescal); + ret =reset_control_reset (pcie->rescal);if (ret)dev_err (&pdev->dev,"failed to deassert 'rescal'\n" ); ret =brcm_phy_start (pcie);if (ret) { -reset_control_assert (pcie->rescal); +reset_control_rearm (pcie->rescal);clk_disable_unprepare (pcie->clk);return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 192/329 ethernet:enic: Fix a use after free bug in enic_hard_start_xmit
In reply to Greg Kroah-HartmanFrom: Lv Yunlong <[email protected]>
[ Upstream commit 643001b47adc844ae33510c4bb93c236667008a3 ]
In enic_hard_start_xmit, it calls enic_queue_wq_skb(). Inside enic_queue_wq_skb, if some error happens, the skb will be freed by dev_kfree_skb(skb). But the freed skb is still used in skb_tx_timestamp(skb).
My patch makes enic_queue_wq_skb() return error and goto spin_unlock() incase of error. The solution is provided by Govind.
See https://lkml.org/lkml/2021/4/30/961.
--- drivers/net/ethernet/cisco/enic/enic_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/cisco/enic/enic_main.c +5 -2
@@ -768,7 +768,7 @@ static inline int enic_queue_wq_skb_encap(struct enic *enic, struct vnic_wq *wq,return err; } -static inline void enic_queue_wq_skb (struct enic *enic, +static inline int enic_queue_wq_skb (struct enic *enic,struct vnic_wq *wq,struct sk_buff *skb) {unsigned int mss =skb_shinfo (skb)->gso_size;
@@ -814,6 +814,7 @@ static inline void enic_queue_wq_skb(struct enic *enic, wq->to_use = buf->next;dev_kfree_skb (skb); } +return err; }/* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -857,7 +858,8 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,return NETDEV_TX_BUSY ; } -enic_queue_wq_skb (enic, wq, skb); +if (enic_queue_wq_skb (enic, wq, skb)) + goto error;if (vnic_wq_desc_avail (wq) <MAX_SKB_FRAGS +ENIC_DESC_MAX_SPLITS )netif_tx_stop_queue (txq);
@@ -865,6 +867,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,if (!netdev_xmit_more () ||netif_xmit_stopped (txq))vnic_wq_doorbell (wq); +error:spin_unlock (&enic->wq_lock[txq_map]);return NETDEV_TX_OK ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 193/329 sctp: fix a SCTP_MIB_CURRESTAB leak in sctp_sf_do_dupcook_b
In reply to Greg Kroah-HartmanFrom: Xin Long <[email protected]>
[ Upstream commit f282df0391267fb2b263da1cc3233aa6fb81defc ]
Normally SCTP_MIB_CURRESTAB is always incremented once asoc enter into ESTABLISHED from the state < ESTABLISHED and decremented when the asoc is being deleted.
However, in sctp_sf_do_dupcook_b(), the asoc's state can be changed to ESTABLISHED from the state >= ESTABLISHED where it shouldn't increment SCTP_MIB_CURRESTAB. Otherwise, one asoc may increment MIB_CURRESTAB multiple times but only decrement once at the end.
I was able to reproduce it by using scapy to do the 4-way shakehands, after that I replayed the COOKIE-ECHO chunk with 'peer_vtag' field changed to different values, and SCTP_MIB_CURRESTAB was incremented multiple times and never went back to 0 even when the asoc was freed.
This patch is to fix it by only incrementing SCTP_MIB_CURRESTAB when the state < ESTABLISHED in sctp_sf_do_dupcook_b().
--- net/sctp/sm_statefuns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sctp/sm_statefuns.c +2 -1
@@ -1944,7 +1944,8 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(sctp_add_cmd_sf (commands,SCTP_CMD_UPDATE_ASSOC ,SCTP_ASOC (new_asoc));sctp_add_cmd_sf (commands,SCTP_CMD_NEW_STATE ,SCTP_STATE (SCTP_STATE_ESTABLISHED )); -SCTP_INC_STATS (net,SCTP_MIB_CURRESTAB ); +if (asoc->state <SCTP_STATE_ESTABLISHED ) +SCTP_INC_STATS (net,SCTP_MIB_CURRESTAB );sctp_add_cmd_sf (commands,SCTP_CMD_HB_TIMERS_START ,SCTP_NULL ()); repl =sctp_make_cookie_ack (new_asoc, chunk);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 194/329 netfilter: xt_SECMARK: add new revision to fix structure layout
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit c7d13358b6a2f49f81a34aa323a2d0878a0532a2 ]
This extension breaks when trying to delete rules, add a new revision to fix this.
--- include/uapi/linux/netfilter/xt_SECMARK.h | 6 ++ net/netfilter/xt_SECMARK.c | 88 ++++++++++++++++++----- 2 files changed, 75 insertions(+), 19 deletions(-)
include/uapi/linux/netfilter/xt_SECMARK.h +6 -0
@@ -20,4 +20,10 @@ struct xt_secmark_target_info { char secctx[SECMARK_SECCTX_MAX]; }; +struct xt_secmark_target_info_v1 { +__u8 mode; +char secctx[SECMARK_SECCTX_MAX ]; +__u32 secid; +}; +#endif /*_XT_SECMARK_H_target */
net/netfilter/xt_SECMARK.c +69 -19
126 lines not on this page · raw message
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 195/329 xsk: Fix for xp_aligned_validate_desc() when len == chunk_size
In reply to Greg Kroah-HartmanFrom: Xuan Zhuo <[email protected]>
[ Upstream commit ac31565c21937eee9117e43c9cd34f557f6f1cb8 ]
When desc->len is equal to chunk_size, it is legal. But when the xp_aligned_validate_desc() got chunk_end from desc->addr + desc->len pointing to the next chunk during the check, it caused the check to fail.
This problem was first introduced in bbff2f321a86 ("xsk: new descriptor addressing scheme"). Later in 2b43470add8c ("xsk: Introduce AF_XDP buffer allocation API") this piece of code was moved into the new function called xp_aligned_validate_desc(). This function was then moved into xsk_queue.h via 26062b185eee ("xsk: Explicitly inline functions and move definitions").
--- net/xdp/xsk_queue.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/xdp/xsk_queue.h +3 -4
@@ -128,13 +128,12 @@ static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr)static inline bool xp_aligned_validate_desc (struct xsk_buff_pool *pool,struct xdp_desc *desc) { -u64 chunk, chunk_end; +u64 chunk; - chunk =xp_aligned_extract_addr (pool, desc->addr); - chunk_end =xp_aligned_extract_addr (pool, desc->addr + desc->len); -if (chunk != chunk_end) +if (desc->len > pool->chunk_size)return false; + chunk =xp_aligned_extract_addr (pool, desc->addr);if (chunk >= pool->addrs_cnt)return false;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 196/329 net: stmmac: Clear receive all(RA) bit when promiscuous mode is off
In reply to Greg Kroah-HartmanFrom: Ramesh Babu B <[email protected]>
[ Upstream commit 4c7a94286ef7ac7301d633f17519fb1bb89d7550 ]
In promiscuous mode Receive All bit is set in GMAC packet filter register, but outside promiscuous mode Receive All bit is not cleared, which resulted in all network packets are received when toggle (ON/OFF) the promiscuous mode.
--- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +1 -0
@@ -638,6 +638,7 @@ static void dwmac4_set_filter(struct mac_device_info *hw, value &= ~GMAC_PACKET_FILTER_PCF ; value &= ~GMAC_PACKET_FILTER_PM ; value &= ~GMAC_PACKET_FILTER_PR ; + value &= ~GMAC_PACKET_FILTER_RA ;if (dev->flags &IFF_PROMISC ) {/* VLAN Tag Filter Fail Packets Queuing */ if (hw->vlan_fail_q_en) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 197/329 drm/radeon: Fix off-by-one power_state index heap overwrite
In reply to Greg Kroah-HartmanFrom: Kees Cook <[email protected]>
[ Upstream commit 5bbf219328849e83878bddb7c226d8d42e84affc ]
An out of bounds write happens when setting the default power state. KASAN sees this as:
[drm] radeon: 512M of GTT memory ready.
[drm] GART: num cpu pages 131072, num gpu pages 131072
==================================================================
BUG: KASAN: slab-out-of-bounds in radeon_atombios_parse_power_table_1_3+0x1837/0x1998 [radeon] Write of size 4 at addr ffff88810178d858 by task systemd-udevd/157 CPU: 0 PID: 157 Comm: systemd-udevd Not tainted 5.12.0-E620 #50 Hardware name: eMachines eMachines E620 /Nile , BIOS V1.03 09/30/2008 Call Trace: dump_stack+0xa5/0xe6 print_address_description.constprop.0+0x18/0x239 kasan_report+0x170/0x1a8 radeon_atombios_parse_power_table_1_3+0x1837/0x1998 [radeon] radeon_atombios_get_power_modes+0x144/0x1888 [radeon] radeon_pm_init+0x1019/0x1904 [radeon] rs690_init+0x76e/0x84a [radeon] radeon_device_init+0x1c1a/0x21e5 [radeon] radeon_driver_load_kms+0xf5/0x30b [radeon] drm_dev_register+0x255/0x4a0 [drm] radeon_pci_probe+0x246/0x2f6 [radeon] pci_device_probe+0x1aa/0x294 really_probe+0x30e/0x850 driver_probe_device+0xe6/0x135 device_driver_attach+0xc1/0xf8 __driver_attach+0x13f/0x146 bus_for_each_dev+0xfa/0x146 bus_add_driver+0x2b3/0x447 driver_register+0x242/0x2c1 do_one_initcall+0x149/0x2fd do_init_module+0x1ae/0x573 load_module+0x4dee/0x5cca __do_sys_finit_module+0xf1/0x140 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xae
Without KASAN, this will manifest later when the kernel attempts to allocate memory that was stomped, since it collides with the inline slab freelist pointer:
invalid opcode: 0000 [#1] SMP NOPTI
CPU: 0 PID: 781 Comm: openrc-run.sh Tainted: G W 5.10.12-gentoo-E620 #2 Hardware name: eMachines eMachines E620 /Nile , BIOS V1.03 09/30/2008 RIP: 0010:kfree+0x115/0x230 Code: 89 c5 e8 75 ea ff ff 48 8b 00 0f ba e0 09 72 63 e8 1f f4 ff ff 41 89 c4 48 8b 45 00 0f ba e0 10 72 0a 48 8b 45 08 a8 01 75 02 <0f> 0b 44 89 e1 48 c7 c2 00 f0 ff ff be 06 00 00 00 48 d3 e2 48 c7 RSP: 0018:ffffb42f40267e10 EFLAGS: 00010246 RAX: ffffd61280ee8d88 RBX: 0000000000000004 RCX: 000000008010000d RDX: 4000000000000000 RSI: ffffffffba1360b0 RDI: ffffd61280ee8d80 RBP: ffffd61280ee8d80 R08: ffffffffb91bebdf R09: 0000000000000000 R10: ffff8fe2c1047ac8 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000100 FS: 00007fe80eff6b68(0000) GS:ffff8fe339c00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fe80eec7bc0 CR3: 0000000038012000 CR4: 00000000000006f0 Call Trace: __free_fdtable+0x16/0x1f put_files_struct+0x81/0x9b do_exit+0x433/0x94d do_group_exit+0xa6/0xa6 __x64_sys_exit_group+0xf/0xf do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7fe80ef64bea Code: Unable to access opcode bytes at RIP 0x7fe80ef64bc0. RSP: 002b:00007ffdb1c47528 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fe80ef64bea RDX: 00007fe80ef64f60 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 R10: 00007fe80ee2c620 R11: 0000000000000246 R12: 00007fe80eff41e0 R13: 00000000ffffffff R14: 0000000000000024 R15: 00007fe80edf9cd0 Modules linked in: radeon(+) ath5k(+) snd_hda_codec_realtek ...
Use a valid power_state index when initializing the "flags" and "misc" and "misc2" fields.
--- drivers/gpu/drm/radeon/radeon_atombios.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +3 -3
@@ -2249,10 +2249,10 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.default_power_state_index = state_index -1 ; rdev->pm.power_state[state_index -1 ].default_clock_mode = &rdev->pm.power_state[state_index -1 ].clock_info[0 ]; - rdev->pm.power_state[state_index].flags &= + rdev->pm.power_state[state_index -1 ].flags &= ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY ; - rdev->pm.power_state[state_index].misc =0 ; - rdev->pm.power_state[state_index].misc2 =0 ; + rdev->pm.power_state[state_index -1 ].misc =0 ; + rdev->pm.power_state[state_index -1 ].misc2 =0 ; }return state_index; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 198/329 drm/radeon: Avoid power table parsing memory leaks
In reply to Greg Kroah-HartmanFrom: Kees Cook <[email protected]>
[ Upstream commit c69f27137a38d24301a6b659454a91ad85dff4aa ]
Avoid leaving a hanging pre-allocated clock_info if last mode is invalid, and avoid heap corruption if no valid modes are found.
--- drivers/gpu/drm/radeon/radeon_atombios.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/gpu/drm/radeon/radeon_atombios.c +15 -5
@@ -2119,11 +2119,14 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)return state_index;/* last mode is usually default, array is low to high */ for (i =0 ; i < num_modes; i++) { - rdev->pm.power_state[state_index].clock_info = -kcalloc (1 ,sizeof (struct radeon_pm_clock_info ), -GFP_KERNEL ); +/* avoid memory leaks from invalid modes or unknown frev. */ +if (!rdev->pm.power_state[state_index].clock_info) { + rdev->pm.power_state[state_index].clock_info = +kzalloc (sizeof (struct radeon_pm_clock_info ), +GFP_KERNEL ); + }if (!rdev->pm.power_state[state_index].clock_info) -return state_index; + goto out; rdev->pm.power_state[state_index].num_clock_modes =1 ; rdev->pm.power_state[state_index].clock_info[0 ].voltage.type =VOLTAGE_NONE ;switch (frev) {
@@ -2242,8 +2245,15 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)break ; } } +out: +/* free any unused clock_info allocation. */ +if (state_index && state_index < num_modes) { +kfree (rdev->pm.power_state[state_index].clock_info); + rdev->pm.power_state[state_index].clock_info =NULL ; + } +/* last mode is usually default */ -if (rdev->pm.default_power_state_index ==-1 ) { +if (state_index && rdev->pm.default_power_state_index ==-1 ) { rdev->pm.power_state[state_index -1 ].type =POWER_STATE_TYPE_DEFAULT ; rdev->pm.default_power_state_index = state_index -1 ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 199/329 arm64: entry: factor irq triage logic into macros
In reply to Greg Kroah-HartmanFrom: Marc Zyngier <[email protected]>
[ Upstream commit 9eb563cdabe1d583c262042d5d44cc256f644543 ]
In subsequent patches we'll allow an FIQ handler to be registered, and FIQ exceptions will need to be triaged very similarly to IRQ exceptions. So that we can reuse the existing logic, this patch factors the IRQ triage logic out into macros that can be reused for FIQ.
The macros are named to follow the elX_foo_handler scheme used by the C exception handlers. For consistency with other top-level exception handlers, the kernel_entry/kernel_exit logic is not moved into the macros. As FIQ will use a different C handler, this handler name is provided as an argument to the macros.
There should be no functional change as a result of this patch.
--- arch/arm64/kernel/entry.S | 80 +++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 37 deletions(-)
arch/arm64/kernel/entry.S +43 -37
@@ -493,8 +493,8 @@ tsk .req x28 // current thread_info /* * Interrupt handling. */ - .macro irq_handler - ldr_l x1, handle_arch_irq + .macro irq_handler, handler:req + ldr_l x1, \handler mov x0, sp irq_stack_entry blr x1
@@ -533,6 +533,45 @@ alternative_endif #endif .endm + .macro el1_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x1 + enable_da_f + + mov x0, sp + bl enter_el1_irq_or_nmi + + irq_handler \handler + +#ifdef CONFIG_PREEMPTION + ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count +alternative_if ARM64_HAS_IRQ_PRIO_MASKING + /* + * DA_F were cleared at start of handling. If anything is set in DAIF, + * we come back from an NMI, so skip preemption + */ + mrs x0, daif + orr x24, x24, x0 +alternative_else_nop_endif + cbnz x24, 1f // preempt count != 0 || NMI return path + bl arm64_preempt_schedule_irq // irq en/disable is done inside +1: +#endif + + mov x0, sp + bl exit_el1_irq_or_nmi + .endm + + .macro el0_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x0 + user_exit_irqoff + enable_da_f + + tbz x22, #55, 1f + bl do_el0_irq_bp_hardening +1: + irq_handler \handler + .endm + .text /*
@@ -662,32 +701,7 @@ SYM_CODE_END(el1_sync) .align 6 SYM_CODE_START_LOCAL_NOALIGN(el1_irq) kernel_entry 1 - gic_prio_irq_setup pmr=x20, tmp=x1 - enable_da_f - - mov x0, sp - bl enter_el1_irq_or_nmi - - irq_handler - -#ifdef CONFIG_PREEMPTION - ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count -alternative_if ARM64_HAS_IRQ_PRIO_MASKING - /* - * DA_F were cleared at start of handling. If anything is set in DAIF, - * we come back from an NMI, so skip preemption - */ - mrs x0, daif - orr x24, x24, x0 -alternative_else_nop_endif - cbnz x24, 1f // preempt count != 0 || NMI return path - bl arm64_preempt_schedule_irq // irq en/disable is done inside -1: -#endif - - mov x0, sp - bl exit_el1_irq_or_nmi - + el1_interrupt_handler handle_arch_irq kernel_exit 1 SYM_CODE_END(el1_irq)
@@ -727,15 +741,7 @@ SYM_CODE_END(el0_error_compat) SYM_CODE_START_LOCAL_NOALIGN(el0_irq) kernel_entry 0 el0_irq_naked: - gic_prio_irq_setup pmr=x20, tmp=x0 - user_exit_irqoff - enable_da_f - - tbz x22, #55, 1f - bl do_el0_irq_bp_hardening -1: - irq_handler - + el0_interrupt_handler handle_arch_irq b ret_to_user SYM_CODE_END(el0_irq)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 200/329 arm64: entry: always set GIC_PRIO_PSR_I_SET during entry
In reply to Greg Kroah-HartmanFrom: Mark Rutland <[email protected]>
[ Upstream commit 4d6a38da8e79e94cbd1344aa90876f0f805db705 ]
Zenghui reports that booting a kernel with "irqchip.gicv3_pseudo_nmi=1" on the command line hits a warning during kernel entry, due to the way we manipulate the PMR.
Early in the entry sequence, we call lockdep_hardirqs_off() to inform lockdep that interrupts have been masked (as the HW sets DAIF wqhen entering an exception). Architecturally PMR_EL1 is not affected by exception entry, and we don't set GIC_PRIO_PSR_I_SET in the PMR early in the exception entry sequence, so early in exception entry the PMR can indicate that interrupts are unmasked even though they are masked by DAIF.
If DEBUG_LOCKDEP is selected, lockdep_hardirqs_off() will check that interrupts are masked, before we set GIC_PRIO_PSR_I_SET in any of the exception entry paths, and hence lockdep_hardirqs_off() will WARN() that something is amiss.
We can avoid this by consistently setting GIC_PRIO_PSR_I_SET during exception entry so that kernel code sees a consistent environment. We must also update local_daif_inherit() to undo this, as currently only touches DAIF. For other paths, local_daif_restore() will update both DAIF and the PMR. With this done, we can remove the existing special cases which set this later in the entry code.
We always use (GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET) for consistency with local_daif_save(), as this will warn if it ever encounters (GIC_PRIO_IRQOFF | GIC_PRIO_PSR_I_SET), and never sets this itself. This matches the gic_prio_kentry_setup that we have to retain for ret_to_user.
The original splat from Zenghui's report was:
| DEBUG_LOCKS_WARN_ON(!irqs_disabled()) | WARNING: CPU: 3 PID: 125 at kernel/locking/lockdep.c:4258 lockdep_hardirqs_off+0xd4/0xe8 | Modules linked in: | CPU: 3 PID: 125 Comm: modprobe Tainted: G W 5.12.0-rc8+ #463 | Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 | pstate: 604003c5 (nZCv DAIF +PAN -UAO -TCO BTYPE=--) | pc : lockdep_hardirqs_off+0xd4/0xe8 | lr : lockdep_hardirqs_off+0xd4/0xe8 | sp : ffff80002a39bad0 | pmr_save: 000000e0 | x29: ffff80002a39bad0 x28: ffff0000de214bc0 | x27: ffff0000de1c0400 x26: 000000000049b328 | x25: 0000000000406f30 x24: ffff0000de1c00a0 | x23: 0000000020400005 x22: ffff8000105f747c | x21: 0000000096000044 x20: 0000000000498ef9 | x19: ffff80002a39bc88 x18: ffffffffffffffff | x17: 0000000000000000 x16: ffff800011c61eb0 | x15: ffff800011700a88 x14: 0720072007200720 | x13: 0720072007200720 x12: 0720072007200720 | x11: 0720072007200720 x10: 0720072007200720 | x9 : ffff80002a39bad0 x8 : ffff80002a39bad0 | x7 : ffff8000119f0800 x6 : c0000000ffff7fff | x5 : ffff8000119f07a8 x4 : 0000000000000001 | x3 : 9bcdab23f2432800 x2 : ffff800011730538 | x1 : 9bcdab23f2432800 x0 : 0000000000000000 | Call trace: | lockdep_hardirqs_off+0xd4/0xe8 | enter_from_kernel_mode.isra.5+0x7c/0xa8 | el1_abort+0x24/0x100 | el1_sync_handler+0x80/0xd0 | el1_sync+0x6c/0x100 | __arch_clear_user+0xc/0x90 | load_elf_binary+0x9fc/0x1450 | bprm_execve+0x404/0x880 | kernel_execve+0x180/0x188 | call_usermodehelper_exec_async+0xdc/0x158 | ret_from_fork+0x10/0x18
--- arch/arm64/include/asm/daifflags.h | 3 +++ arch/arm64/kernel/entry-common.c | 17 ----------------- arch/arm64/kernel/entry.S | 15 ++------------- 3 files changed, 5 insertions(+), 30 deletions(-)
arch/arm64/include/asm/daifflags.h +3 -0
@@ -131,6 +131,9 @@ static inline void local_daif_inherit(struct pt_regs *regs)if (interrupts_enabled (regs))trace_hardirqs_on (); +if (system_uses_irq_prio_masking ()) +gic_write_pmr (regs->pmr_save); +/* * We can't use local_daif_restore(regs->pstate) here as * system_has_prio_mask_debugging() won't restore the I bit if it can
arch/arm64/kernel/entry-common.c +0 -17
@@ -177,14 +177,6 @@ static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) {unsigned long far =read_sysreg (far_el1); -/* -* The CPU masked interrupts, and we are leaving them masked during -* do_debug_exception(). Update PMR as if we had called -* local_daif_mask(). -*/ -if (system_uses_irq_prio_masking ()) -gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET ); -arm64_enter_el1_dbg (regs);do_debug_exception (far, esr, regs);arm64_exit_el1_dbg (regs);
@@ -348,9 +340,6 @@ static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr)/* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */ unsigned long far =read_sysreg (far_el1); -if (system_uses_irq_prio_masking ()) -gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET ); -enter_from_user_mode ();do_debug_exception (far, esr, regs);local_daif_restore (DAIF_PROCCTX_NOIRQ );
@@ -358,9 +347,6 @@ static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr) static void noinstr el0_svc(struct pt_regs *regs) { -if (system_uses_irq_prio_masking ()) -gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET ); -enter_from_user_mode ();do_el0_svc (regs); }
@@ -435,9 +421,6 @@ static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr) static void noinstr el0_svc_compat(struct pt_regs *regs) { -if (system_uses_irq_prio_masking ()) -gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET ); -enter_from_user_mode ();do_el0_svc_compat (regs); }
arch/arm64/kernel/entry.S +2 -13
@@ -292,6 +292,8 @@ alternative_else_nop_endif alternative_if ARM64_HAS_IRQ_PRIO_MASKING mrs_s x20, SYS_ICC_PMR_EL1 str x20, [sp, #S_PMR_SAVE] + mov x20, #GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET + msr_s SYS_ICC_PMR_EL1, x20 alternative_else_nop_endif /* Re-enable tag checking (TCO set on exception entry) */
@@ -524,17 +526,7 @@ alternative_endif #endif .endm - .macro gic_prio_irq_setup, pmr:req, tmp:req -#ifdef CONFIG_ARM64_PSEUDO_NMI - alternative_if ARM64_HAS_IRQ_PRIO_MASKING - orr \tmp, \pmr, #GIC_PRIO_PSR_I_SET - msr_s SYS_ICC_PMR_EL1, \tmp - alternative_else_nop_endif -#endif - .endm - .macro el1_interrupt_handler, handler:req - gic_prio_irq_setup pmr=x20, tmp=x1 enable_da_f mov x0, sp
@@ -562,7 +554,6 @@ alternative_else_nop_endif .endm .macro el0_interrupt_handler, handler:req - gic_prio_irq_setup pmr=x20, tmp=x0 user_exit_irqoff enable_da_f
@@ -748,7 +739,6 @@ SYM_CODE_END(el0_irq) SYM_CODE_START_LOCAL(el1_error) kernel_entry 1 mrs x1, esr_el1 - gic_prio_kentry_setup tmp=x2 enable_dbg mov x0, sp bl do_serror
@@ -759,7 +749,6 @@ SYM_CODE_START_LOCAL(el0_error) kernel_entry 0 el0_error_naked: mrs x25, esr_el1 - gic_prio_kentry_setup tmp=x2 user_exit_irqoff enable_dbg mov x0, sp
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 201/329 khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
[ Upstream commit 74e579bf231a337ab3786d59e64bc94f45ca7b3f ]
In writable and !referenced case, the result value should be SCAN_LACK_REFERENCED_PAGE for trace_mm_collapse_huge_page_isolate() instead of default 0 (SCAN_FAIL) here.
--- mm/khugepaged.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
mm/khugepaged.c +9 -9
@@ -716,17 +716,17 @@ next:if (pte_write (pteval)) writable = true; } -if (likely (writable)) { -if (likely (referenced)) { - result =SCAN_SUCCEED ; -trace_mm_collapse_huge_page_isolate (page, none_or_zero, - referenced, writable, result); -return 1 ; - } - }else { + +if (unlikely (!writable)) { result =SCAN_PAGE_RO ; + }else if (unlikely (!referenced)) { + result =SCAN_LACK_REFERENCED_PAGE ; + }else { + result =SCAN_SUCCEED ; +trace_mm_collapse_huge_page_isolate (page, none_or_zero, + referenced, writable, result); +return 1 ; } - out:release_pte_pages (pte, _pte, compound_pagelist); trace_mm_collapse_huge_page_isolate(page, none_or_zero,
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 202/329 mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
[ Upstream commit da56388c4397878a65b74f7fe97760f5aa7d316b ]
A rare out of memory error would prevent removal of the reserve map region for a page. hugetlb_fix_reserve_counts() handles this rare case to avoid dangling with incorrect counts. Unfortunately, hugepage_subpool_get_pages and hugetlb_acct_memory could possibly fail too. We should correctly handle these cases.
--- mm/hugetlb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
mm/hugetlb.c +9 -2
@@ -745,13 +745,20 @@ void hugetlb_fix_reserve_counts(struct inode *inode) {struct hugepage_subpool *spool =subpool_inode (inode);long rsv_adjust; +bool reserved = false; rsv_adjust =hugepage_subpool_get_pages (spool,1 ); -if (rsv_adjust) { +if (rsv_adjust >0 ) {struct hstate *h =hstate_inode (inode); -hugetlb_acct_memory (h,1 ); +if (!hugetlb_acct_memory (h,1 )) + reserved = true; + }else if (!rsv_adjust) { + reserved = true; } + +if (!reserved) +pr_warn ("hugetlb: Huge Page Reserved count may go negative.\n" ); }/*
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 203/329 mm/migrate.c: fix potential indeterminate pte entry in migrate_vma_insert_page()
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
[ Upstream commit 34f5e9b9d1990d286199084efa752530ee3d8297 ]
If the zone device page does not belong to un-addressable device memory, the variable entry will be uninitialized and lead to indeterminate pte entry ultimately. Fix this unexpected case and warn about it.
--- mm/migrate.c | 7 +++++++ 1 file changed, 7 insertions(+)
mm/migrate.c +7 -0
@@ -2967,6 +2967,13 @@ static void migrate_vma_insert_page(struct migrate_vma *migrate, swp_entry =make_device_private_entry (page, vma->vm_flags &VM_WRITE ); entry =swp_entry_to_pte (swp_entry); + }else { +/* +* For now we only support migrating to un-addressable +* device memory. +*/ +pr_warn_once ("Unsupported ZONE_DEVICE page type.\n" ); + goto abort; } }else { entry =mk_pte (page, vma->vm_page_prot);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 204/329 ksm: fix potential missing rmap_item for stable_node
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
[ Upstream commit c89a384e2551c692a9fe60d093fd7080f50afc51 ]
When removing rmap_item from stable tree, STABLE_FLAG of rmap_item is cleared with head reserved. So the following scenario might happen: For ksm page with rmap_item1:
cmp_and_merge_page
stable_node->head = &migrate_nodes; remove_rmap_item_from_tree, but head still equal to stable_node; try_to_merge_with_ksm_page failed;
return;
For the same ksm page with rmap_item2, stable node migration succeed this time. The stable_node->head does not equal to migrate_nodes now. For ksm page with rmap_item1 again:
cmp_and_merge_page
stable_node->head != &migrate_nodes && rmap_item->head == stable_node return;
We would miss the rmap_item for stable_node and might result in failed rmap_walk_ksm(). Fix this by set rmap_item->head to NULL when rmap_item is removed from stable tree.
--- mm/ksm.c | 1 + 1 file changed, 1 insertion(+)
mm/ksm.c +1 -0
@@ -794,6 +794,7 @@ static void remove_rmap_item_from_tree(struct rmap_item *rmap_item) stable_node->rmap_hlist_len--;put_anon_vma (rmap_item->anon_vma); + rmap_item->head =NULL ; rmap_item->address &=PAGE_MASK ; }else if (rmap_item->address &UNSTABLE_FLAG ) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 205/329 mm/gup: check every subpage of a compound page during isolation
In reply to Greg Kroah-HartmanFrom: Pavel Tatashin <[email protected]>
[ Upstream commit 83c02c23d0747a7bdcd71f99a538aacec94b146c ]
When pages are isolated in check_and_migrate_movable_pages() we skip compound number of pages at a time. However, as Jason noted, it is not necessary correct that pages[i] corresponds to the pages that we skipped. This is because it is possible that the addresses in this range had split_huge_pmd()/split_huge_pud(), and these functions do not update the compound page metadata.
The problem can be reproduced if something like this occurs:
1. User faulted huge pages.
2. split_huge_pmd() was called for some reason
3. User has unmapped some sub-pages in the range
4. User tries to longterm pin the addresses.
The resulting pages[i] might end-up having pages which are not compound size page aligned.
--- mm/gup.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)
mm/gup.c +7 -12
@@ -1549,26 +1549,23 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm, unsigned int gup_flags) {unsigned long i; -unsigned long step;bool drain_allow = true;bool migrate_allow = true;LIST_HEAD (cma_page_list);long ret = nr_pages; +struct page *prev_head, *head;struct migration_target_control mtc = { .nid =NUMA_NO_NODE , .gfp_mask =GFP_USER | __GFP_MOVABLE | __GFP_NOWARN, }; check_again: -for (i =0 ; i < nr_pages;) { - -struct page *head =compound_head (pages[i]); - -/* -* gup may start from a tail page. Advance step by the left -* part. -*/ - step =compound_nr (head) - (pages[i] - head); + prev_head =NULL ; +for (i =0 ; i < nr_pages; i++) { + head =compound_head (pages[i]); +if (head == prev_head) +continue ; + prev_head = head;/* * If we get a page from the CMA zone, since we are going to * be pinning these entries, we might as well move them out
@@ -1592,8 +1589,6 @@ check_again: } } } - - i += step; }if (!list_empty (&cma_page_list)) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 206/329 mm/gup: return an error on migration failure
In reply to Greg Kroah-HartmanFrom: Pavel Tatashin <[email protected]>
[ Upstream commit f0f4463837da17a89d965dcbe4e411629dbcf308 ]
When migration failure occurs, we still pin pages, which means that we may pin CMA movable pages which should never be the case.
Instead return an error without pinning pages when migration failure happens.
No need to retry migrating, because migrate_pages() already retries 10 times.
--- mm/gup.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
mm/gup.c +7 -10
@@ -1550,7 +1550,6 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm, {unsigned long i;bool drain_allow = true; -bool migrate_allow = true;LIST_HEAD (cma_page_list);long ret = nr_pages;struct page *prev_head, *head;
@@ -1601,17 +1600,15 @@ check_again:for (i =0 ; i < nr_pages; i++)put_page (pages[i]); -if (migrate_pages (&cma_page_list, alloc_migration_target,NULL , - (unsigned long )&mtc,MIGRATE_SYNC ,MR_CONTIG_RANGE )) { -/* -* some of the pages failed migration. Do get_user_pages -* without migration. -*/ - migrate_allow = false; - + ret =migrate_pages (&cma_page_list, alloc_migration_target, +NULL , (unsigned long )&mtc,MIGRATE_SYNC , +MR_CONTIG_RANGE ); +if (ret) {if (!list_empty (&cma_page_list))putback_movable_pages (&cma_page_list); +return ret >0 ? -ENOMEM : ret; } +/* * We did migrate all the pages, Try to get the page references * again migrating any new CMA pages which we failed to isolate
@@ -1621,7 +1618,7 @@ check_again: pages, vmas,NULL , gup_flags); -if ((ret >0 ) && migrate_allow) { +if (ret >0 ) { nr_pages = ret; drain_allow = true; goto check_again;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 207/329 mm/gup: check for isolation errors
In reply to Greg Kroah-HartmanFrom: Pavel Tatashin <[email protected]>
[ Upstream commit 6e7f34ebb8d25d71ce7f4580ba3cbfc10b895580 ]
It is still possible that we pin movable CMA pages if there are isolation errors and cma_page_list stays empty when we check again.
Check for isolation errors, and return success only when there are no isolation errors, and cma_page_list is empty after checking.
Because isolation errors are transient, we retry indefinitely.
--- mm/gup.c | 60 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 26 deletions(-)
mm/gup.c +34 -26
@@ -1548,8 +1548,8 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm,struct vm_area_struct **vmas, unsigned int gup_flags) { - unsigned long i; -bool drain_allow = true; + unsigned long i, isolation_error_count; +bool drain_allow;LIST_HEAD (cma_page_list);long ret = nr_pages;struct page *prev_head, *head;
@@ -1560,6 +1560,8 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm, check_again: prev_head =NULL ; + isolation_error_count =0 ; + drain_allow = true;for (i =0 ; i < nr_pages; i++) { head =compound_head (pages[i]);if (head == prev_head)
@@ -1571,25 +1573,35 @@ check_again:* of the CMA zone if possible. */ if (is_migrate_cma_page (head)) { -if (PageHuge (head)) -isolate_huge_page (head, &cma_page_list); -else { +if (PageHuge (head)) { +if (!isolate_huge_page (head, &cma_page_list)) + isolation_error_count++; + }else {if (!PageLRU (head) && drain_allow) {lru_add_drain_all (); drain_allow = false; } -if (!isolate_lru_page (head)) { -list_add_tail (&head->lru, &cma_page_list); -mod_node_page_state (page_pgdat (head), -NR_ISOLATED_ANON + -page_is_file_lru (head), -thp_nr_pages (head)); +if (isolate_lru_page (head)) { + isolation_error_count++; +continue ; } +list_add_tail (&head->lru, &cma_page_list); +mod_node_page_state (page_pgdat (head), +NR_ISOLATED_ANON + +page_is_file_lru (head), +thp_nr_pages (head)); } } } +/* +* If list is empty, and no isolation errors, means that all pages are +* in the correct zone. +*/ +if (list_empty (&cma_page_list) && !isolation_error_count) +return ret; +if (!list_empty (&cma_page_list)) {/* * drop the above get_user_pages reference.
@@ -1609,23 +1621,19 @@ check_again: return ret > 0 ? -ENOMEM : ret; } -/* -* We did migrate all the pages, Try to get the page references -* again migrating any new CMA pages which we failed to isolate -* earlier. -*/ - ret =__get_user_pages_locked (mm, start, nr_pages, - pages, vmas,NULL , - gup_flags); - -if (ret >0 ) { - nr_pages = ret; - drain_allow = true; - goto check_again; - } +/* We unpinned pages before migration, pin them again */ + ret =__get_user_pages_locked (mm, start, nr_pages, pages, vmas, +NULL , gup_flags); +if (ret <=0 ) +return ret; + nr_pages = ret; } -return ret; +/* +* check again because pages were unpinned, and we also might have +* had isolation errors and need more pages to migrate. +*/ + goto check_again; }#else static long check_and_migrate_cma_pages(struct mm_struct *mm,
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 208/329 ethtool: fix missing NLM_F_MULTI flag when dumping
In reply to Greg Kroah-HartmanFrom: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit cf754ae331be7cc192b951756a1dd031e9ed978a ]
When dumping the ethtool information from all the interfaces, the netlink reply should contain the NLM_F_MULTI flag. This flag allows userspace tools to identify that multiple messages are expected.
--- net/ethtool/netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/ethtool/netlink.c +2 -1
@@ -384,7 +384,8 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,int ret; ehdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, cb->nlh->nlmsg_seq, - ðtool_genl_family,0 , ctx->ops->reply_cmd); + ðtool_genl_family,NLM_F_MULTI , + ctx->ops->reply_cmd);if (!ehdr)return -EMSGSIZE ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 209/329 net: fix nla_strcmp to handle more then one trailing null character
In reply to Greg Kroah-HartmanFrom: Maciej Żenczykowski <[email protected]>
[ Upstream commit 2c16db6c92b0ee4aa61e88366df82169e83c3f7e ]
Android userspace has been using TCA_KIND with a char[IFNAMESIZ] many-null-terminated buffer containing the string 'bpf'.
This works on 4.19 and ceases to work on 5.10.
I'm not entirely sure what fixes tag to use, but I think the issue was likely introduced in the below mentioned 5.4 commit.
--- lib/nlattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/nlattr.c +1 -1
@@ -828,7 +828,7 @@ int nla_strcmp(const struct nlattr *nla, const char *str)int attrlen =nla_len (nla);int d; -if (attrlen >0 && buf[attrlen -1 ] =='\0' ) +while (attrlen >0 && buf[attrlen -1 ] =='\0' ) attrlen--; d = attrlen - len;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 210/329 smc: disallow TCP_ULP in smc_setsockopt()
In reply to Greg Kroah-HartmanFrom: Cong Wang <[email protected]>
[ Upstream commit 8621436671f3a4bba5db57482e1ee604708bf1eb ]
syzbot is able to setup kTLS on an SMC socket which coincidentally uses sk_user_data too. Later, kTLS treats it as psock so triggers a refcnt warning. The root cause is that smc_setsockopt() simply calls TCP setsockopt() which includes TCP_ULP. I do not think it makes sense to setup kTLS on top of SMC sockets, so we should just disallow this setup.
It is hard to find a commit to blame, but we can apply this patch since the beginning of TCP_ULP.
--- net/smc/af_smc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/smc/af_smc.c +3 -1
@@ -2162,6 +2162,9 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,struct smc_sock *smc;int val, rc; +if (level ==SOL_TCP && optname ==TCP_ULP ) +return -EOPNOTSUPP ; + smc =smc_sk (sk);/* generic setsockopts reaching us here always apply to the
@@ -2186,7 +2189,6 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,if (rc || smc->use_fallback) goto out;switch (optname) { -case TCP_ULP :case TCP_FASTOPEN :case TCP_FASTOPEN_CONNECT :case TCP_FASTOPEN_KEY :
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 211/329 netfilter: nfnetlink_osf: Fix a missing skb_header_pointer() NULL check
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 5e024c325406470d1165a09c6feaf8ec897936be ]
Do not assume that the tcph->doff field is correct when parsing for TCP options, skb_header_pointer() might fail to fetch these bits.
--- net/netfilter/nfnetlink_osf.c | 2 ++ 1 file changed, 2 insertions(+)
net/netfilter/nfnetlink_osf.c +2 -0
@@ -186,6 +186,8 @@ static const struct tcphdr *nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx *ctx, ctx->optp =skb_header_pointer (skb,ip_hdrlen (skb) +sizeof (struct tcphdr ), ctx->optsize, opts); +if (!ctx->optp) +return NULL ; }return tcp;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 212/329 netfilter: nftables: Fix a memleak from userdata error path in new objects
In reply to Greg Kroah-HartmanFrom: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 85dfd816fabfc16e71786eda0a33a7046688b5b0 ]
Release object name if userdata allocation fails.
--- net/netfilter/nf_tables_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/nf_tables_api.c +2 -2
@@ -6213,9 +6213,9 @@ err_obj_ht:INIT_LIST_HEAD (&obj->list);return err; err_trans: -kfree (obj->key.name); -err_userdata:kfree (obj->udata); +err_userdata: +kfree (obj->key.name); err_strdup:if (obj->ops->destroy) obj->ops->destroy (&ctx, obj);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 213/329 can: mcp251xfd: mcp251xfd_probe(): add missing can_rx_offload_del() in error path
In reply to Greg Kroah-HartmanFrom: Marc Kleine-Budde <[email protected]>
[ Upstream commit 4376ea42db8bfcac2bc3a30bba93917244a8c2d4 ]
This patch adds the missing can_rx_offload_del(), that must be called if mcp251xfd_register() fails.
--- drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +3 -1
@@ -2947,10 +2947,12 @@ static int mcp251xfd_probe(struct spi_device *spi) err =mcp251xfd_register (priv);if (err) - goto out_free_candev; + goto out_can_rx_offload_del;return 0 ; + out_can_rx_offload_del: +can_rx_offload_del (&priv->offload); out_free_candev: spi->max_speed_hz = priv->spi_max_speed_hz_orig;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 214/329 can: mcp251x: fix resume from sleep before interface was brought up
In reply to Greg Kroah-HartmanFrom: Frieder Schrempf <[email protected]>
[ Upstream commit 03c427147b2d3e503af258711af4fc792b89b0af ]
Since 8ce8c0abcba3 the driver queues work via priv->restart_work when resuming after suspend, even when the interface was not previously enabled. This causes a null dereference error as the workqueue is only allocated and initialized in mcp251x_open().
To fix this we move the workqueue init to mcp251x_can_probe() as there is no reason to do it later and repeat it whenever mcp251x_open() is called.
--- drivers/net/can/spi/mcp251x.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-)
drivers/net/can/spi/mcp251x.c +18 -17
@@ -956,8 +956,6 @@ static int mcp251x_stop(struct net_device *net) priv->force_quit =1 ;free_irq (spi->irq, priv); -destroy_workqueue (priv->wq); - priv->wq =NULL ;mutex_lock (&priv->mcp_lock);
@@ -1224,24 +1222,15 @@ static int mcp251x_open(struct net_device *net) goto out_close; } - priv->wq =alloc_workqueue ("mcp251x_wq" ,WQ_FREEZABLE |WQ_MEM_RECLAIM , -0 ); -if (!priv->wq) { - ret = -ENOMEM ; - goto out_clean; - } -INIT_WORK (&priv->tx_work, mcp251x_tx_work_handler); -INIT_WORK (&priv->restart_work, mcp251x_restart_work_handler); - ret =mcp251x_hw_wake (spi);if (ret) - goto out_free_wq; + goto out_free_irq; ret =mcp251x_setup (net, spi);if (ret) - goto out_free_wq; + goto out_free_irq; ret =mcp251x_set_normal_mode (spi);if (ret) - goto out_free_wq; + goto out_free_irq;can_led_event (net,CAN_LED_EVENT_OPEN );
@@ -1250,9 +1239,7 @@ static int mcp251x_open(struct net_device *net)return 0 ; -out_free_wq: -destroy_workqueue (priv->wq); -out_clean: +out_free_irq:free_irq (spi->irq, priv);mcp251x_hw_sleep (spi); out_close:
@@ -1373,6 +1360,15 @@ static int mcp251x_can_probe(struct spi_device *spi)if (ret) goto out_clk; + priv->wq =alloc_workqueue ("mcp251x_wq" ,WQ_FREEZABLE |WQ_MEM_RECLAIM , +0 ); +if (!priv->wq) { + ret = -ENOMEM ; + goto out_clk; + } +INIT_WORK (&priv->tx_work, mcp251x_tx_work_handler); +INIT_WORK (&priv->restart_work, mcp251x_restart_work_handler); + priv->spi = spi;mutex_init (&priv->mcp_lock);
@@ -1417,6 +1413,8 @@ static int mcp251x_can_probe(struct spi_device *spi)return 0 ; error_probe: +destroy_workqueue (priv->wq); + priv->wq =NULL ;mcp251x_power_enable (priv->power,0 ); out_clk:
@@ -1438,6 +1436,9 @@ static int mcp251x_can_remove(struct spi_device *spi)mcp251x_power_enable (priv->power,0 ); +destroy_workqueue (priv->wq); + priv->wq =NULL ; +clk_disable_unprepare (priv->clk);free_candev (net);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 215/329 can: m_can: m_can_tx_work_queue(): fix tx_skb race condition
In reply to Greg Kroah-HartmanFrom: Marc Kleine-Budde <[email protected]>
[ Upstream commit e04b2cfe61072c7966e1a5fb73dd1feb30c206ed ]
The m_can_start_xmit() function checks if the cdev->tx_skb is NULL and returns with NETDEV_TX_BUSY in case tx_sbk is not NULL.
There is a race condition in the m_can_tx_work_queue(), where first the skb is send to the driver and then the case tx_sbk is set to NULL. A TX complete IRQ might come in between and wake the queue, which results in tx_skb not being cleared yet.
--- drivers/net/can/m_can/m_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/can/m_can/m_can.c +2 -1
@@ -1455,6 +1455,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)int i;int putidx; + cdev->tx_skb =NULL ; +/* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id &CAN_EFF_FLAG ) {
@@ -1571,7 +1573,6 @@ static void m_can_tx_work_queue(struct work_struct *ws) tx_work);m_can_tx_handler (cdev); - cdev->tx_skb =NULL ; } static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 216/329 sched: Fix out-of-bound access in uclamp
In reply to Greg Kroah-HartmanFrom: Quentin Perret <[email protected]>
[ Upstream commit 6d2f8909a5fabb73fe2a63918117943986c39b6c ]
Util-clamp places tasks in different buckets based on their clamp values for performance reasons. However, the size of buckets is currently computed using a rounding division, which can lead to an off-by-one error in some configurations.
For instance, with 20 buckets, the bucket size will be 1024/20=51. A task with a clamp of 1024 will be mapped to bucket id 1024/51=20. Sadly, correct indexes are in range [0,19], hence leading to an out of bound memory access.
Clamp the bucket id to fix the issue.
--- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/core.c +1 -1
@@ -928,7 +928,7 @@ DEFINE_STATIC_KEY_FALSE(sched_uclamp_used);static inline unsigned int uclamp_bucket_id (unsigned int clamp_value) { -return clamp_value /UCLAMP_BUCKET_DELTA ; + return min_t(unsigned int, clamp_value / UCLAMP_BUCKET_DELTA, UCLAMP_BUCKETS - 1); }static inline unsigned int uclamp_none (enum uclamp_id clamp_id)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 217/329 sched/fair: Fix unfairness caused by missing load decay
In reply to Greg Kroah-HartmanFrom: Odin Ugedal <[email protected]>
[ Upstream commit 0258bdfaff5bd13c4d2383150b7097aecd6b6d82 ]
This fixes an issue where old load on a cfs_rq is not properly decayed, resulting in strange behavior where fairness can decrease drastically. Real workloads with equally weighted control groups have ended up getting a respective 99% and 1%(!!) of cpu time.
When an idle task is attached to a cfs_rq by attaching a pid to a cgroup, the old load of the task is attached to the new cfs_rq and sched_entity by attach_entity_cfs_rq. If the task is then moved to another cpu (and therefore cfs_rq) before being enqueued/woken up, the load will be moved to cfs_rq->removed from the sched_entity. Such a move will happen when enforcing a cpuset on the task (eg. via a cgroup) that force it to move.
The load will however not be removed from the task_group itself, making it look like there is a constant load on that cfs_rq. This causes the vruntime of tasks on other sibling cfs_rq's to increase faster than they are supposed to; causing severe fairness issues. If no other task is started on the given cfs_rq, and due to the cpuset it would not happen, this load would never be properly unloaded. With this patch the load will be properly removed inside update_blocked_averages. This also applies to tasks moved to the fair scheduling class and moved to another cpu, and this path will also fix that. For fork, the entity is queued right away, so this problem does not affect that.
This applies to cases where the new process is the first in the cfs_rq, issue introduced 3d30544f0212 ("sched/fair: Apply more PELT fixes"), and when there has previously been load on the cgroup but the cgroup was removed from the leaflist due to having null PELT load, indroduced in 039ae8bcf7a5 ("sched/fair: Fix O(nr_cgroups) in the load balancing path").
For a simple cgroup hierarchy (as seen below) with two equally weighted groups, that in theory should get 50/50 of cpu time each, it often leads to a load of 60/40 or 70/30.
parent/
cg-1/
cpu.weight: 100
cpuset.cpus: 1
cg-2/
cpu.weight: 100
cpuset.cpus: 1If the hierarchy is deeper (as seen below), while keeping cg-1 and cg-2 equally weighted, they should still get a 50/50 balance of cpu time. This however sometimes results in a balance of 10/90 or 1/99(!!) between the task groups.
$ ps u -C stress USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 18568 1.1 0.0 3684 100 pts/12 R+ 13:36 0:00 stress --cpu 1 root 18580 99.3 0.0 3684 100 pts/12 R+ 13:36 0:09 stress --cpu 1
parent/
cg-1/
cpu.weight: 100
sub-group/
cpu.weight: 1
cpuset.cpus: 1
cg-2/
cpu.weight: 100
sub-group/
cpu.weight: 10000
cpuset.cpus: 1This can be reproduced by attaching an idle process to a cgroup and moving it to a given cpuset before it wakes up. The issue is evident in many (if not most) container runtimes, and has been reproduced with both crun and runc (and therefore docker and all its "derivatives"), and with both cgroup v1 and v2.
--- kernel/sched/fair.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
kernel/sched/fair.c +9 -3
@@ -10885,16 +10885,22 @@ static void propagate_entity_cfs_rq(struct sched_entity *se) {struct cfs_rq *cfs_rq; +list_add_leaf_cfs_rq (cfs_rq_of (se)); +/* Start to propagate at parent */ se = se->parent;for_each_sched_entity (se) { cfs_rq =cfs_rq_of (se); -if (cfs_rq_throttled (cfs_rq)) -break ; +if (!cfs_rq_throttled (cfs_rq)){ +update_load_avg (cfs_rq, se,UPDATE_TG ); +list_add_leaf_cfs_rq (cfs_rq); +continue ; + } -update_load_avg (cfs_rq, se,UPDATE_TG ); +if (list_add_leaf_cfs_rq (cfs_rq)) +break ; } }#else
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 218/329 net: ipa: fix inter-EE IRQ register definitions
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
[ Upstream commit 6a780f51f87b430cc69ebf4e859e7e9be720b283 ]
In gsi_irq_setup(), two registers are written with the intention of disabling inter-EE channel and event IRQs.
But the wrong registers are used (and defined); the ones used are read-only registers that indicate whether the interrupt condition is present.
Define the mask registers instead of the status registers, and use them to disable the inter-EE interrupt types.
--- drivers/net/ipa/gsi.c | 4 ++-- drivers/net/ipa/gsi_reg.h | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-)
drivers/net/ipa/gsi.c +2 -2
@@ -205,8 +205,8 @@ static void gsi_irq_setup(struct gsi *gsi)iowrite32 (0 , gsi->virt +GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET );/* The inter-EE registers are in the non-adjusted address range */ -iowrite32 (0 , gsi->virt_raw +GSI_INTER_EE_SRC_CH_IRQ_OFFSET ); -iowrite32 (0 , gsi->virt_raw +GSI_INTER_EE_SRC_EV_CH_IRQ_OFFSET ); +iowrite32 (0 , gsi->virt_raw +GSI_INTER_EE_SRC_CH_IRQ_MSK_OFFSET ); +iowrite32 (0 , gsi->virt_raw +GSI_INTER_EE_SRC_EV_CH_IRQ_MSK_OFFSET );iowrite32 (0 , gsi->virt +GSI_CNTXT_GSI_IRQ_EN_OFFSET ); }
drivers/net/ipa/gsi_reg.h +9 -9
@@ -53,15 +53,15 @@#define GSI_EE_REG_ADJUST 0x0000d000/* IPA v4.5+ */ /* The two inter-EE IRQ register offsets are relative to gsi->virt_raw */ -#define GSI_INTER_EE_SRC_CH_IRQ_OFFSET \ - GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET(GSI_EE_AP) -#define GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET (ee) \ - (0x0000c018 + 0x1000 * (ee)) - -#define GSI_INTER_EE_SRC_EV_CH_IRQ_OFFSET \ - GSI_INTER_EE_N_SRC_EV_CH_IRQ_OFFSET(GSI_EE_AP) -#define GSI_INTER_EE_N_SRC_EV_CH_IRQ_OFFSET (ee) \ - (0x0000c01c + 0x1000 * (ee)) +#define GSI_INTER_EE_SRC_CH_IRQ_MSK_OFFSET \ + GSI_INTER_EE_N_SRC_CH_IRQ_MSK_OFFSET(GSI_EE_AP) +#define GSI_INTER_EE_N_SRC_CH_IRQ_MSK_OFFSET (ee) \ + (0x0000c020 + 0x1000 * (ee)) + +#define GSI_INTER_EE_SRC_EV_CH_IRQ_MSK_OFFSET \ + GSI_INTER_EE_N_SRC_EV_CH_IRQ_MSK_OFFSET(GSI_EE_AP) +#define GSI_INTER_EE_N_SRC_EV_CH_IRQ_MSK_OFFSET (ee) \ + (0x0000c024 + 0x1000 * (ee))/* All other register offsets are relative to gsi->virt */ #define GSI_CH_C_CNTXT_0_OFFSET (ch) \
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 219/329 fs/proc/generic.c: fix incorrect pde_is_permanent check
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
[ Upstream commit f4bf74d82915708208bc9d0c9bd3f769f56bfbec ]
Currently the pde_is_permanent() check is being run on root multiple times rather than on the next proc directory entry. This looks like a copy-paste error. Fix this by replacing root with next.
Addresses-Coverity: ("Copy-paste error")
--- fs/proc/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/proc/generic.c +1 -1
@@ -754,7 +754,7 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)while (1 ) { next =pde_subdir_first (de);if (next) { -if (unlikely (pde_is_permanent (root))) { +if (unlikely (pde_is_permanent (next))) {write_unlock (&proc_subdir_lock);WARN (1 ,"removing permanent /proc entry '%s/%s'" , next->parent->name, next->name);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 220/329 kernel: kexec_file: fix error return code of kexec_calculate_store_digests()
In reply to Greg Kroah-HartmanFrom: Jia-Ju Bai <[email protected]>
[ Upstream commit 31d82c2c787d5cf65fedd35ebbc0c1bd95c1a679 ]
When vzalloc() returns NULL to sha_regions, no error return code of kexec_calculate_store_digests() is assigned. To fix this bug, ret is assigned with -ENOMEM in this case.
--- kernel/kexec_file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/kexec_file.c +3 -1
@@ -740,8 +740,10 @@ static int kexec_calculate_store_digests(struct kimage *image) sha_region_sz =KEXEC_SEGMENT_MAX *sizeof (struct kexec_sha_region ); sha_regions =vzalloc (sha_region_sz); -if (!sha_regions) +if (!sha_regions) { + ret = -ENOMEM ; goto out_free_desc; + } desc->tfm = tfm;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 221/329 kernel/resource: make walk_system_ram_res() find all busy IORESOURCE_SYSTEM_RAM resources
In reply to Greg Kroah-HartmanFrom: David Hildenbrand <[email protected]>
[ Upstream commit 97f61c8f44ec9020708b97a51188170add4f3084 ]
Patch series "kernel/resource: make walk_system_ram_res() and walk_mem_res() search the whole tree", v2.
Playing with kdump+virtio-mem I noticed that kexec_file_load() does not consider System RAM added via dax/kmem and virtio-mem when preparing the elf header for kdump. Looking into the details, the logic used in walk_system_ram_res() and walk_mem_res() seems to be outdated.
walk_system_ram_range() already does the right thing, let's change walk_system_ram_res() and walk_mem_res(), and clean up.
Loading a kdump kernel via "kexec -p -s" ... will result in the kdump kernel to also dump dax/kmem and virtio-mem added System RAM now.
Note: kexec-tools on x86-64 also have to be updated to consider this memory in the kexec_load() case when processing /proc/iomem.
This patch (of 3):
It used to be true that we can have system RAM (IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY) only on the first level in the resource tree. However, this is no longer holds for driver-managed system RAM (i.e., added via dax/kmem and virtio-mem), which gets added on lower levels, for example, inside device containers.
We have two users of walk_system_ram_res(), which currently only consideres the first level:
a) kernel/kexec_file.c:kexec_walk_resources() -- We properly skip IORESOURCE_SYSRAM_DRIVER_MANAGED resources via locate_mem_hole_callback(), so even after this change, we won't be placing kexec images onto dax/kmem and virtio-mem added memory. No change.
b) arch/x86/kernel/crash.c:fill_up_crash_elf_data() -- we're currently not adding relevant ranges to the crash elf header, resulting in them not getting dumped via kdump.
This change fixes loading a crashkernel via kexec_file_load() and including dax/kmem and virtio-mem added System RAM in the crashdump on x86-64. Note that e.g,, arm64 relies on memblock data and, therefore, always considers all added System RAM already.
Let's find all IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY resources, making the function behave like walk_system_ram_range().
--- kernel/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/resource.c +1 -1
@@ -454,7 +454,7 @@ int walk_system_ram_res(u64 start, u64 end, void *arg, {unsigned long flags =IORESOURCE_SYSTEM_RAM |IORESOURCE_BUSY ; -return __walk_iomem_res_desc (start, end, flags,IORES_DESC_NONE , true, +return __walk_iomem_res_desc (start, end, flags,IORES_DESC_NONE , false, arg, func); }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 222/329 kernel/resource: make walk_mem_res() find all busy IORESOURCE_MEM resources
In reply to Greg Kroah-HartmanFrom: David Hildenbrand <[email protected]>
[ Upstream commit 3c9c797534364593b73ba6ab060a014af8934721 ]
It used to be true that we can have system RAM (IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY) only on the first level in the resource tree. However, this is no longer holds for driver-managed system RAM (i.e., added via dax/kmem and virtio-mem), which gets added on lower levels, for example, inside device containers.
IORESOURCE_SYSTEM_RAM is defined as IORESOURCE_MEM | IORESOURCE_SYSRAM and just a special type of IORESOURCE_MEM.
The function walk_mem_res() only considers the first level and is used in arch/x86/mm/ioremap.c:__ioremap_check_mem() only. We currently fail to identify System RAM added by dax/kmem and virtio-mem as "IORES_MAP_SYSTEM_RAM", for example, allowing for remapping of such "normal RAM" in __ioremap_caller().
Let's find all IORESOURCE_MEM | IORESOURCE_BUSY resources, making the function behave similar to walk_system_ram_res().
--- kernel/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/resource.c +1 -1
@@ -467,7 +467,7 @@ int walk_mem_res(u64 start, u64 end, void *arg, {unsigned long flags =IORESOURCE_MEM |IORESOURCE_BUSY ; -return __walk_iomem_res_desc (start, end, flags,IORES_DESC_NONE , true, +return __walk_iomem_res_desc (start, end, flags,IORES_DESC_NONE , false, arg, func); }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 223/329 netfilter: nftables: avoid overflows in nft_hash_buckets()
In reply to Greg Kroah-HartmanFrom: Eric Dumazet <[email protected]>
[ Upstream commit a54754ec9891830ba548e2010c889e3c8146e449 ]
Number of buckets being stored in 32bit variables, we have to ensure that no overflows occur in nft_hash_buckets()
syzbot injected a size == 0x40000000 and reported:
UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13 shift exponent 64 is too large for 64-bit type 'long unsigned int' CPU: 1 PID: 29539 Comm: syz-executor.4 Not tainted 5.12.0-rc7-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:79 [inline] dump_stack+0x141/0x1d7 lib/dump_stack.c:120 ubsan_epilogue+0xb/0x5a lib/ubsan.c:148 __ubsan_handle_shift_out_of_bounds.cold+0xb1/0x181 lib/ubsan.c:327 __roundup_pow_of_two include/linux/log2.h:57 [inline] nft_hash_buckets net/netfilter/nft_set_hash.c:411 [inline] nft_hash_estimate.cold+0x19/0x1e net/netfilter/nft_set_hash.c:652 nft_select_set_ops net/netfilter/nf_tables_api.c:3586 [inline] nf_tables_newset+0xe62/0x3110 net/netfilter/nf_tables_api.c:4322 nfnetlink_rcv_batch+0xa09/0x24b0 net/netfilter/nfnetlink.c:488 nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:612 [inline] nfnetlink_rcv+0x3af/0x420 net/netfilter/nfnetlink.c:630 netlink_unicast_kernel net/netlink/af_netlink.c:1312 [inline] netlink_unicast+0x533/0x7d0 net/netlink/af_netlink.c:1338 netlink_sendmsg+0x856/0xd90 net/netlink/af_netlink.c:1927 sock_sendmsg_nosec net/socket.c:654 [inline] sock_sendmsg+0xcf/0x120 net/socket.c:674 ____sys_sendmsg+0x6e8/0x810 net/socket.c:2350 ___sys_sendmsg+0xf3/0x170 net/socket.c:2404 __sys_sendmsg+0xe5/0x1b0 net/socket.c:2433 do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
--- net/netfilter/nft_set_hash.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
net/netfilter/nft_set_hash.c +9 -1
@@ -406,9 +406,17 @@ static void nft_rhash_destroy(const struct nft_set *set) (void *)set); } +/* Number of buckets is stored in u32, so cap our result to 1U<<31 */ +#define NFT_MAX_BUCKETS (1U << 31) +static u32 nft_hash_buckets (u32 size) { -return roundup_pow_of_two (size *4 /3 ); +u64 val =div_u64 ((u64 )size *4 ,3 ); + +if (val >=NFT_MAX_BUCKETS ) +return NFT_MAX_BUCKETS ; + +return roundup_pow_of_two (val); } static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 224/329 i40e: fix broken XDP support
In reply to Greg Kroah-HartmanFrom: Magnus Karlsson <[email protected]>
[ Upstream commit ae4393dfd472b194c90d75d2123105fb5ed59b04 ]
Commit 12738ac4754e ("i40e: Fix sparse errors in i40e_txrx.c") broke XDP support in the i40e driver. That commit was fixing a sparse error in the code by introducing a new variable xdp_res instead of overloading this into the skb pointer. The problem is that the code later uses the skb pointer in if statements and these where not extended to also test for the new xdp_res variable. Fix this by adding the correct tests for xdp_res in these places.
The skb pointer was used to store the result of the XDP program by overloading the results in the error pointer ERR_PTR(-result). Therefore, the allocation failure test that used to only test for !skb now need to be extended to also consider !xdp_res.
i40e_cleanup_headers() had a check that based on the skb value being an error pointer, i.e. a result from the XDP program != XDP_PASS, and if so start to process a new packet immediately, instead of populating skb fields and sending the skb to the stack. This check is not needed anymore, since we have added an explicit test for xdp_res being set and if so just do continue to pick the next packet from the NIC.
--- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_txrx.c +2 -6
@@ -1821,10 +1821,6 @@ static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb, union i40e_rx_desc *rx_desc) { -/* XDP packets use error pointer so abort at this point */ -if (IS_ERR (skb)) -return true; -/* ERR_MASK will only have valid bits if EOP set, and * what we are doing here is actually checking * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
@@ -2437,7 +2433,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) }/* exit if we failed to retrieve a buffer */ -if (!skb) { +if (!xdp_res && !skb) { rx_ring->rx_stats.alloc_buff_failed++; rx_buffer->pagecnt_bias++;break ;
@@ -2449,7 +2445,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)if (i40e_is_non_eop (rx_ring, rx_desc, skb))continue ; -if (i40e_cleanup_headers (rx_ring, skb, rx_desc)) { +if (xdp_res ||i40e_cleanup_headers (rx_ring, skb, rx_desc)) { skb =NULL ;continue ; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 225/329 i40e: Fix use-after-free in i40e_client_subtask()
In reply to Greg Kroah-HartmanFrom: Yunjian Wang <[email protected]>
[ Upstream commit 38318f23a7ef86a8b1862e5e8078c4de121960c3 ]
Currently the call to i40e_client_del_instance frees the object pf->cinst, however pf->cinst->lan_info is being accessed after the free. Fix this by adding the missing return.
Addresses-Coverity: ("Read from pointer after free")
--- drivers/net/ethernet/intel/i40e/i40e_client.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/intel/i40e/i40e_client.c +1 -0
@@ -375,6 +375,7 @@ void i40e_client_subtask(struct i40e_pf *pf)clear_bit (__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);i40e_client_del_instance (pf); +return ; } } }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 226/329 i40e: fix the restart auto-negotiation after FEC modified
In reply to Greg Kroah-HartmanFrom: Jaroslaw Gawin <[email protected]>
[ Upstream commit 61343e6da7810de81d6b826698946ae4f9070819 ]
When FEC mode was changed the link didn't know it because the link was not reset and new parameters were not negotiated. Set a flag 'I40E_AQ_PHY_ENABLE_ATOMIC_LINK' in 'abilities' to restart the link and make it run with the new settings.
--- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/i40e/i40e_ethtool.c +2 -1
@@ -1409,7 +1409,8 @@ static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg)memset (&config,0 ,sizeof (config)); config.phy_type = abilities.phy_type; - config.abilities = abilities.abilities; + config.abilities = abilities.abilities | +I40E_AQ_PHY_ENABLE_ATOMIC_LINK ; config.phy_type_ext = abilities.phy_type_ext; config.link_speed = abilities.link_speed; config.eee_capability = abilities.eee_capability;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 227/329 i40e: Fix PHY type identifiers for 2.5G and 5G adapters
In reply to Greg Kroah-HartmanFrom: Mateusz Palczewski <[email protected]>
[ Upstream commit 15395ec4685bd45a43d1b54b8fd9846b87e2c621 ]
Unlike other supported adapters, 2.5G and 5G use different PHY type identifiers for reading/writing PHY settings and for reading link status. This commit introduces separate PHY identifiers for these two operation types.
--- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 6 ++++-- drivers/net/ethernet/intel/i40e/i40e_common.c | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_type.h | 7 ++----- 4 files changed, 10 insertions(+), 11 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +4 -2
@@ -1565,8 +1565,10 @@ enum i40e_aq_phy_type {I40E_PHY_TYPE_25GBASE_LR =0x22 ,I40E_PHY_TYPE_25GBASE_AOC =0x23 ,I40E_PHY_TYPE_25GBASE_ACC =0x24 , -I40E_PHY_TYPE_2_5GBASE_T =0x30 , -I40E_PHY_TYPE_5GBASE_T =0x31 , +I40E_PHY_TYPE_2_5GBASE_T =0x26 , +I40E_PHY_TYPE_5GBASE_T =0x27 , +I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS =0x30 , +I40E_PHY_TYPE_5GBASE_T_LINK_STATUS =0x31 ,I40E_PHY_TYPE_MAX ,I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP =0xFD , I40E_PHY_TYPE_EMPTY = 0xFE,
drivers/net/ethernet/intel/i40e/i40e_common.c +2 -2
@@ -1154,8 +1154,8 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw)break ;case I40E_PHY_TYPE_100BASE_TX :case I40E_PHY_TYPE_1000BASE_T : -case I40E_PHY_TYPE_2_5GBASE_T : -case I40E_PHY_TYPE_5GBASE_T : +case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS : +case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS :case I40E_PHY_TYPE_10GBASE_T : media =I40E_MEDIA_TYPE_BASET ;break ;
drivers/net/ethernet/intel/i40e/i40e_ethtool.c +2 -2
@@ -841,8 +841,8 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw, 10000baseT_Full);break ;case I40E_PHY_TYPE_10GBASE_T : -case I40E_PHY_TYPE_5GBASE_T : -case I40E_PHY_TYPE_2_5GBASE_T : +case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS : +case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS :case I40E_PHY_TYPE_1000BASE_T :case I40E_PHY_TYPE_100BASE_TX :ethtool_link_ksettings_add_link_mode (ks, supported, Autoneg);
drivers/net/ethernet/intel/i40e/i40e_type.h +2 -5
@@ -239,11 +239,8 @@ struct i40e_phy_info {#define I40E_CAP_PHY_TYPE_25GBASE_ACC BIT_ULL(I40E_PHY_TYPE_25GBASE_ACC + \ I40E_PHY_TYPE_OFFSET)/* Offset for 2.5G/5G PHY Types value to bit number conversion */ -#define I40E_PHY_TYPE_OFFSET2 (-10) -#define I40E_CAP_PHY_TYPE_2_5GBASE_T BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T + \ - I40E_PHY_TYPE_OFFSET2) -#define I40E_CAP_PHY_TYPE_5GBASE_T BIT_ULL(I40E_PHY_TYPE_5GBASE_T + \ - I40E_PHY_TYPE_OFFSET2) +#define I40E_CAP_PHY_TYPE_2_5GBASE_T BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T) +#define I40E_CAP_PHY_TYPE_5GBASE_T BIT_ULL(I40E_PHY_TYPE_5GBASE_T)#define I40E_HW_CAP_MAX_GPIO 30/* Capabilities of a PF or a VF or the whole device */ struct i40e_hw_capabilities {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 228/329 mptcp: fix splat when closing unaccepted socket
In reply to Greg Kroah-HartmanFrom: Paolo Abeni <[email protected]>
[ Upstream commit 578c18eff1627d6a911f08f4cf351eca41fdcc7d ]
If userspace exits before calling accept() on a listener that had at least one new connection ready, we get:
Attempt to release TCP socket in state 8
This happens because the mptcp socket gets cloned when the TCP connection is ready, but the socket is never exposed to userspace.
The client additionally sends a DATA_FIN, which brings connection into CLOSE_WAIT state. This in turn prevents the orphan+state reset fixup in mptcp_sock_destruct() from doing its job.
--- net/mptcp/subflow.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/mptcp/subflow.c +1 -2
@@ -479,8 +479,7 @@ static void mptcp_sock_destruct(struct sock *sk)* ESTABLISHED state and will not have the SOCK_DEAD flag. * Both result in warnings from inet_sock_destruct. */ - -if (sk->sk_state ==TCP_ESTABLISHED ) { +if ((1 << sk->sk_state) & (TCPF_ESTABLISHED |TCPF_CLOSE_WAIT )) { sk->sk_state =TCP_CLOSE ;WARN_ON_ONCE (sk->sk_socket);sock_orphan (sk);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 229/329 ARC: entry: fix off-by-one error in syscall number validation
In reply to Greg Kroah-HartmanFrom: Vineet Gupta <[email protected]>
commit 3433adc8bd09fc9f29b8baddf33b4ecd1ecd2cdc upstream.
We have NR_syscall syscalls from [0 .. NR_syscall-1]. However the check for invalid syscall number is "> NR_syscall" as opposed to >=. This off-by-one error erronesously allows "NR_syscall" to be treated as valid syscall causeing out-of-bounds access into syscall-call table ensuing a crash (holes within syscall table have a invalid-entry handler but this is beyond the array implementing the table).
This problem showed up on v5.6 kernel when testing glibc 2.33 (v5.10 kernel capable, includng faccessat2 syscall 439). The v5.6 kernel has NR_syscalls=439 (0 to 438). Due to the bug, 439 passed by glibc was not handled as -ENOSYS but processed leading to a crash.
--- arch/arc/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arc/kernel/entry.S +2 -2
@@ -177,7 +177,7 @@ tracesys: ; Do the Sys Call as we normally would. ; Validate the Sys Call number - cmp r8, NR_syscalls + cmp r8, NR_syscalls - 1 mov.hi r0, -ENOSYS bhi tracesys_exit
@@ -255,7 +255,7 @@ ENTRY(EV_Trap) ;============ Normal syscall case ; syscall num shd not exceed the total system calls avail - cmp r8, NR_syscalls + cmp r8, NR_syscalls - 1 mov.hi r0, -ENOSYS bhi .Lret_from_system_call
Greg Kroah-Hartman
maintainerPATCH 230/329 ARC: mm: PAE: use 40-bit physical page mask
In reply to Greg Kroah-HartmanFrom: Vladimir Isaev <[email protected]>
commit c5f756d8c6265ebb1736a7787231f010a3b782e5 upstream.
32-bit PAGE_MASK can not be used as a mask for physical addresses when PAE is enabled. PAGE_MASK_PHYS must be used for physical addresses instead of PAGE_MASK.
Without this, init gets SIGSEGV if pte_modify was called:
| potentially unexpected fatal signal 11. | Path: /bin/busybox | CPU: 0 PID: 1 Comm: init Not tainted 5.12.0-rc5-00003-g1e43c377a79f-dirty | Insn could not be fetched | @No matching VMA found | ECR: 0x00040000 EFA: 0x00000000 ERET: 0x00000000 | STAT: 0x80080082 [IE U ] BTA: 0x00000000 | SP: 0x5f9ffe44 FP: 0x00000000 BLK: 0xaf3d4 | LPS: 0x000d093e LPE: 0x000d0950 LPC: 0x00000000 | r00: 0x00000002 r01: 0x5f9fff14 r02: 0x5f9fff20 | ... | Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
--- arch/arc/include/asm/page.h | 12 ++++++++++++ arch/arc/include/asm/pgtable.h | 12 +++--------- arch/arc/include/uapi/asm/page.h | 1 - arch/arc/mm/ioremap.c | 5 +++-- arch/arc/mm/tlb.c | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-)
arch/arc/include/asm/page.h +12 -0
@@ -7,6 +7,18 @@#include <uapi/asm/page.h> +#ifdef CONFIG_ARC_HAS_PAE40 + +#define MAX_POSSIBLE_PHYSMEM_BITS 40 +#define PAGE_MASK_PHYS (0xff00000000ull | PAGE_MASK) + +#else /* CONFIG_ARC_HAS_PAE40 */ + +#define MAX_POSSIBLE_PHYSMEM_BITS 32 +#define PAGE_MASK_PHYS PAGE_MASK + +#endif /* CONFIG_ARC_HAS_PAE40 */ +#ifndef __ASSEMBLY__#define clear_page (paddr) memset((paddr), 0, PAGE_SIZE)
arch/arc/include/asm/pgtable.h +3 -9
@@ -107,8 +107,8 @@#define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE)/* Set of bits not changed in pte_modify */ -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL) - +#define _PAGE_CHG_MASK (PAGE_MASK_PHYS | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SPECIAL)/* More Abbrevaited helpers */ #define PAGE_U_NONE __pgprot(___DEF)#define PAGE_U_R __pgprot(___DEF | _PAGE_READ)
@@ -132,13 +132,7 @@#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_HW_SZ)#define PTE_BITS_RWX (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ) -#ifdef CONFIG_ARC_HAS_PAE40 -#define PTE_BITS_NON_RWX_IN_PD1 (0xff00000000 | PAGE_MASK | _PAGE_CACHEABLE) -#define MAX_POSSIBLE_PHYSMEM_BITS 40 -#else -#define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE) -#define MAX_POSSIBLE_PHYSMEM_BITS 32 -#endif +#define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK_PHYS | _PAGE_CACHEABLE)/************************************************************************** * Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
arch/arc/include/uapi/asm/page.h +0 -1
@@ -33,5 +33,4 @@#define PAGE_MASK (~(PAGE_SIZE-1)) -#endif /* _UAPI__ASM_ARC_PAGE_H */
arch/arc/mm/ioremap.c +3 -2
@@ -53,9 +53,10 @@ EXPORT_SYMBOL(ioremap);void __iomem *ioremap_prot (phys_addr_t paddr,unsigned long size,unsigned long flags) { +unsigned int off;unsigned long vaddr;struct vm_struct *area; -phys_addr_t off, end; +phys_addr_t end;pgprot_t prot =__pgprot (flags);/* Don't allow wraparound, zero size */
@@ -72,7 +73,7 @@ void __iomem *ioremap_prot(phys_addr_t p/* Mappings have to be page-aligned */ off = paddr & ~PAGE_MASK ; - paddr &=PAGE_MASK ; + paddr &=PAGE_MASK_PHYS ; size =PAGE_ALIGN (end +1 ) - paddr;/*
arch/arc/mm/tlb.c +1 -1
@@ -576,7 +576,7 @@ void update_mmu_cache(struct vm_area_str pte_t *ptep) {unsigned long vaddr = vaddr_unaligned &PAGE_MASK ; -phys_addr_t paddr =pte_val (*ptep) &PAGE_MASK ; +phys_addr_t paddr =pte_val (*ptep) &PAGE_MASK_PHYS ;struct page *page =pfn_to_page (pte_pfn (*ptep));create_tlb (vma, vaddr, ptep);
Greg Kroah-Hartman
maintainerPATCH 231/329 ARC: mm: Use max_high_pfn as a HIGHMEM zone border
In reply to Greg Kroah-HartmanFrom: Vladimir Isaev <[email protected]>
commit 1d5e4640e5df15252398c1b621f6bd432f2d7f17 upstream.
Commit 4af22ded0ecf ("arc: fix memory initialization for systems with two memory banks") fixed highmem, but for the PAE case it causes bug messages:
| BUG: Bad page state in process swapper pfn:80000 | page:(ptrval) refcount:0 mapcount:1 mapping:00000000 index:0x0 pfn:0x80000 flags: 0x0() | raw: 00000000 00000100 00000122 00000000 00000000 00000000 00000000 00000000 | raw: 00000000 | page dumped because: nonzero mapcount | Modules linked in: | CPU: 0 PID: 0 Comm: swapper Not tainted 5.12.0-rc5-00003-g1e43c377a79f #1
This is because the fix expects highmem to be always less than lowmem and uses min_low_pfn as an upper zone border for highmem.
max_high_pfn should be ok for both highmem and highmem+PAE cases.
--- arch/arc/mm/init.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
arch/arc/mm/init.c +10 -1
@@ -157,7 +157,16 @@ void __init setup_arch_memory(void) min_high_pfn =PFN_DOWN (high_mem_start); max_high_pfn =PFN_DOWN (high_mem_start + high_mem_sz); - max_zone_pfn[ZONE_HIGHMEM ] = min_low_pfn; +/* +* max_high_pfn should be ok here for both HIGHMEM and HIGHMEM+PAE. +* For HIGHMEM without PAE max_high_pfn should be less than +* min_low_pfn to guarantee that these two regions don't overlap. +* For PAE case highmem is greater than lowmem, so it is natural +* to use max_high_pfn. +* +* In both cases, holes should be handled by pfn_valid(). +*/ + max_zone_pfn[ZONE_HIGHMEM ] = max_high_pfn; high_memory = (void *)(min_high_pfn <<PAGE_SHIFT );
Greg Kroah-Hartman
maintainerPATCH 232/329 sh: Remove unused variable
In reply to Greg Kroah-HartmanFrom: Eric Dumazet <[email protected]>
commit 0d3ae948741ac6d80e39ab27b45297367ee477de upstream.
Removes this annoying warning:
arch/sh/kernel/traps.c: In function ‘nmi_trap_handler’:arch/sh/kernel/traps.c:183:15: warning: unused variable ‘cpu’ [-Wunused-variable]
183 | unsigned int cpu = smp_processor_id();
--- arch/sh/kernel/traps.c | 1 - 1 file changed, 1 deletion(-)
arch/sh/kernel/traps.c +0 -1
@@ -180,7 +180,6 @@ static inline void arch_ftrace_nmi_exit(BUILD_TRAP_HANDLER (nmi) { -unsigned int cpu =smp_processor_id ();TRAP_HANDLER_DECL ;arch_ftrace_nmi_enter ();
Greg Kroah-Hartman
maintainerPATCH 233/329 powerpc/64s: Fix crashes when toggling stf barrier
In reply to Greg Kroah-HartmanFrom: Michael Ellerman <[email protected]>
commit 8ec7791bae1327b1c279c5cd6e929c3b12daaf0a upstream.
The STF (store-to-load forwarding) barrier mitigation can be enabled/disabled at runtime via a debugfs file (stf_barrier), which causes the kernel to patch itself to enable/disable the relevant mitigations.
However depending on which mitigation we're using, it may not be safe to do that patching while other CPUs are active. For example the following crash:
User access of kernel address (c00000003fff5af0) - exploit attempt? (uid: 0) segfault (11) at c00000003fff5af0 nip 7fff8ad12198 lr 7fff8ad121f8 code 1
code: 40820128 e93c00d0 e9290058 7c292840 40810058 38600000 4bfd9a81 e8410018
code: 2c030006 41810154 3860ffb6 e9210098 <e94d8ff0> 7d295279 39400000 40820a3c
Shows that we returned to userspace without restoring the user r13 value, due to executing the partially patched STF exit code.
Fix it by doing the patching under stop machine. The CPUs that aren't doing the patching will be spinning in the core of the stop machine logic. That is currently sufficient for our purposes, because none of the patching we do is to that code or anywhere in the vicinity.
--- arch/powerpc/lib/feature-fixups.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
arch/powerpc/lib/feature-fixups.c +17 -2
@@ -14,6 +14,7 @@#include <linux/string.h> #include <linux/init.h> #include <linux/sched/mm.h> +#include <linux/stop_machine.h> #include <asm/cputable.h> #include <asm/code-patching.h> #include <asm/page.h>
@@ -227,11 +228,25 @@ static void do_stf_exit_barrier_fixups(e : "unknown"); } +static int __do_stf_barrier_fixups (void *data) +{ +enum stf_barrier_type *types = data; + +do_stf_entry_barrier_fixups (*types); +do_stf_exit_barrier_fixups (*types); + +return 0 ; +}void do_stf_barrier_fixups (enum stf_barrier_type types) { -do_stf_entry_barrier_fixups (types); -do_stf_exit_barrier_fixups (types); +/* +* The call to the fallback entry flush, and the fallback/sync-ori exit +* flush can not be safely patched in/out while other CPUs are executing +* them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs +* spin in the stop machine core with interrupts hard disabled. +*/ +stop_machine (__do_stf_barrier_fixups, &types,NULL ); }void do_uaccess_flush_fixups (enum l1d_flush_type types)
Greg Kroah-Hartman
maintainerPATCH 234/329 powerpc/64s: Fix crashes when toggling entry flush barrier
In reply to Greg Kroah-HartmanFrom: Michael Ellerman <[email protected]>
commit aec86b052df6541cc97c5fca44e5934cbea4963b upstream.
The entry flush mitigation can be enabled/disabled at runtime via a debugfs file (entry_flush), which causes the kernel to patch itself to enable/disable the relevant mitigations.
However depending on which mitigation we're using, it may not be safe to do that patching while other CPUs are active. For example the following crash:
sleeper[15639]: segfault (11) at c000000000004c20 nip c000000000004c20 lr c000000000004c20
Shows that we returned to userspace with a corrupted LR that points into the kernel, due to executing the partially patched call to the fallback entry flush (ie. we missed the LR restore).
Fix it by doing the patching under stop machine. The CPUs that aren't doing the patching will be spinning in the core of the stop machine logic. That is currently sufficient for our purposes, because none of the patching we do is to that code or anywhere in the vicinity.
--- arch/powerpc/lib/feature-fixups.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
arch/powerpc/lib/feature-fixups.c +15 -1
@@ -299,8 +299,9 @@ void do_uaccess_flush_fixups(enum l1d_fl : "unknown"); } -void do_entry_flush_fixups (enum l1d_flush_type types) +static int __do_entry_flush_fixups (void *data) { +enum l1d_flush_type types = *(enum l1d_flush_type *)data;unsigned int instrs[3 ], *dest;long *start, *end;int i;
@@ -369,6 +370,19 @@ void do_entry_flush_fixups(enum l1d_flus : "ori type" : (types &L1D_FLUSH_MTTRIG ) ?"mttrig type" : "unknown"); + +return 0 ; +} + +void do_entry_flush_fixups (enum l1d_flush_type types) +{ +/* +* The call to the fallback flush can not be safely patched in/out while +* other CPUs are executing it. So call __do_entry_flush_fixups() on one +* CPU while all other CPUs spin in the stop machine core with interrupts +* hard disabled. +*/ +stop_machine (__do_entry_flush_fixups, &types,NULL ); }void do_rfi_flush_fixups (enum l1d_flush_type types)
Greg Kroah-Hartman
maintainerPATCH 235/329 hfsplus: prevent corruption in shrinking truncate
In reply to Greg Kroah-HartmanFrom: Jouni Roivas <[email protected]>
commit c3187cf32216313fb316084efac4dab3a8459b1d upstream.
I believe there are some issues introduced by commit 31651c607151 ("hfsplus: avoid deadlock on file truncation")
HFS+ has extent records which always contains 8 extents. In case the first extent record in catalog file gets full, new ones are allocated from extents overflow file.
In case shrinking truncate happens to middle of an extent record which locates in extents overflow file, the logic in hfsplus_file_truncate() was changed so that call to hfs_brec_remove() is not guarded any more.
Right action would be just freeing the extents that exceed the new size inside extent record by calling hfsplus_free_extents(), and then check if the whole extent record should be removed. However since the guard (blk_cnt > start) is now after the call to hfs_brec_remove(), this has unfortunate effect that the last matching extent record is removed unconditionally.
To reproduce this issue, create a file which has at least 10 extents, and then perform shrinking truncate into middle of the last extent record, so that the number of remaining extents is not under or divisible by 8. This causes the last extent record (8 extents) to be removed totally instead of truncating into middle of it. Thus this causes corruption, and lost data.
Fix for this is simply checking if the new truncated end is below the start of this extent record, making it safe to remove the full extent record. However call to hfs_brec_remove() can't be moved to it's previous place since we're dropping ->tree_lock and it can cause a race condition and the cached info being invalidated possibly corrupting the node data.
Another issue is related to this one. When entering into the block (blk_cnt > start) we are not holding the ->tree_lock. We break out from the loop not holding the lock, but hfs_find_exit() does unlock it. Not sure if it's possible for someone else to take the lock under our feet, but it can cause hard to debug errors and premature unlocking. Even if there's no real risk of it, the locking should still always be kept in balance. Thus taking the lock now just before the check.
--- fs/hfsplus/extents.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
fs/hfsplus/extents.c +4 -3
@@ -598,13 +598,15 @@ void hfsplus_file_truncate(struct inode res =__hfsplus_ext_cache_extent (&fd, inode, alloc_cnt);if (res)break ; -hfs_brec_remove (&fd); -mutex_unlock (&fd.tree->tree_lock); start = hip->cached_start; +if (blk_cnt <= start) +hfs_brec_remove (&fd); +mutex_unlock (&fd.tree->tree_lock);hfsplus_free_extents (sb, hip->cached_extents, alloc_cnt - start, alloc_cnt - blk_cnt);hfsplus_dump_extent (hip->cached_extents); +mutex_lock (&fd.tree->tree_lock);if (blk_cnt > start) { hip->extent_state |=HFSPLUS_EXT_DIRTY ;break ;
@@ -612,7 +614,6 @@ void hfsplus_file_truncate(struct inode alloc_cnt = start; hip->cached_start = hip->cached_blocks =0 ; hip->extent_state &= ~(HFSPLUS_EXT_DIRTY |HFSPLUS_EXT_NEW ); -mutex_lock (&fd.tree->tree_lock); }hfs_find_exit (&fd);
Greg Kroah-Hartman
maintainerPATCH 236/329 squashfs: fix divide error in calculate_skip()
In reply to Greg Kroah-HartmanFrom: Phillip Lougher <[email protected]>
commit d6e621de1fceb3b098ebf435ef7ea91ec4838a1a upstream.
Sysbot has reported a "divide error" which has been identified as being caused by a corrupted file_size value within the file inode. This value has been corrupted to a much larger value than expected.
Calculate_skip() is passed i_size_read(inode) >> msblk->block_log. Due to the file_size value corruption this overflows the int argument/variable in that function, leading to the divide error.
This patch changes the function to use u64. This will accommodate any unexpectedly large values due to corruption.
The value returned from calculate_skip() is clamped to be never more than SQUASHFS_CACHED_BLKS - 1, or 7. So file_size corruption does not lead to an unexpectedly large return result here.
--- fs/squashfs/file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/squashfs/file.c +3 -3
@@ -211,11 +211,11 @@ failure:* If the skip factor is limited in this way then the file will use multiple * slots. */ -static inline int calculate_skip (int blocks) +static inline int calculate_skip (u64 blocks) { -int skip = blocks / ((SQUASHFS_META_ENTRIES +1 ) +u64 skip = blocks / ((SQUASHFS_META_ENTRIES +1 ) *SQUASHFS_META_INDEXES ); -return min (SQUASHFS_CACHED_BLKS -1 , skip +1 ); +return min ((u64 )SQUASHFS_CACHED_BLKS -1 , skip +1 ); }
Greg Kroah-Hartman
maintainerPATCH 237/329 userfaultfd: release page in error path to avoid BUG_ON
In reply to Greg Kroah-HartmanFrom: Axel Rasmussen <[email protected]>
commit 7ed9d238c7dbb1fdb63ad96a6184985151b0171c upstream.
Consider the following sequence of events:
1. Userspace issues a UFFD ioctl, which ends up calling into shmem_mfill_atomic_pte(). We successfully account the blocks, we shmem_alloc_page(), but then the copy_from_user() fails. We return -ENOENT. We don't release the page we allocated.
2. Our caller detects this error code, tries the copy_from_user() after dropping the mmap_lock, and retries, calling back into shmem_mfill_atomic_pte().
3. Meanwhile, let's say another process filled up the tmpfs being used.
4. So shmem_mfill_atomic_pte() fails to account blocks this time, and immediately returns - without releasing the page.
This triggers a BUG_ON in our caller, which asserts that the page should always be consumed, unless -ENOENT is returned.
To fix this, detect if we have such a "dangling" page when accounting fails, and if so, release it before returning.
--- mm/shmem.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
mm/shmem.c +11 -1
@@ -2373,8 +2373,18 @@ static int shmem_mfill_atomic_pte(structpgoff_t offset, max_off; ret = -ENOMEM ; -if (!shmem_inode_acct_block (inode,1 )) +if (!shmem_inode_acct_block (inode,1 )) { +/* +* We may have got a page, returned -ENOENT triggering a retry, +* and now we find ourselves with -ENOMEM. Release the page, to +* avoid a BUG_ON in our caller. +*/ +if (unlikely (*pagep)) { +put_page (*pagep); + *pagep =NULL ; + } goto out; + }if (!*pagep) { page =shmem_alloc_page (gfp, info, pgoff);
Greg Kroah-Hartman
maintainerPATCH 238/329 kasan: fix unit tests with CONFIG_UBSAN_LOCAL_BOUNDS enabled
In reply to Greg Kroah-HartmanFrom: Peter Collingbourne <[email protected]>
commit f649dc0e0d7b509c75570ee403723660f5b72ec7 upstream.
These tests deliberately access these arrays out of bounds, which will cause the dynamic local bounds checks inserted by CONFIG_UBSAN_LOCAL_BOUNDS to fail and panic the kernel. To avoid this problem, access the arrays via volatile pointers, which will prevent the compiler from being able to determine the array bounds.
These accesses use volatile pointers to char (char *volatile) rather than the more conventional pointers to volatile char (volatile char *) because we want to prevent the compiler from making inferences about the pointer itself (i.e. its array bounds), not the data that it refers to.
--- lib/test_kasan.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
lib/test_kasan.c +23 -6
@@ -449,8 +449,20 @@ static char global_array[10];static void kasan_global_oob (struct kunit *test) { -volatile int i =3 ; -char *p = &global_array[ARRAY_SIZE (global_array) + i]; +/* +* Deliberate out-of-bounds access. To prevent CONFIG_UBSAN_LOCAL_BOUNDS +* from failing here and panicing the kernel, access the array via a +* volatile pointer, which will prevent the compiler from being able to +* determine the array bounds. +* +* This access uses a volatile pointer to char (char *volatile) rather +* than the more conventional pointer to volatile char (volatile char *) +* because we want to prevent the compiler from making inferences about +* the pointer itself (i.e. its array bounds), not the data that it +* refers to. +*/ +char *volatile array = global_array; +char *p = &array[ARRAY_SIZE (global_array) +3 ];/* Only generic mode instruments globals. */ if (!IS_ENABLED (CONFIG_KASAN_GENERIC )) {
@@ -479,8 +491,9 @@ static void ksize_unpoisons_memory(strucstatic void kasan_stack_oob (struct kunit *test) {char stack_array[10 ]; -volatile int i =OOB_TAG_OFF ; -char *p = &stack_array[ARRAY_SIZE (stack_array) + i]; +/* See comment in kasan_global_oob. */ +char *volatile array = stack_array; +char *p = &array[ARRAY_SIZE (stack_array) +OOB_TAG_OFF ];if (!IS_ENABLED (CONFIG_KASAN_STACK )) {kunit_info (test,"CONFIG_KASAN_STACK is not enabled" );
@@ -494,7 +507,9 @@ static void kasan_alloca_oob_left(struct {volatile int i =10 ;char alloca_array[i]; -char *p = alloca_array -1 ; +/* See comment in kasan_global_oob. */ +char *volatile array = alloca_array; +char *p = array -1 ;/* Only generic mode instruments dynamic allocas. */ if (!IS_ENABLED (CONFIG_KASAN_GENERIC )) {
@@ -514,7 +529,9 @@ static void kasan_alloca_oob_right(struc {volatile int i =10 ;char alloca_array[i]; -char *p = alloca_array + i; +/* See comment in kasan_global_oob. */ +char *volatile array = alloca_array; +char *p = array + i;/* Only generic mode instruments dynamic allocas. */ if (!IS_ENABLED (CONFIG_KASAN_GENERIC )) {
Greg Kroah-Hartman
maintainerPATCH 239/329 mm/hugetlb: fix F_SEAL_FUTURE_WRITE
In reply to Greg Kroah-HartmanFrom: Peter Xu <[email protected]>
commit 22247efd822e6d263f3c8bd327f3f769aea9b1d9 upstream.
Patch series "mm/hugetlb: Fix issues on file sealing and fork", v2.
Hugh reported issue with F_SEAL_FUTURE_WRITE not applied correctly to hugetlbfs, which I can easily verify using the memfd_test program, which seems that the program is hardly run with hugetlbfs pages (as by default shmem).
Meanwhile I found another probably even more severe issue on that hugetlb fork won't wr-protect child cow pages, so child can potentially write to parent private pages. Patch 2 addresses that.
After this series applied, "memfd_test hugetlbfs" should start to pass.
This patch (of 2):
F_SEAL_FUTURE_WRITE is missing for hugetlb starting from the first day. There is a test program for that and it fails constantly.
$ ./memfd_test hugetlbfs memfd-hugetlb: CREATE memfd-hugetlb: BASIC memfd-hugetlb: SEAL-WRITE memfd-hugetlb: SEAL-FUTURE-WRITE mmap() didn't fail as expected Aborted (core dumped)
I think it's probably because no one is really running the hugetlbfs test.
Fix it by checking FUTURE_WRITE also in hugetlbfs_file_mmap() as what we do in shmem_mmap(). Generalize a helper for that.
--- fs/hugetlbfs/inode.c | 5 +++++ include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++ mm/shmem.c | 22 ++++------------------ 3 files changed, 41 insertions(+), 18 deletions(-)
fs/hugetlbfs/inode.c +5 -0
@@ -131,6 +131,7 @@ static void huge_pagevec_release(structstatic int hugetlbfs_file_mmap (struct file *file,struct vm_area_struct *vma) {struct inode *inode =file_inode (file); +struct hugetlbfs_inode_info *info =HUGETLBFS_I (inode);loff_t len, vma_len;int ret;struct hstate *h =hstate_file (file);
@@ -146,6 +147,10 @@ static int hugetlbfs_file_mmap(struct fi vma->vm_flags |=VM_HUGETLB |VM_DONTEXPAND ; vma->vm_ops = &hugetlb_vm_ops; + ret =seal_check_future_write (info->seals, vma); +if (ret) +return ret; +/* * page based offset in vm_pgoff could be sufficiently large to * overflow a loff_t when converted to byte offset. This can
include/linux/mm.h +32 -0
@@ -3191,5 +3191,37 @@ unsigned long wp_shared_mapping_range(stextern int sysctl_nr_trim_pages; +/** +* seal_check_future_write - Check for F_SEAL_FUTURE_WRITE flag and handle it +* @seals: the seals to check +* @vma: the vma to operate on +* +* Check whether F_SEAL_FUTURE_WRITE is set; if so, do proper check/handling on +* the vma flags. Return 0 if check pass, or <0 for errors. +*/ +static inline int seal_check_future_write (int seals,struct vm_area_struct *vma) +{ +if (seals &F_SEAL_FUTURE_WRITE ) { +/* +* New PROT_WRITE and MAP_SHARED mmaps are not allowed when +* "future write" seal active. +*/ +if ((vma->vm_flags &VM_SHARED ) && (vma->vm_flags &VM_WRITE )) +return -EPERM ; + +/* +* Since an F_SEAL_FUTURE_WRITE sealed memfd can be mapped as +* MAP_SHARED and read-only, take care to not allow mprotect to +* revert protections on such mappings. Do this only for shared +* mappings. For private mappings, don't need to mask +* VM_MAYWRITE as we still want them to be COW-writable. +*/ +if (vma->vm_flags &VM_SHARED ) + vma->vm_flags &= ~(VM_MAYWRITE ); + } + +return 0 ; +} +#endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */
mm/shmem.c +4 -18
@@ -2256,25 +2256,11 @@ out_nomem:static int shmem_mmap (struct file *file,struct vm_area_struct *vma) {struct shmem_inode_info *info =SHMEM_I (file_inode (file)); +int ret; -if (info->seals &F_SEAL_FUTURE_WRITE ) { -/* -* New PROT_WRITE and MAP_SHARED mmaps are not allowed when -* "future write" seal active. -*/ -if ((vma->vm_flags &VM_SHARED ) && (vma->vm_flags &VM_WRITE )) -return -EPERM ; - -/* -* Since an F_SEAL_FUTURE_WRITE sealed memfd can be mapped as -* MAP_SHARED and read-only, take care to not allow mprotect to -* revert protections on such mappings. Do this only for shared -* mappings. For private mappings, don't need to mask -* VM_MAYWRITE as we still want them to be COW-writable. -*/ -if (vma->vm_flags &VM_SHARED ) - vma->vm_flags &= ~(VM_MAYWRITE ); - } + ret =seal_check_future_write (info->seals, vma); +if (ret) +return ret;/* arm64 - allow memory tagging on RAM-based files */ vma->vm_flags |=VM_MTE_ALLOWED ;
Greg Kroah-Hartman
maintainerPATCH 240/329 blk-iocost: fix weight updates of inner active iocgs
In reply to Greg Kroah-HartmanFrom: Tejun Heo <[email protected]>
commit e9f4eee9a0023ba22db9560d4cc6ee63f933dae8 upstream.
When the weight of an active iocg is updated, weight_updated() is called which in turn calls __propagate_weights() to update the active and inuse weights so that the effective hierarchical weights are update accordingly.
The current implementation is incorrect for inner active nodes. For an active leaf iocg, inuse can be any value between 1 and active and the difference represents how much the iocg is donating. When weight is updated, as long as inuse is clamped between 1 and the new weight, we're alright and this is what __propagate_weights() currently implements.
However, that's not how an active inner node's inuse is set. An inner node's inuse is solely determined by the ratio between the sums of inuse's and active's of its children - ie. they're results of propagating the leaves' active and inuse weights upwards. __propagate_weights() incorrectly applies the same clamping as for a leaf when an active inner node's weight is updated. Consider a hierarchy which looks like the following with saturating workloads in AA and BB.
R
/ \
A B | | AA BB
1. For both A and B, active=100, inuse=100, hwa=0.5, hwi=0.5.
2. echo 200 > A/io.weight
3. __propagate_weights() update A's active to 200 and leave inuse at 100 as it's already between 1 and the new active, making A:active=200, A:inuse=100. As R's active_sum is updated along with A's active, A:hwa=2/3, B:hwa=1/3. However, because the inuses didn't change, the hwi's remain unchanged at 0.5.
4. The weight of A is now twice that of B but AA and BB still have the same hwi of 0.5 and thus are doing the same amount of IOs.
Fix it by making __propgate_weights() always calculate the inuse of an active inner iocg based on the ratio of child_inuse_sum to child_active_sum.
--- block/blk-iocost.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
block/blk-iocost.c +12 -2
@@ -1073,7 +1073,17 @@ static void __propagate_weights(struct ilockdep_assert_held (&ioc->lock); - inuse =clamp_t (u32, inuse,1 , active); +/* +* For an active leaf node, its inuse shouldn't be zero or exceed +* @active. An active internal node's inuse is solely determined by the +* inuse to active ratio of its children regardless of @inuse. +*/ +if (list_empty (&iocg->active_list) && iocg->child_active_sum) { + inuse =DIV64_U64_ROUND_UP (active * iocg->child_inuse_sum, + iocg->child_active_sum); + }else { + inuse =clamp_t (u32, inuse,1 , active); + } iocg->last_inuse = iocg->inuse;if (save)
@@ -1090,7 +1100,7 @@ static void __propagate_weights(struct i/* update the level sums */ parent->child_active_sum += (s32)(active - child->active); parent->child_inuse_sum += (s32)(inuse - child->inuse); -/* apply the udpates */ +/* apply the updates */ child->active = active; child->inuse = inuse;
Greg Kroah-Hartman
maintainerPATCH 241/329 x86, sched: Fix the AMD CPPC maximum performance value on certain AMD Ryzen generations
In reply to Greg Kroah-HartmanFrom: Huang Rui <[email protected]>
commit 3743d55b289c203d8f77b7cd47c24926b9d186ae upstream.
Some AMD Ryzen generations has different calculation method on maximum performance. 255 is not for all ASICs, some specific generations should use 166 as the maximum performance. Otherwise, it will report incorrect frequency value like below:
~ → lscpu | grep MHz
CPU MHz: 3400.000 CPU max MHz: 7228.3198 CPU min MHz: 2200.0000
[ mingo: Tidied up whitespace use. ]
[ Alexander Monakov <[email protected]>: fix 225 -> 255 typo. ]
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=211791
--- arch/x86/include/asm/processor.h | 2 ++ arch/x86/kernel/cpu/amd.c | 16 ++++++++++++++++ arch/x86/kernel/smpboot.c | 2 +- drivers/cpufreq/acpi-cpufreq.c | 6 +++++- 4 files changed, 24 insertions(+), 2 deletions(-)
arch/x86/include/asm/processor.h +2 -0
@@ -805,8 +805,10 @@ DECLARE_PER_CPU(u64, msr_misc_features_s#ifdef CONFIG_CPU_SUP_AMD extern u32 amd_get_nodes_per_socket (void ); +extern u32 amd_get_highest_perf (void );#else static inline u32 amd_get_nodes_per_socket (void ) {return 0 ; } +static inline u32 amd_get_highest_perf (void ) {return 0 ; }#endif static inline uint32_t hypervisor_cpuid_base (const char *sig,uint32_t leaves)
arch/x86/kernel/cpu/amd.c +16 -0
@@ -1170,3 +1170,19 @@ void set_dr_addr_mask(unsigned long maskbreak ; } } + +u32 amd_get_highest_perf (void ) +{ +struct cpuinfo_x86 *c = &boot_cpu_data; + +if (c->x86 ==0x17 && ((c->x86_model >=0x30 && c->x86_model <0x40 ) || + (c->x86_model >=0x70 && c->x86_model <0x80 ))) +return 166 ; + +if (c->x86 ==0x19 && ((c->x86_model >=0x20 && c->x86_model <0x30 ) || + (c->x86_model >=0x40 && c->x86_model <0x70 ))) +return 166 ; + +return 255 ; +} +EXPORT_SYMBOL_GPL (amd_get_highest_perf);
arch/x86/kernel/smpboot.c +1 -1
@@ -2046,7 +2046,7 @@ static bool amd_set_max_freq_ratio(void)return false; } - highest_perf = perf_caps.highest_perf; + highest_perf =amd_get_highest_perf (); nominal_perf = perf_caps.nominal_perf;if (!highest_perf || !nominal_perf) {
drivers/cpufreq/acpi-cpufreq.c +5 -1
@@ -646,7 +646,11 @@ static u64 get_max_boost_ratio(unsignedreturn 0 ; } - highest_perf = perf_caps.highest_perf; +if (boot_cpu_data.x86_vendor ==X86_VENDOR_AMD ) + highest_perf =amd_get_highest_perf (); +else + highest_perf = perf_caps.highest_perf; + nominal_perf = perf_caps.nominal_perf;if (!highest_perf || !nominal_perf) {
Greg Kroah-Hartman
maintainerPATCH 242/329 arm64: mte: initialize RGSR_EL1.SEED in __cpu_setup
In reply to Greg Kroah-HartmanFrom: Peter Collingbourne <[email protected]>
commit 37a8024d265564eba680575df6421f19db21dfce upstream.
A valid implementation choice for the ChooseRandomNonExcludedTag() pseudocode function used by IRG is to behave in the same way as with GCR_EL1.RRND=0. This would mean that RGSR_EL1.SEED is used as an LFSR which must have a non-zero value in order for IRG to properly produce pseudorandom numbers. However, RGSR_EL1 is reset to an UNKNOWN value on soft reset and thus may reset to 0. Therefore we must initialize RGSR_EL1.SEED to a non-zero value in order to ensure that IRG behaves as expected.
--- arch/arm64/mm/proc.S | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/arm64/mm/proc.S +12 -0
@@ -454,6 +454,18 @@ SYM_FUNC_START(__cpu_setup) mov x10, #(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK) msr_s SYS_GCR_EL1, x10 + /* + * If GCR_EL1.RRND=1 is implemented the same way as RRND=0, then + * RGSR_EL1.SEED must be non-zero for IRG to produce + * pseudorandom numbers. As RGSR_EL1 is UNKNOWN out of reset, we + * must initialize it. + */ + mrs x10, CNTVCT_EL0 + ands x10, x10, #SYS_RGSR_EL1_SEED_MASK + csinc x10, x10, xzr, ne + lsl x10, x10, #SYS_RGSR_EL1_SEED_SHIFT + msr_s SYS_RGSR_EL1, x10 + /* clear any pending tag check faults in TFSR*_EL1 */ msr_s SYS_TFSR_EL1, xzr msr_s SYS_TFSRE0_EL1, xzr
Greg Kroah-Hartman
maintainerPATCH 243/329 arm64: Fix race condition on PG_dcache_clean in __sync_icache_dcache()
In reply to Greg Kroah-HartmanFrom: Catalin Marinas <[email protected]>
commit 588a513d34257fdde95a9f0df0202e31998e85c6 upstream.
To ensure that instructions are observable in a new mapping, the arm64 set_pte_at() implementation cleans the D-cache and invalidates the I-cache to the PoU. As an optimisation, this is only done on executable mappings and the PG_dcache_clean page flag is set to avoid future cache maintenance on the same page.
When two different processes map the same page (e.g. private executable file or shared mapping) there's a potential race on checking and setting PG_dcache_clean via set_pte_at() -> __sync_icache_dcache(). While on the fault paths the page is locked (PG_locked), mprotect() does not take the page lock. The result is that one process may see the PG_dcache_clean flag set but the I/D cache maintenance not yet performed.
Avoid test_and_set_bit(PG_dcache_clean) in favour of separate test_bit() and set_bit(). In the rare event of a race, the cache maintenance is done twice.
--- arch/arm64/mm/flush.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm64/mm/flush.c +3 -1
@@ -55,8 +55,10 @@ void __sync_icache_dcache(pte_t pte) {struct page *page =pte_page (pte); -if (!test_and_set_bit (PG_dcache_clean, &page->flags)) +if (!test_bit (PG_dcache_clean, &page->flags)) {sync_icache_aliases (page_address (page),page_size (page)); +set_bit (PG_dcache_clean, &page->flags); + } }EXPORT_SYMBOL_GPL (__sync_icache_dcache);
Greg Kroah-Hartman
maintainerPATCH 244/329 btrfs: fix deadlock when cloning inline extents and using qgroups
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit f9baa501b4fd6962257853d46ddffbc21f27e344 upstream.
There are a few exceptional cases where cloning an inline extent needs to copy the inline extent data into a page of the destination inode.
When this happens, we end up starting a transaction while having a dirty page for the destination inode and while having the range locked in the destination's inode iotree too. Because when reserving metadata space for a transaction we may need to flush existing delalloc in case there is not enough free space, we have a mechanism in place to prevent a deadlock, which was introduced in commit 3d45f221ce627d ("btrfs: fix deadlock when cloning inline extent and low on free metadata space").
However when using qgroups, a transaction also reserves metadata qgroup space, which can also result in flushing delalloc in case there is not enough available space at the moment. When this happens we deadlock, since flushing delalloc requires locking the file range in the inode's iotree and the range was already locked at the very beginning of the clone operation, before attempting to start the transaction.
When this issue happens, stack traces like the following are reported:
[72747.556262] task:kworker/u81:9 state:D stack: 0 pid: 225 ppid: 2 flags:0x00004000 [72747.556268] Workqueue: writeback wb_workfn (flush-btrfs-1142) [72747.556271] Call Trace: [72747.556273] __schedule+0x296/0x760 [72747.556277] schedule+0x3c/0xa0 [72747.556279] io_schedule+0x12/0x40 [72747.556284] __lock_page+0x13c/0x280 [72747.556287] ? generic_file_readonly_mmap+0x70/0x70 [72747.556325] extent_write_cache_pages+0x22a/0x440 [btrfs] [72747.556331] ? __set_page_dirty_nobuffers+0xe7/0x160 [72747.556358] ? set_extent_buffer_dirty+0x5e/0x80 [btrfs] [72747.556362] ? update_group_capacity+0x25/0x210 [72747.556366] ? cpumask_next_and+0x1a/0x20 [72747.556391] extent_writepages+0x44/0xa0 [btrfs] [72747.556394] do_writepages+0x41/0xd0 [72747.556398] __writeback_single_inode+0x39/0x2a0 [72747.556403] writeback_sb_inodes+0x1ea/0x440 [72747.556407] __writeback_inodes_wb+0x5f/0xc0 [72747.556410] wb_writeback+0x235/0x2b0 [72747.556414] ? get_nr_inodes+0x35/0x50 [72747.556417] wb_workfn+0x354/0x490 [72747.556420] ? newidle_balance+0x2c5/0x3e0 [72747.556424] process_one_work+0x1aa/0x340 [72747.556426] worker_thread+0x30/0x390 [72747.556429] ? create_worker+0x1a0/0x1a0 [72747.556432] kthread+0x116/0x130 [72747.556435] ? kthread_park+0x80/0x80 [72747.556438] ret_from_fork+0x1f/0x30
[72747.566958] Workqueue: btrfs-flush_delalloc btrfs_work_helper [btrfs] [72747.566961] Call Trace: [72747.566964] __schedule+0x296/0x760 [72747.566968] ? finish_wait+0x80/0x80 [72747.566970] schedule+0x3c/0xa0 [72747.566995] wait_extent_bit.constprop.68+0x13b/0x1c0 [btrfs] [72747.566999] ? finish_wait+0x80/0x80 [72747.567024] lock_extent_bits+0x37/0x90 [btrfs] [72747.567047] btrfs_invalidatepage+0x299/0x2c0 [btrfs] [72747.567051] ? find_get_pages_range_tag+0x2cd/0x380 [72747.567076] __extent_writepage+0x203/0x320 [btrfs] [72747.567102] extent_write_cache_pages+0x2bb/0x440 [btrfs] [72747.567106] ? update_load_avg+0x7e/0x5f0 [72747.567109] ? enqueue_entity+0xf4/0x6f0 [72747.567134] extent_writepages+0x44/0xa0 [btrfs] [72747.567137] ? enqueue_task_fair+0x93/0x6f0 [72747.567140] do_writepages+0x41/0xd0 [72747.567144] __filemap_fdatawrite_range+0xc7/0x100 [72747.567167] btrfs_run_delalloc_work+0x17/0x40 [btrfs] [72747.567195] btrfs_work_helper+0xc2/0x300 [btrfs] [72747.567200] process_one_work+0x1aa/0x340 [72747.567202] worker_thread+0x30/0x390 [72747.567205] ? create_worker+0x1a0/0x1a0 [72747.567208] kthread+0x116/0x130 [72747.567211] ? kthread_park+0x80/0x80 [72747.567214] ret_from_fork+0x1f/0x30
[72747.569686] task:fsstress state:D stack: 0 pid:841421 ppid:841417 flags:0x00000000 [72747.569689] Call Trace: [72747.569691] __schedule+0x296/0x760 [72747.569694] schedule+0x3c/0xa0 [72747.569721] try_flush_qgroup+0x95/0x140 [btrfs] [72747.569725] ? finish_wait+0x80/0x80 [72747.569753] btrfs_qgroup_reserve_data+0x34/0x50 [btrfs] [72747.569781] btrfs_check_data_free_space+0x5f/0xa0 [btrfs] [72747.569804] btrfs_buffered_write+0x1f7/0x7f0 [btrfs] [72747.569810] ? path_lookupat.isra.48+0x97/0x140 [72747.569833] btrfs_file_write_iter+0x81/0x410 [btrfs] [72747.569836] ? __kmalloc+0x16a/0x2c0 [72747.569839] do_iter_readv_writev+0x160/0x1c0 [72747.569843] do_iter_write+0x80/0x1b0 [72747.569847] vfs_writev+0x84/0x140 [72747.569869] ? btrfs_file_llseek+0x38/0x270 [btrfs] [72747.569873] do_writev+0x65/0x100 [72747.569876] do_syscall_64+0x33/0x40 [72747.569879] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[72747.569899] task:fsstress state:D stack: 0 pid:841424 ppid:841417 flags:0x00004000 [72747.569903] Call Trace: [72747.569906] __schedule+0x296/0x760 [72747.569909] schedule+0x3c/0xa0 [72747.569936] try_flush_qgroup+0x95/0x140 [btrfs] [72747.569940] ? finish_wait+0x80/0x80 [72747.569967] __btrfs_qgroup_reserve_meta+0x36/0x50 [btrfs] [72747.569989] start_transaction+0x279/0x580 [btrfs] [72747.570014] clone_copy_inline_extent+0x332/0x490 [btrfs] [72747.570041] btrfs_clone+0x5b7/0x7a0 [btrfs] [72747.570068] ? lock_extent_bits+0x64/0x90 [btrfs] [72747.570095] btrfs_clone_files+0xfc/0x150 [btrfs] [72747.570122] btrfs_remap_file_range+0x3d8/0x4a0 [btrfs] [72747.570126] do_clone_file_range+0xed/0x200 [72747.570131] vfs_clone_file_range+0x37/0x110 [72747.570134] ioctl_file_clone+0x7d/0xb0 [72747.570137] do_vfs_ioctl+0x138/0x630 [72747.570140] __x64_sys_ioctl+0x62/0xc0 [72747.570143] do_syscall_64+0x33/0x40 [72747.570146] entry_SYSCALL_64_after_hwframe+0x44/0xa9
So fix this by skipping the flush of delalloc for an inode that is flagged with BTRFS_INODE_NO_DELALLOC_FLUSH, meaning it is currently under such a special case of cloning an inline extent, when flushing delalloc during qgroup metadata reservation.
The special cases for cloning inline extents were added in kernel 5.7 by by commit 05a5a7621ce66c ("Btrfs: implement full reflink support for inline extents"), while having qgroup metadata space reservation flushing delalloc when low on space was added in kernel 5.9 by commit c53e9653605dbf ("btrfs: qgroup: try to flush qgroup space when we get -EDQUOT"). So use a "Fixes:" tag for the later commit to ease stable kernel backports.
--- fs/btrfs/ctree.h | 2 +- fs/btrfs/inode.c | 4 ++-- fs/btrfs/ioctl.c | 2 +- fs/btrfs/qgroup.c | 2 +- fs/btrfs/send.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-)
fs/btrfs/ctree.h +1 -1
@@ -3104,7 +3104,7 @@ int btrfs_truncate_inode_items(struct bt struct btrfs_inode *inode, u64 new_size, u32 min_type); -int btrfs_start_delalloc_snapshot (struct btrfs_root *root); +int btrfs_start_delalloc_snapshot (struct btrfs_root *root,bool in_reclaim_context);int btrfs_start_delalloc_roots (struct btrfs_fs_info *fs_info,u64 nr,bool in_reclaim_context); int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
fs/btrfs/inode.c +2 -2
@@ -9475,7 +9475,7 @@ out:return ret; } -int btrfs_start_delalloc_snapshot (struct btrfs_root *root) +int btrfs_start_delalloc_snapshot (struct btrfs_root *root,bool in_reclaim_context) {struct writeback_control wbc = { .nr_to_write =LONG_MAX ,
@@ -9488,7 +9488,7 @@ int btrfs_start_delalloc_snapshot(structif (test_bit (BTRFS_FS_STATE_ERROR , &fs_info->fs_state))return -EROFS ; -return start_delalloc_inodes (root, &wbc, true, false); +return start_delalloc_inodes (root, &wbc, true, in_reclaim_context); } int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
fs/btrfs/ioctl.c +1 -1
@@ -1042,7 +1042,7 @@ static noinline int btrfs_mksnapshot(con*/ btrfs_drew_read_lock (&root->snapshot_lock); - ret =btrfs_start_delalloc_snapshot (root); + ret =btrfs_start_delalloc_snapshot (root, false);if (ret) goto out;
fs/btrfs/qgroup.c +1 -1
@@ -3579,7 +3579,7 @@ static int try_flush_qgroup(struct btrfsreturn 0 ; } - ret =btrfs_start_delalloc_snapshot (root); + ret =btrfs_start_delalloc_snapshot (root, true);if (ret <0 ) goto out;btrfs_wait_ordered_extents (root,U64_MAX ,0 , (u64)-1 );
fs/btrfs/send.c +2 -2
@@ -7159,7 +7159,7 @@ static int flush_delalloc_roots(struct sint i;if (root) { - ret =btrfs_start_delalloc_snapshot (root); + ret =btrfs_start_delalloc_snapshot (root, false);if (ret)return ret;btrfs_wait_ordered_extents (root,U64_MAX ,0 ,U64_MAX );
@@ -7167,7 +7167,7 @@ static int flush_delalloc_roots(struct sfor (i =0 ; i < sctx->clone_roots_cnt; i++) { root = sctx->clone_roots[i].root; - ret =btrfs_start_delalloc_snapshot (root); + ret =btrfs_start_delalloc_snapshot (root, false);if (ret)return ret;btrfs_wait_ordered_extents (root,U64_MAX ,0 ,U64_MAX );
Greg Kroah-Hartman
maintainerPATCH 245/329 btrfs: fix race leading to unpersisted data and metadata on fsync
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit 626e9f41f7c281ba3e02843702f68471706aa6d9 upstream.
When doing a fast fsync on a file, there is a race which can result in the fsync returning success to user space without logging the inode and without durably persisting new data.
The following example shows one possible scenario for this:
$ mkfs.btrfs -f /dev/sdc $ mount /dev/sdc /mnt
$ touch /mnt/bar $ xfs_io -f -c "pwrite -S 0xab 0 1M" -c "fsync" /mnt/baz
# Now we have:
# file bar == inode 257 # file baz == inode 258
$ mv /mnt/baz /mnt/foo
# Now we have:
# file bar == inode 257 # file foo == inode 258
$ xfs_io -c "pwrite -S 0xcd 0 1M" /mnt/foo
# fsync bar before foo, it is important to trigger the race. $ xfs_io -c "fsync" /mnt/bar $ xfs_io -c "fsync" /mnt/foo
# After this:
# inode 257, file bar, is empty # inode 258, file foo, has 1M filled with 0xcd
<power failure>
# Replay the log:
$ mount /dev/sdc /mnt
# After this point file foo should have 1M filled with 0xcd and not 0xab
The following steps explain how the race happens:
1) Before the first fsync of inode 258, when it has the "baz" name, its ->logged_trans is 0, ->last_sub_trans is 0 and ->last_log_commit is -1. The inode also has the full sync flag set;
2) After the first fsync, we set inode 258 ->logged_trans to 6, which is the generation of the current transaction, and set ->last_log_commit to 0, which is the current value of ->last_sub_trans (done at btrfs_log_inode()).
The full sync flag is cleared from the inode during the fsync.
The log sub transaction that was committed had an ID of 0 and when we synced the log, at btrfs_sync_log(), we incremented root->log_transid from 0 to 1;
3) During the rename:
We update inode 258, through btrfs_update_inode(), and that causes its ->last_sub_trans to be set to 1 (the current log transaction ID), and ->last_log_commit remains with a value of 0.
After updating inode 258, because we have previously logged the inode in the previous fsync, we log again the inode through the call to btrfs_log_new_name(). This results in updating the inode's ->last_log_commit from 0 to 1 (the current value of its ->last_sub_trans).
The ->last_sub_trans of inode 257 is updated to 1, which is the ID of the next log transaction;
4) Then a buffered write against inode 258 is made. This leaves the value of ->last_sub_trans as 1 (the ID of the current log transaction, stored at root->log_transid);
5) Then an fsync against inode 257 (or any other inode other than 258), happens. This results in committing the log transaction with ID 1, which results in updating root->last_log_commit to 1 and bumping root->log_transid from 1 to 2;
6) Then an fsync against inode 258 starts. We flush delalloc and wait only for writeback to complete, since the full sync flag is not set in the inode's runtime flags - we do not wait for ordered extents to complete.
Then, at btrfs_sync_file(), we call btrfs_inode_in_log() before the ordered extent completes. The call returns true:
static inline bool btrfs_inode_in_log(...)
{
bool ret = false;
spin_lock(&inode->lock);
if (inode->logged_trans == generation &&
inode->last_sub_trans <= inode->last_log_commit &&
inode->last_sub_trans <= inode->root->last_log_commit)
ret = true;
spin_unlock(&inode->lock);
return ret;
} generation has a value of 6 (fs_info->generation), ->logged_trans also has a value of 6 (set when we logged the inode during the first fsync and when logging it during the rename), ->last_sub_trans has a value of 1, set during the rename (step 3), ->last_log_commit also has a value of 1 (set in step 3) and root->last_log_commit has a value of 1, which was set in step 5 when fsyncing inode 257.
As a consequence we don't log the inode, any new extents and do not sync the log, resulting in a data loss if a power failure happens after the fsync and before the current transaction commits. Also, because we do not log the inode, after a power failure the mtime and ctime of the inode do not match those we had before.
When the ordered extent completes before we call btrfs_inode_in_log(), then the call returns false and we log the inode and sync the log, since at the end of ordered extent completion we update the inode and set ->last_sub_trans to 2 (the value of root->log_transid) and ->last_log_commit to 1.
This problem is found after removing the check for the emptiness of the inode's list of modified extents in the recent commit 209ecbb8585bf6 ("btrfs: remove stale comment and logic from btrfs_inode_in_log()"), added in the 5.13 merge window. However checking the emptiness of the list is not really the way to solve this problem, and was never intended to, because while that solves the problem for COW writes, the problem persists for NOCOW writes because in that case the list is always empty.
In the case of NOCOW writes, even though we wait for the writeback to complete before returning from btrfs_sync_file(), we end up not logging the inode, which has a new mtime/ctime, and because we don't sync the log, we never issue disk barriers (send REQ_PREFLUSH to the device) since that only happens when we sync the log (when we write super blocks at btrfs_sync_log()). So effectively, for a NOCOW case, when we return from btrfs_sync_file() to user space, we are not guaranteeing that the data is durably persisted on disk.
Also, while the example above uses a rename exchange to show how the problem happens, it is not the only way to trigger it. An alternative could be adding a new hard link to inode 258, since that also results in calling btrfs_log_new_name() and updating the inode in the log. An example reproducer using the addition of a hard link instead of a rename operation:
$ mkfs.btrfs -f /dev/sdc $ mount /dev/sdc /mnt
$ touch /mnt/bar $ xfs_io -f -c "pwrite -S 0xab 0 1M" -c "fsync" /mnt/foo
$ ln /mnt/foo /mnt/foo_link $ xfs_io -c "pwrite -S 0xcd 0 1M" /mnt/foo
$ xfs_io -c "fsync" /mnt/bar $ xfs_io -c "fsync" /mnt/foo
<power failure>
# Replay the log:
$ mount /dev/sdc /mnt
# After this point file foo often has 1M filled with 0xab and not 0xcd
The reasons leading to the final fsync of file foo, inode 258, not persisting the new data are the same as for the previous example with a rename operation.
So fix by never skipping logging and log syncing when there are still any ordered extents in flight. To avoid making the conditional if statement that checks if logging an inode is needed harder to read, place all the logic into an helper function with separate if statements to make it more manageable and easier to read.
A test case for fstests will follow soon.
For NOCOW writes, the problem existed before commit b5e6c3e170b770 ("btrfs: always wait on ordered extents at fsync time"), introduced in kernel 4.19, then it went away with that commit since we started to always wait for ordered extent completion before logging.
The problem came back again once the fast fsync path was changed again to avoid waiting for ordered extent completion, in commit 487781796d3022 ("btrfs: make fast fsyncs wait only for writeback"), added in kernel 5.10.
However, for COW writes, the race only happens after the recent commit 209ecbb8585bf6 ("btrfs: remove stale comment and logic from btrfs_inode_in_log()"), introduced in the 5.13 merge window. For NOCOW writes, the bug existed before that commit. So tag 5.10+ as the release for stable backports.
--- fs/btrfs/file.c | 36 +++++++++++++++++++++++++----------- fs/btrfs/tree-log.c | 3 ++- 2 files changed, 27 insertions(+), 12 deletions(-)
fs/btrfs/file.c +25 -11
@@ -2082,6 +2082,30 @@ static int start_ordered_ops(struct inodreturn ret; } +static inline bool skip_inode_logging (const struct btrfs_log_ctx *ctx) +{ +struct btrfs_inode *inode =BTRFS_I (ctx->inode); +struct btrfs_fs_info *fs_info = inode->root->fs_info; + +if (btrfs_inode_in_log (inode, fs_info->generation) && +list_empty (&ctx->ordered_extents)) +return true; + +/* +* If we are doing a fast fsync we can not bail out if the inode's +* last_trans is <= then the last committed transaction, because we only +* update the last_trans of the inode during ordered extent completion, +* and for a fast fsync we don't wait for that, we only wait for the +* writeback to complete. +*/ +if (inode->last_trans <= fs_info->last_trans_committed && + (test_bit (BTRFS_INODE_NEEDS_FULL_SYNC , &inode->runtime_flags) || +list_empty (&ctx->ordered_extents))) +return true; + +return false; +} +/* * fsync call for both files and directories. This logs the inode into * the tree log instead of forcing full commits whenever possible.
@@ -2097,7 +2121,6 @@ int btrfs_sync_file(struct file *file, l {struct dentry *dentry =file_dentry (file);struct inode *inode =d_inode (dentry); -struct btrfs_fs_info *fs_info =btrfs_sb (inode->i_sb);struct btrfs_root *root =BTRFS_I (inode)->root;struct btrfs_trans_handle *trans;struct btrfs_log_ctx ctx;
@@ -2196,17 +2219,8 @@ int btrfs_sync_file(struct file *file, latomic_inc (&root->log_batch); -/* -* If we are doing a fast fsync we can not bail out if the inode's -* last_trans is <= then the last committed transaction, because we only -* update the last_trans of the inode during ordered extent completion, -* and for a fast fsync we don't wait for that, we only wait for the -* writeback to complete. -*/ smp_mb (); -if (btrfs_inode_in_log (BTRFS_I (inode), fs_info->generation) || - (BTRFS_I (inode)->last_trans <= fs_info->last_trans_committed && - (full_sync ||list_empty (&ctx.ordered_extents)))) { +if (skip_inode_logging (&ctx)) {/* * We've had everything committed since the last time we were * modified so clear this flag in case it was set for whatever
fs/btrfs/tree-log.c +2 -1
@@ -6066,7 +6066,8 @@ static int btrfs_log_inode_parent(struct* (since logging them is pointless, a link count of 0 means they * will never be accessible). */ -if (btrfs_inode_in_log (inode, trans->transid) || +if ((btrfs_inode_in_log (inode, trans->transid) && +list_empty (&ctx->ordered_extents)) || inode->vfs_inode.i_nlink ==0 ) { ret =BTRFS_NO_LOG_SYNC ; goto end_no_trans;
Greg Kroah-Hartman
maintainerPATCH 246/329 drm/radeon/dpm: Disable sclk switching on Oland when two 4K 60Hz monitors are connected
In reply to Greg Kroah-HartmanFrom: Kai-Heng Feng <[email protected]>
commit 227545b9a08c68778ddd89428f99c351fc9315ac upstream.
Screen flickers rapidly when two 4K 60Hz monitors are in use. This issue doesn't happen when one monitor is 4K 60Hz (pixelclock 594MHz) and another one is 4K 30Hz (pixelclock 297MHz).
The issue is gone after setting "power_dpm_force_performance_level" to "high". Following the indication, we found that the issue occurs when sclk is too low.
So resolve the issue by disabling sclk switching when there are two monitors requires high pixelclock (> 297MHz).
v2:
- Only apply the fix to Oland.
--- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++++++ drivers/gpu/drm/radeon/si_dpm.c | 3 +++ 3 files changed, 12 insertions(+)
drivers/gpu/drm/radeon/radeon.h +1 -0
@@ -1559,6 +1559,7 @@ struct radeon_dpm {void *priv;u32 new_active_crtcs;int new_active_crtc_count; +int high_pixelclock_count;u32 current_active_crtcs;int current_active_crtc_count;bool single_display;
drivers/gpu/drm/radeon/radeon_pm.c +8 -0
@@ -1775,6 +1775,7 @@ static void radeon_pm_compute_clocks_dpmstruct drm_device *ddev = rdev->ddev;struct drm_crtc *crtc;struct radeon_crtc *radeon_crtc; +struct radeon_connector *radeon_connector;if (!rdev->pm.dpm_enabled)return ;
@@ -1784,6 +1785,7 @@ static void radeon_pm_compute_clocks_dpm/* update active crtc counts */ rdev->pm.dpm.new_active_crtcs =0 ; rdev->pm.dpm.new_active_crtc_count =0 ; + rdev->pm.dpm.high_pixelclock_count =0 ;if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {list_for_each_entry (crtc, &ddev->mode_config.crtc_list, head) {
@@ -1791,6 +1793,12 @@ static void radeon_pm_compute_clocks_dpmif (crtc->enabled) { rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); rdev->pm.dpm.new_active_crtc_count++; +if (!radeon_crtc->connector) +continue ; + + radeon_connector =to_radeon_connector (radeon_crtc->connector); +if (radeon_connector->pixelclock_for_modeset >297000 ) + rdev->pm.dpm.high_pixelclock_count++; } } }
drivers/gpu/drm/radeon/si_dpm.c +3 -0
@@ -2979,6 +2979,9 @@ static void si_apply_state_adjust_rules( (rdev->pdev->device == 0x6605)) { max_sclk =75000 ; } + +if (rdev->pm.dpm.high_pixelclock_count >1 ) + disable_sclk_switching = true; }if (rps->vce_active) {
Greg Kroah-Hartman
maintainerPATCH 247/329 drm/amd/display: Initialize attribute for hdcp_srm sysfs file
In reply to Greg Kroah-HartmanFrom: David Ward <[email protected]>
commit fe1c97d008f86f672f0e9265f180c22451ca3b9f upstream.
It is stored in dynamically allocated memory, so sysfs_bin_attr_init() must be called to initialize it. (Note: "initialization" only sets the .attr.key member in this struct; it does not change the value of any other members.)
Otherwise, when CONFIG_DEBUG_LOCK_ALLOC=y this message appears during boot:
BUG: key ffff9248900cd148 has not been registered!
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +1 -0
@@ -643,6 +643,7 @@ struct hdcp_workqueue *hdcp_create_workq/* File created at /sys/class/drm/card0/device/hdcp_srm*/ hdcp_work[0 ].attr = data_attr; +sysfs_bin_attr_init (&hdcp_work[0 ].attr);if (sysfs_create_bin_file (&adev->dev->kobj, &hdcp_work[0 ].attr))DRM_WARN ("Failed to create device file hdcp_srm" );
Greg Kroah-Hartman
maintainerPATCH 248/329 drm/i915: Avoid div-by-zero on gen2
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit 4819d16d91145966ce03818a95169df1fd56b299 upstream.
Gen2 tiles are 2KiB in size so i915_gem_object_get_tile_row_size() can in fact return <4KiB, which leads to div-by-zero here. Avoid that.
Not sure i915_gem_object_get_tile_row_size() is entirely sane anyway since it doesn't account for the different tile layouts on i8xx/i915...
I'm not able to hit this before commit 6846895fde05 ("drm/i915:
Replace PIN_NONFAULT with calls to PIN_NOEVICT") and it looks like I also need to run recent version of Mesa. With those in place xonotic trips on this quite easily on my 85x.
--- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gem/i915_gem_mman.c +1 -1
@@ -189,7 +189,7 @@ compute_partial_view(const struct drm_i9struct i915_ggtt_view view;if (i915_gem_object_is_tiled (obj)) - chunk =roundup (chunk,tile_row_pages (obj)); + chunk =roundup (chunk,tile_row_pages (obj) ?:1 ); view.type =I915_GGTT_VIEW_PARTIAL ; view.partial.offset =rounddown (page_offset, chunk);
Greg Kroah-Hartman
maintainerPATCH 249/329 kvm: exit halt polling on need_resched() as well
In reply to Greg Kroah-HartmanFrom: Benjamin Segall <[email protected]>
commit 262de4102c7bb8e59f26a967a8ffe8cce85cc537 upstream.
single_task_running() is usually more general than need_resched() but CFS_BANDWIDTH throttling will use resched_task() when there is just one task to get the task to block. This was causing long-need_resched warnings and was likely allowing VMs to overrun their quota when halt polling.
Message-Id: <[email protected]>
--- virt/kvm/kvm_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/kvm_main.c +2 -1
@@ -2814,7 +2814,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcp goto out; } poll_end = cur =ktime_get (); - }while (single_task_running () &&ktime_before (cur, stop)); + }while (single_task_running () && !need_resched () && +ktime_before (cur, stop)); }prepare_to_rcuwait (&vcpu->wait);
Greg Kroah-Hartman
maintainerPATCH 250/329 drm/msm: fix LLC not being enabled for mmu500 targets
In reply to Greg Kroah-HartmanFrom: Jonathan Marek <[email protected]>
[ Upstream commit 4b95d371fb001185af84d177e69a23d55bd0167a ]
mmu500 targets don't have a "cx_mem" region, set llc_mmio to NULL in that case to avoid the IS_ERR() condition in a6xx_llc_activate().
--- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/gpu/drm/msm/adreno/a6xx_gpu.c +5 -4
@@ -1152,10 +1152,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, {struct device_node *phandle; - a6xx_gpu->llc_mmio =msm_ioremap (pdev,"cx_mem" ,"gpu_cx" ); -if (IS_ERR (a6xx_gpu->llc_mmio)) -return ; -/* * There is a different programming path for targets with an mmu500 * attached, so detect if that is the case
@@ -1165,6 +1161,11 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, of_device_is_compatible(phandle, "arm,mmu-500"));of_node_put (phandle); +if (a6xx_gpu->have_mmu500) + a6xx_gpu->llc_mmio =NULL ; +else + a6xx_gpu->llc_mmio =msm_ioremap (pdev,"cx_mem" ,"gpu_cx" ); + a6xx_gpu->llc_slice =llcc_slice_getd (LLCC_GPU ); a6xx_gpu->htw_llc_slice =llcc_slice_getd (LLCC_GPUHTW );
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 251/329 KVM: LAPIC: Accurately guarantee busy wait for timer to expire when using hv_timer
In reply to Greg Kroah-HartmanFrom: Wanpeng Li <[email protected]>
[ Upstream commit d981dd15498b188636ec5a7d8ad485e650f63d8d ]
Commit ee66e453db13d (KVM: lapic: Busy wait for timer to expire when using hv_timer) tries to set ktime->expired_tscdeadline by checking ktime->hv_timer_in_use since lapic timer oneshot/periodic modes which are emulated by vmx preemption timer also get advanced, they leverage the same vmx preemption timer logic with tsc-deadline mode. However, ktime->hv_timer_in_use is cleared before apic_timer_expired() handling, let's delay this clearing in preemption-disabled region.
Message-Id: <[email protected]>
--- arch/x86/kvm/lapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/lapic.c +1 -1
@@ -1908,8 +1908,8 @@ void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)if (!apic->lapic_timer.hv_timer_in_use) goto out;WARN_ON (rcuwait_active (&vcpu->wait)); -cancel_hv_timer (apic);apic_timer_expired (apic, false); +cancel_hv_timer (apic);if (apic_lvtt_period (apic) && apic->lapic_timer.period) {advance_periodic_target_expiration (apic);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 252/329 drm/msm/dp: initialize audio_comp when audio starts
In reply to Greg Kroah-HartmanFrom: Kuogee Hsieh <[email protected]>
[ Upstream commit f2f46b878777e0d3f885c7ddad48f477b4dea247 ]
Initialize audio_comp when audio starts and wait for audio_comp at dp_display_disable(). This will take care of both dongle unplugged and display off (suspend) cases.
Changes in v2:
-- add dp_display_signal_audio_start()
Changes in v3:
-- restore dp_display_handle_plugged_change() at dp_hpd_unplug_handle().
Changes in v4:
-- none
--- drivers/gpu/drm/msm/dp/dp_audio.c | 1 + drivers/gpu/drm/msm/dp/dp_display.c | 11 +++++++++-- drivers/gpu/drm/msm/dp/dp_display.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/msm/dp/dp_audio.c +1 -0
@@ -527,6 +527,7 @@ int dp_audio_hw_params(struct device *dev,dp_audio_setup_acr (audio);dp_audio_safe_to_exit_level (audio);dp_audio_enable (audio, true); +dp_display_signal_audio_start (dp_display); dp_display->audio_enabled = true; end:
drivers/gpu/drm/msm/dp/dp_display.c +9 -2
@@ -178,6 +178,15 @@ static int dp_del_event(struct dp_display_private *dp_priv, u32 event)return 0 ; } +void dp_display_signal_audio_start (struct msm_dp *dp_display) +{ +struct dp_display_private *dp; + + dp = container_of(dp_display, struct dp_display_private, dp_display); + +reinit_completion (&dp->audio_comp); +} +void dp_display_signal_audio_complete (struct msm_dp *dp_display) {struct dp_display_private *dp;
@@ -651,7 +660,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)dp_add_event (dp,EV_DISCONNECT_PENDING_TIMEOUT ,0 ,DP_TIMEOUT_5_SECOND );/* signal the disconnect event early to ensure proper teardown */ -reinit_completion (&dp->audio_comp);dp_display_handle_plugged_change (g_dp_display, false); dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK |
@@ -891,7 +899,6 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)/* wait only if audio was enabled */ if (dp_display->audio_enabled) {/* signal the disconnect event */ -reinit_completion (&dp->audio_comp);dp_display_handle_plugged_change (dp_display, false);if (!wait_for_completion_timeout (&dp->audio_comp,HZ *5 ))
drivers/gpu/drm/msm/dp/dp_display.h +1 -0
@@ -34,6 +34,7 @@ int dp_display_get_modes(struct msm_dp *dp_display,int dp_display_request_irq (struct msm_dp *dp_display);bool dp_display_check_video_test (struct msm_dp *dp_display);int dp_display_get_test_bpp (struct msm_dp *dp_display); +void dp_display_signal_audio_start (struct msm_dp *dp_display);void dp_display_signal_audio_complete (struct msm_dp *dp_display);#endif /* _DP_DISPLAY_H_ */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 253/329 KVM: x86: Cancel pvclock_gtod_work on module removal
In reply to Greg Kroah-HartmanFrom: Thomas Gleixner <[email protected]>
[ Upstream commit 594b27e677b35f9734b1969d175ebc6146741109 ]
Nothing prevents the following:
pvclock_gtod_notify()
queue_work(system_long_wq, &pvclock_gtod_work);
...
remove_module(kvm);
...
work_queue_run()
pvclock_gtod_work() <- UAFDitto for any other operation on that workqueue list head which touches pvclock_gtod_work after module removal.
Cancel the work in kvm_arch_exit() to prevent that.
Message-Id: <[email protected]>
--- arch/x86/kvm/x86.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/kvm/x86.c +1 -0
@@ -8005,6 +8005,7 @@ void kvm_arch_exit(void)cpuhp_remove_state_nocalls (CPUHP_AP_X86_KVM_CLK_ONLINE );#ifdef CONFIG_X86_64 pvclock_gtod_unregister_notifier (&pvclock_gtod_notifier); +cancel_work_sync (&pvclock_gtod_work);#endif kvm_x86_ops.hardware_enable =NULL ;kvm_mmu_module_exit ();
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 254/329 KVM: x86: Prevent deadlock against tk_core.seq
In reply to Greg Kroah-HartmanFrom: Thomas Gleixner <[email protected]>
[ Upstream commit 3f804f6d201ca93adf4c3df04d1bfd152c1129d6 ]
syzbot reported a possible deadlock in pvclock_gtod_notify():
CPU 0 CPU 1write_seqcount_begin(&tk_core.seq);
pvclock_gtod_notify() spin_lock(&pool->lock);
queue_work(..., &pvclock_gtod_work) ktime_get()
spin_lock(&pool->lock); do {
seq = read_seqcount_begin(tk_core.seq)
...
} while (read_seqcount_retry(&tk_core.seq, seq);While this is unlikely to happen, it's possible.
Delegate queue_work() to irq_work() which postpones it until the tk_core.seq write held region is left and interrupts are reenabled.
Message-Id: <[email protected]>
--- arch/x86/kvm/x86.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
arch/x86/kvm/x86.c +18 -4
@@ -7872,6 +7872,18 @@ static void pvclock_gtod_update_fn(struct work_struct *work) static DECLARE_WORK(pvclock_gtod_work, pvclock_gtod_update_fn); +/* +* Indirection to move queue_work() out of the tk_core.seq write held +* region to prevent possible deadlocks against time accessors which +* are invoked with work related locks held. +*/ +static void pvclock_irq_work_fn (struct irq_work *w) +{ +queue_work (system_long_wq, &pvclock_gtod_work); +} + +static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn); +/* * Notification about pvclock gtod data update. */
@@ -7883,13 +7895,14 @@ static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,update_pvclock_gtod (tk); -/* disable master clock if host does not trust, or does not -* use, TSC based clocksource. +/* +* Disable master clock if host does not trust, or does not use, +* TSC based clocksource. Delegate queue_work() to irq_work as +* this is invoked with tk_core.seq write held. */ if (!gtod_is_based_on_tsc (gtod->clock.vclock_mode) &&atomic_read (&kvm_guest_has_master_clock) !=0 ) -queue_work (system_long_wq, &pvclock_gtod_work); - +irq_work_queue (&pvclock_irq_work);return 0 ; }
@@ -8005,6 +8018,7 @@ void kvm_arch_exit(void)cpuhp_remove_state_nocalls (CPUHP_AP_X86_KVM_CLK_ONLINE );#ifdef CONFIG_X86_64 pvclock_gtod_unregister_notifier (&pvclock_gtod_notifier); +irq_work_sync (&pvclock_irq_work);cancel_work_sync (&pvclock_gtod_work);#endif kvm_x86_ops.hardware_enable =NULL ;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 255/329 dax: Add an enum for specifying dax wakup mode
In reply to Greg Kroah-HartmanFrom: Vivek Goyal <[email protected]>
[ Upstream commit 698ab77aebffe08b312fbcdddeb0e8bd08b78717 ]
Dan mentioned that he is not very fond of passing around a boolean true/false to specify if only next waiter should be woken up or all waiters should be woken up. He instead prefers that we introduce an enum and make it very explicity at the callsite itself. Easier to read code.
This patch should not introduce any change of behavior.
--- fs/dax.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
fs/dax.c +17 -6
@@ -144,6 +144,16 @@ struct wait_exceptional_entry_queue {struct exceptional_entry_key key; }; +/** +* enum dax_wake_mode: waitqueue wakeup behaviour +* @WAKE_ALL: wake all waiters in the waitqueue +* @WAKE_NEXT: wake only the first waiter in the waitqueue +*/ +enum dax_wake_mode { +WAKE_ALL , +WAKE_NEXT , +}; +static wait_queue_head_t *dax_entry_waitqueue (struct xa_state *xas,void *entry,struct exceptional_entry_key *key) {
@@ -182,7 +192,8 @@ static int wake_exceptional_entry_func(wait_queue_entry_t *wait,* The important information it's conveying is whether the entry at * this index used to be a PMD entry. */ -static void dax_wake_entry (struct xa_state *xas,void *entry,bool wake_all) +static void dax_wake_entry (struct xa_state *xas,void *entry, +enum dax_wake_mode mode) {struct exceptional_entry_key key;wait_queue_head_t *wq;
@@ -196,7 +207,7 @@ static void dax_wake_entry(struct xa_state *xas, void *entry, bool wake_all)* must be in the waitqueue and the following check will see them. */ if (waitqueue_active (wq)) -__wake_up (wq,TASK_NORMAL , wake_all ?0 :1 , &key); +__wake_up (wq,TASK_NORMAL , mode ==WAKE_ALL ?0 :1 , &key); }/*
@@ -268,7 +279,7 @@ static void put_unlocked_entry(struct xa_state *xas, void *entry) {/* If we were the only waiter woken, wake the next one */ if (entry && !dax_is_conflict (entry)) -dax_wake_entry (xas, entry, false); +dax_wake_entry (xas, entry,WAKE_NEXT ); }/*
@@ -286,7 +297,7 @@ static void dax_unlock_entry(struct xa_state *xas, void *entry) old =xas_store (xas, entry);xas_unlock_irq (xas);BUG_ON (!dax_is_locked (old)); -dax_wake_entry (xas, entry, false); +dax_wake_entry (xas, entry,WAKE_NEXT ); }/*
@@ -524,7 +535,7 @@ static void *grab_mapping_entry(struct xa_state *xas,dax_disassociate_entry (entry, mapping, false);xas_store (xas,NULL );/* undo the PMD join */ -dax_wake_entry (xas, entry, true); +dax_wake_entry (xas, entry,WAKE_ALL ); mapping->nrexceptional--; entry =NULL ;xas_set (xas, index);
@@ -937,7 +948,7 @@ static int dax_writeback_one(struct xa_state *xas, struct dax_device *dax_dev,xas_lock_irq (xas);xas_store (xas, entry);xas_clear_mark (xas,PAGECACHE_TAG_DIRTY ); -dax_wake_entry (xas, entry, false); +dax_wake_entry (xas, entry,WAKE_NEXT );trace_dax_writeback_one (mapping->host, index, count);return ret;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 256/329 dax: Add a wakeup mode parameter to put_unlocked_entry()
In reply to Greg Kroah-HartmanFrom: Vivek Goyal <[email protected]>
[ Upstream commit 4c3d043d271d4d629aa2328796cdfc96b37d3b3c ]
As of now put_unlocked_entry() always wakes up next waiter. In next patches we want to wake up all waiters at one callsite. Hence, add a parameter to the function.
This patch does not introduce any change of behavior.
--- fs/dax.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
fs/dax.c +7 -7
@@ -275,11 +275,11 @@ static void wait_entry_unlocked(struct xa_state *xas, void *entry)finish_wait (wq, &ewait.wait); } -static void put_unlocked_entry (struct xa_state *xas,void *entry) +static void put_unlocked_entry (struct xa_state *xas,void *entry, +enum dax_wake_mode mode) { -/* If we were the only waiter woken, wake the next one */ if (entry && !dax_is_conflict (entry)) -dax_wake_entry (xas, entry,WAKE_NEXT ); +dax_wake_entry (xas, entry, mode); }/*
@@ -633,7 +633,7 @@ struct page *dax_layout_busy_page_range(struct address_space *mapping, entry =get_unlocked_entry (&xas,0 );if (entry) page =dax_busy_page (entry); -put_unlocked_entry (&xas, entry); +put_unlocked_entry (&xas, entry,WAKE_NEXT );if (page)break ;if (++scanned %XA_CHECK_SCHED )
@@ -675,7 +675,7 @@ static int __dax_invalidate_entry(struct address_space *mapping, mapping->nrexceptional--; ret =1 ; out: -put_unlocked_entry (&xas, entry); +put_unlocked_entry (&xas, entry,WAKE_NEXT );xas_unlock_irq (&xas);return ret; }
@@ -954,7 +954,7 @@ static int dax_writeback_one(struct xa_state *xas, struct dax_device *dax_dev,return ret; put_unlocked: -put_unlocked_entry (xas, entry); +put_unlocked_entry (xas, entry,WAKE_NEXT );return ret; }
@@ -1695,7 +1695,7 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order)/* Did we race with someone splitting entry or so? */ if (!entry ||dax_is_conflict (entry) || (order ==0 && !dax_is_pte_entry (entry))) { -put_unlocked_entry (&xas, entry); +put_unlocked_entry (&xas, entry,WAKE_NEXT );xas_unlock_irq (&xas);trace_dax_insert_pfn_mkwrite_no_entry (mapping->host, vmf,VM_FAULT_NOPAGE );
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 257/329 dax: Wake up all waiters after invalidating dax entry
In reply to Greg Kroah-HartmanFrom: Vivek Goyal <[email protected]>
[ Upstream commit 237388320deffde7c2d65ed8fc9eef670dc979b3 ]
I am seeing missed wakeups which ultimately lead to a deadlock when I am using virtiofs with DAX enabled and running "make -j". I had to mount virtiofs as rootfs and also reduce to dax window size to 256M to reproduce the problem consistently.
So here is the problem. put_unlocked_entry() wakes up waiters only if entry is not null as well as !dax_is_conflict(entry). But if I call multiple instances of invalidate_inode_pages2() in parallel, then I can run into a situation where there are waiters on this index but nobody will wake these waiters.
invalidate_inode_pages2()
invalidate_inode_pages2_range()
invalidate_exceptional_entry2()
dax_invalidate_mapping_entry_sync()
__dax_invalidate_entry() {
xas_lock_irq(&xas);
entry = get_unlocked_entry(&xas, 0);
...
...
dax_disassociate_entry(entry, mapping, trunc);
xas_store(&xas, NULL);
...
...
put_unlocked_entry(&xas, entry);
xas_unlock_irq(&xas);
}Say a fault in in progress and it has locked entry at offset say "0x1c". Now say three instances of invalidate_inode_pages2() are in progress (A, B, C) and they all try to invalidate entry at offset "0x1c". Given dax entry is locked, all tree instances A, B, C will wait in wait queue.
When dax fault finishes, say A is woken up. It will store NULL entry at index "0x1c" and wake up B. When B comes along it will find "entry=0" at page offset 0x1c and it will call put_unlocked_entry(&xas, 0). And this means put_unlocked_entry() will not wake up next waiter, given the current code. And that means C continues to wait and is not woken up.
This patch fixes the issue by waking up all waiters when a dax entry has been invalidated. This seems to fix the deadlock I am facing and I can make forward progress.
--- fs/dax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dax.c +1 -1
@@ -675,7 +675,7 @@ static int __dax_invalidate_entry(struct address_space *mapping, mapping->nrexceptional--; ret =1 ; out: -put_unlocked_entry (&xas, entry,WAKE_NEXT ); +put_unlocked_entry (&xas, entry,WAKE_ALL );xas_unlock_irq (&xas);return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 258/329 xen/unpopulated-alloc: fix error return code in fill_list()
In reply to Greg Kroah-HartmanFrom: Zhen Lei <[email protected]>
[ Upstream commit dbc03e81586fc33e4945263fd6e09e22eb4b980f ]
Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function.
--- drivers/xen/unpopulated-alloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/xen/unpopulated-alloc.c +3 -1
@@ -39,8 +39,10 @@ static int fill_list(unsigned int nr_pages) } pgmap =kzalloc (sizeof (*pgmap),GFP_KERNEL ); -if (!pgmap) +if (!pgmap) { + ret = -ENOMEM ; goto err_pgmap; + } pgmap->type =MEMORY_DEVICE_GENERIC ; pgmap->range = (struct range ) {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 259/329 perf tools: Fix dynamic libbpf link
In reply to Greg Kroah-HartmanFrom: Jiri Olsa <[email protected]>
[ Upstream commit ad1237c30d975535a669746496cbed136aa5a045 ]
Justin reported broken build with LIBBPF_DYNAMIC=1.
When linking libbpf dynamically we need to use perf's hashmap object, because it's not exported in libbpf.so (only in libbpf.a).
Following build is now passing:
$ make LIBBPF_DYNAMIC=1
BUILD: Doing 'make -j8' parallel build
...
$ ldd perf | grep libbpf
libbpf.so.0 => /lib64/libbpf.so.0 (0x00007fa7630db000)--- tools/perf/Makefile.config | 1 + tools/perf/util/Build | 7 +++++++ 2 files changed, 8 insertions(+)
tools/perf/Makefile.config +1 -0
@@ -530,6 +530,7 @@ ifndef NO_LIBELF ifdef LIBBPF_DYNAMIC ifeq ($(feature-libbpf), 1) EXTLIBS += -lbpf + $(call detected,CONFIG_LIBBPF_DYNAMIC) else dummy := $(error Error: No libbpf devel library found, please install libbpf-devel); endif
tools/perf/util/Build +7 -0
@@ -140,7 +140,14 @@ perf-$(CONFIG_LIBELF) += symbol-elf.o perf-$(CONFIG_LIBELF) += probe-file.o perf-$(CONFIG_LIBELF) += probe-event.o +ifdef CONFIG_LIBBPF_DYNAMIC + hashmap := 1 +endif ifndef CONFIG_LIBBPF + hashmap := 1 +endif + +ifdef hashmap perf-y += hashmap.o endif
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 260/329 usb: dwc3: gadget: Free gadget structure only after freeing endpoints
In reply to Greg Kroah-HartmanFrom: Jack Pham <[email protected]>
[ Upstream commit bb9c74a5bd1462499fe5ccb1e3c5ac40dcfa9139 ]
As part of commit e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") the dwc3_gadget_release() was added which will free the dwc->gadget structure upon the device's removal when usb_del_gadget_udc() is called in dwc3_gadget_exit().
However, simply freeing the gadget results a dangling pointer
situation: the endpoints created in dwc3_gadget_init_endpoints() have their dep->endpoint.ep_list members chained off the list_head anchored at dwc->gadget->ep_list. Thus when dwc->gadget is freed, the first dwc3_ep in the list now has a dangling prev pointer and likewise for the next pointer of the dwc3_ep at the tail of the list. The dwc3_gadget_free_endpoints() that follows will result in a use-after-free when it calls list_del().
This was caught by enabling KASAN and performing a driver unbind. The recent commit 568262bf5492 ("usb: dwc3: core: Add shutdown callback for dwc3") also exposes this as a panic during shutdown.
There are a few possibilities to fix this. One could be to perform a list_del() of the gadget->ep_list itself which removes it from the rest of the dwc3_ep chain.
Another approach is what this patch does, by splitting up the usb_del_gadget_udc() call into its separate "del" and "put" components. This allows dwc3_gadget_free_endpoints() to be called before the gadget is finally freed with usb_put_gadget().
--- drivers/usb/dwc3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/dwc3/gadget.c +2 -1
@@ -3948,8 +3948,9 @@ int dwc3_gadget_init(struct dwc3 *dwc)void dwc3_gadget_exit (struct dwc3 *dwc) { -usb_del_gadget_udc (dwc->gadget); +usb_del_gadget (dwc->gadget);dwc3_gadget_free_endpoints (dwc); +usb_put_gadget (dwc->gadget);dma_free_coherent (dwc->sysdev,DWC3_BOUNCE_SIZE , dwc->bounce, dwc->bounce_addr);kfree (dwc->setup_buf);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 261/329 iio: light: gp2ap002: Fix rumtime PM imbalance on error
In reply to Greg Kroah-HartmanFrom: Dinghao Liu <[email protected]>
[ Upstream commit 8edb79af88efc6e49e735f9baf61d9f0748b881f ]
When devm_request_threaded_irq() fails, we should decrease the runtime PM counter to keep the counter balanced. But when iio_device_register() fails, we need not to decrease it because we have already decreased it before.
--- drivers/iio/light/gp2ap002.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iio/light/gp2ap002.c +3 -2
@@ -583,7 +583,7 @@ static int gp2ap002_probe(struct i2c_client *client, "gp2ap002", indio_dev);if (ret) {dev_err (dev,"unable to request IRQ\n" ); - goto out_disable_vio; + goto out_put_pm; } gp2ap002->irq = client->irq;
@@ -613,8 +613,9 @@ static int gp2ap002_probe(struct i2c_client *client,return 0 ; -out_disable_pm: +out_put_pm:pm_runtime_put_noidle (dev); +out_disable_pm:pm_runtime_disable (dev); out_disable_vio:regulator_disable (gp2ap002->vio);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 262/329 iio: proximity: pulsedlight: Fix rumtime PM imbalance on error
In reply to Greg Kroah-HartmanFrom: Dinghao Liu <[email protected]>
[ Upstream commit a2fa9242e89f27696515699fe0f0296bf1ac1815 ]
When lidar_write_control() fails, a pairing PM usage counter decrement is needed to keep the counter balanced.
--- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 1 + 1 file changed, 1 insertion(+)
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +1 -0
@@ -160,6 +160,7 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg) ret =lidar_write_control (data,LIDAR_REG_CONTROL_ACQUIRE );if (ret <0 ) {dev_err (&client->dev,"cannot send start measurement command" ); +pm_runtime_put_noidle (&client->dev);return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 263/329 iio: hid-sensors: select IIO_TRIGGERED_BUFFER under HID_SENSOR_IIO_TRIGGER
In reply to Greg Kroah-HartmanFrom: Alexandru Ardelean <[email protected]>
[ Upstream commit 7061803522ee7876df1ca18cdd1e1551f761352d ]
During commit 067fda1c065ff ("iio: hid-sensors: move triggered buffer setup into hid_sensor_setup_trigger"), the iio_triggered_buffer_{setup,cleanup}() functions got moved under the hid-sensor-trigger module.
The above change works fine, if any of the sensors get built. However, when only the common hid-sensor-trigger module gets built (and none of the drivers), then the IIO_TRIGGERED_BUFFER symbol isn't selected/enforced.
Previously, each driver would enforce/select the IIO_TRIGGERED_BUFFER symbol. With this change the HID_SENSOR_IIO_TRIGGER (for the hid-sensor-trigger module) will enforce that IIO_TRIGGERED_BUFFER gets selected.
All HID sensor drivers select the HID_SENSOR_IIO_TRIGGER symbol. So, this change removes the IIO_TRIGGERED_BUFFER enforcement from each driver.
--- drivers/iio/accel/Kconfig | 1 - drivers/iio/common/hid-sensors/Kconfig | 1 + drivers/iio/gyro/Kconfig | 1 - drivers/iio/humidity/Kconfig | 1 - drivers/iio/light/Kconfig | 2 -- drivers/iio/magnetometer/Kconfig | 1 - drivers/iio/orientation/Kconfig | 2 -- drivers/iio/pressure/Kconfig | 1 - drivers/iio/temperature/Kconfig | 1 - 9 files changed, 1 insertion(+), 10 deletions(-)
drivers/iio/accel/Kconfig +0 -1
@@ -211,7 +211,6 @@ config DMARD10 config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID Accelerometers 3D"
drivers/iio/common/hid-sensors/Kconfig +1 -0
@@ -19,6 +19,7 @@ config HID_SENSOR_IIO_TRIGGER tristate "Common module (trigger) for all HID Sensor IIO drivers" depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON && IIO_BUFFER select IIO_TRIGGER + select IIO_TRIGGERED_BUFFER help Say yes here to build trigger support for HID sensors. Triggers will be send if all requested attributes were read.
drivers/iio/gyro/Kconfig +0 -1
@@ -111,7 +111,6 @@ config FXAS21002C_SPI config HID_SENSOR_GYRO_3D depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID Gyroscope 3D"
drivers/iio/humidity/Kconfig +0 -1
@@ -52,7 +52,6 @@ config HID_SENSOR_HUMIDITY tristate "HID Environmental humidity sensor" depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER help
drivers/iio/light/Kconfig +0 -2
@@ -256,7 +256,6 @@ config ISL29125 config HID_SENSOR_ALS depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID ALS"
@@ -270,7 +269,6 @@ config HID_SENSOR_ALS config HID_SENSOR_PROX depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID PROX"
drivers/iio/magnetometer/Kconfig +0 -1
@@ -95,7 +95,6 @@ config MAG3110 config HID_SENSOR_MAGNETOMETER_3D depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID Magenetometer 3D"
drivers/iio/orientation/Kconfig +0 -2
@@ -9,7 +9,6 @@ menu "Inclinometer sensors" config HID_SENSOR_INCLINOMETER_3D depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID Inclinometer 3D"
@@ -20,7 +19,6 @@ config HID_SENSOR_INCLINOMETER_3D config HID_SENSOR_DEVICE_ROTATION depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID Device Rotation"
drivers/iio/pressure/Kconfig +0 -1
@@ -79,7 +79,6 @@ config DPS310 config HID_SENSOR_PRESS depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID PRESS"
drivers/iio/temperature/Kconfig +0 -1
@@ -45,7 +45,6 @@ config HID_SENSOR_TEMP tristate "HID Environmental temperature sensor" depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER help
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 264/329 iio: core: return ENODEV if ioctl is unknown
In reply to Greg Kroah-HartmanFrom: Alexandru Ardelean <[email protected]>
[ Upstream commit af0670b0bf1b116fd729b1b1011cf814bc34e12e ]
When the ioctl() mechanism was introduced in IIO core to centralize the registration of all ioctls in one place via commit 8dedcc3eee3ac ("iio:
core: centralize ioctl() calls to the main chardev"), the return code was changed from ENODEV to EINVAL, when the ioctl code isn't known.
This was done by accident.
This change reverts back to the old behavior, where if the ioctl() code isn't known, ENODEV is returned (vs EINVAL).
This was brought into perspective by this patch:
https://lore.kernel.org/linux-iio/[email protected]/
--- drivers/iio/industrialio-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iio/industrialio-core.c +1 -2
@@ -1698,7 +1698,6 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)if (!indio_dev->info) goto out_unlock; - ret = -EINVAL ;list_for_each_entry (h, &iio_dev_opaque->ioctl_handlers, entry) { ret = h->ioctl (indio_dev, filp, cmd, arg);if (ret !=IIO_IOCTL_UNHANDLED )
@@ -1706,7 +1705,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) }if (ret ==IIO_IOCTL_UNHANDLED ) - ret = -EINVAL ; + ret = -ENODEV ; out_unlock:mutex_unlock (&indio_dev->info_exist_lock);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 265/329 usb: fotg210-hcd: Fix an error message
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit a60a34366e0d09ca002c966dd7c43a68c28b1f82 ]
'retval' is known to be -ENODEV here.
This is a hard-coded default error code which is not useful in the error message. Moreover, another error message is printed at the end of the error handling path. The corresponding error code (-ENOMEM) is more informative.
So remove simplify the first error message.
While at it, also remove the useless initialization of 'retval'.
--- drivers/usb/host/fotg210-hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/host/fotg210-hcd.c +2 -2
@@ -5568,7 +5568,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev)struct usb_hcd *hcd;struct resource *res;int irq; -int retval = -ENODEV ; +int retval;struct fotg210_hcd *fotg210;if (usb_disabled ())
@@ -5588,7 +5588,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) hcd =usb_create_hcd (&fotg210_fotg210_hc_driver, dev,dev_name (dev));if (!hcd) { -dev_err (dev,"failed to create hcd with err %d\n" , retval); +dev_err (dev,"failed to create hcd\n" ); retval = -ENOMEM ; goto fail_create_hcd; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 266/329 hwmon: (occ) Fix poll rate limiting
In reply to Greg Kroah-HartmanFrom: Eddie James <[email protected]>
[ Upstream commit 5216dff22dc2bbbbe6f00335f9fd2879670e753b ]
The poll rate limiter time was initialized at zero. This breaks the comparison in time_after if jiffies is large. Switch to storing the next update time rather than the previous time, and initialize the time when the device is probed.
--- drivers/hwmon/occ/common.c | 5 +++-- drivers/hwmon/occ/common.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/hwmon/occ/common.c +3 -2
@@ -217,9 +217,9 @@ int occ_update_response(struct occ *occ)return rc;/* limit the maximum rate of polling the OCC */ -if (time_after (jiffies, occ->last_update +OCC_UPDATE_FREQUENCY )) { +if (time_after (jiffies, occ->next_update)) { rc =occ_poll (occ); - occ->last_update = jiffies; + occ->next_update = jiffies +OCC_UPDATE_FREQUENCY ; }else { rc = occ->last_error; }
@@ -1164,6 +1164,7 @@ int occ_setup(struct occ *occ, const char *name)return rc; } + occ->next_update = jiffies +OCC_UPDATE_FREQUENCY ;occ_parse_poll_response (occ); rc =occ_setup_sensor_attrs (occ);
drivers/hwmon/occ/common.h +1 -1
@@ -99,7 +99,7 @@ struct occ {u8 poll_cmd_data;/* to perform OCC poll command */ int (*send_cmd)(struct occ *occ,u8 *cmd); -unsigned long last_update; +unsigned long next_update;struct mutex lock;/* lock OCC access */ struct device *hwmon;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 267/329 usb: musb: Fix an error message
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit d9ff1096a840dddea3d5cfa2149ff7da9f499fb2 ]
'ret' is known to be 0 here.
Initialize 'ret' with the expected error code before using it.
--- drivers/usb/musb/mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/musb/mediatek.c +1 -1
@@ -518,8 +518,8 @@ static int mtk_musb_probe(struct platform_device *pdev) glue->xceiv =devm_usb_get_phy (dev,USB_PHY_TYPE_USB2 );if (IS_ERR (glue->xceiv)) { -dev_err (dev,"fail to getting usb-phy %d\n" , ret); ret =PTR_ERR (glue->xceiv); +dev_err (dev,"fail to getting usb-phy %d\n" , ret); goto err_unregister_usb_phy; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 268/329 hwmon: (ltc2992) Put fwnode in error case during ->probe()
In reply to Greg Kroah-HartmanFrom: Andy Shevchenko <[email protected]>
[ Upstream commit 8370e5b093080c03cf89f7ebf0bef6984545429e ]
In each iteration fwnode_for_each_available_child_node() bumps a reference counting of a loop variable followed by dropping in on a next iteration,
Since in error case the loop is broken, we have to drop a reference count by ourselves. Do it for port_fwnode in error case during ->probe().
--- drivers/hwmon/ltc2992.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/hwmon/ltc2992.c +6 -2
@@ -900,11 +900,15 @@ static int ltc2992_parse_dt(struct ltc2992_state *st)fwnode_for_each_available_child_node (fwnode, child) { ret =fwnode_property_read_u32 (child,"reg" , &addr); -if (ret <0 ) +if (ret <0 ) { +fwnode_handle_put (child);return ret; + } -if (addr >1 ) +if (addr >1 ) { +fwnode_handle_put (child);return -EINVAL ; + } ret =fwnode_property_read_u32 (child,"shunt-resistor-micro-ohms" , &val);if (!ret)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 269/329 ACPI: scan: Fix a memory leak in an error handling path
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit 0c8bd174f0fc131bc9dfab35cd8784f59045da87 ]
If 'acpi_device_set_name()' fails, we must free 'acpi_device_bus_id->bus_id' or there is a (potential) memory leak.
--- drivers/acpi/scan.c | 1 + 1 file changed, 1 insertion(+)
drivers/acpi/scan.c +1 -0
@@ -705,6 +705,7 @@ int acpi_device_add(struct acpi_device *device, result =acpi_device_set_name (device, acpi_device_bus_id);if (result) { +kfree_const (acpi_device_bus_id->bus_id);kfree (acpi_device_bus_id); goto err_unlock; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 270/329 kyber: fix out of bounds access when preempted
In reply to Greg Kroah-HartmanFrom: Omar Sandoval <[email protected]>
[ Upstream commit efed9a3337e341bd0989161b97453b52567bc59d ]
__blk_mq_sched_bio_merge() gets the ctx and hctx for the current CPU and passes the hctx to ->bio_merge(). kyber_bio_merge() then gets the ctx for the current CPU again and uses that to get the corresponding Kyber context in the passed hctx. However, the thread may be preempted between the two calls to blk_mq_get_ctx(), and the ctx returned the second time may no longer correspond to the passed hctx. This "works" accidentally most of the time, but it can cause us to read garbage if the second ctx came from an hctx with more ctx's than the first one (i.e., if ctx->index_hw[hctx->type] > hctx->nr_ctx).
This manifested as this UBSAN array index out of bounds error reported by Jakub:
UBSAN: array-index-out-of-bounds in ../kernel/locking/qspinlock.c:130:9 index 13106 is out of range for type 'long unsigned int [128]' Call Trace: dump_stack+0xa4/0xe5 ubsan_epilogue+0x5/0x40 __ubsan_handle_out_of_bounds.cold.13+0x2a/0x34 queued_spin_lock_slowpath+0x476/0x480 do_raw_spin_lock+0x1c2/0x1d0 kyber_bio_merge+0x112/0x180 blk_mq_submit_bio+0x1f5/0x1100 submit_bio_noacct+0x7b0/0x870 submit_bio+0xc2/0x3a0 btrfs_map_bio+0x4f0/0x9d0 btrfs_submit_data_bio+0x24e/0x310 submit_one_bio+0x7f/0xb0 submit_extent_page+0xc4/0x440 __extent_writepage_io+0x2b8/0x5e0 __extent_writepage+0x28d/0x6e0 extent_write_cache_pages+0x4d7/0x7a0 extent_writepages+0xa2/0x110 do_writepages+0x8f/0x180 __writeback_single_inode+0x99/0x7f0 writeback_sb_inodes+0x34e/0x790 __writeback_inodes_wb+0x9e/0x120 wb_writeback+0x4d2/0x660 wb_workfn+0x64d/0xa10 process_one_work+0x53a/0xa80 worker_thread+0x69/0x5b0 kthread+0x20b/0x240 ret_from_fork+0x1f/0x30
Only Kyber uses the hctx, so fix it by passing the request_queue to ->bio_merge() instead. BFQ and mq-deadline just use that, and Kyber can map the queues itself to avoid the mismatch.
--- block/bfq-iosched.c | 3 +-- block/blk-mq-sched.c | 8 +++++--- block/kyber-iosched.c | 5 +++-- block/mq-deadline.c | 3 +-- include/linux/elevator.h | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-)
block/bfq-iosched.c +1 -2
@@ -2210,10 +2210,9 @@ static void bfq_remove_request(struct request_queue *q, } -static bool bfq_bio_merge (struct blk_mq_hw_ctx *hctx,struct bio *bio, +static bool bfq_bio_merge (struct request_queue *q,struct bio *bio,unsigned int nr_segs) { -struct request_queue *q = hctx->queue;struct bfq_data *bfqd = q->elevator->elevator_data;struct request *free =NULL ;/*
block/blk-mq-sched.c +5 -3
@@ -348,14 +348,16 @@ bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio, unsigned int nr_segs) {struct elevator_queue *e = q->elevator; -struct blk_mq_ctx *ctx =blk_mq_get_ctx (q); -struct blk_mq_hw_ctx *hctx =blk_mq_map_queue (q, bio->bi_opf, ctx); +struct blk_mq_ctx *ctx; +struct blk_mq_hw_ctx *hctx;bool ret = false;enum hctx_type type;if (e && e->type->ops.bio_merge) -return e->type->ops.bio_merge (hctx, bio, nr_segs); +return e->type->ops.bio_merge (q, bio, nr_segs); + ctx =blk_mq_get_ctx (q); + hctx =blk_mq_map_queue (q, bio->bi_opf, ctx); type = hctx->type;if (!(hctx->flags &BLK_MQ_F_SHOULD_MERGE ) ||list_empty_careful (&ctx->rq_lists[type]))
block/kyber-iosched.c +3 -2
@@ -562,11 +562,12 @@ static void kyber_limit_depth(unsigned int op, struct blk_mq_alloc_data *data) } } -static bool kyber_bio_merge (struct blk_mq_hw_ctx *hctx,struct bio *bio, +static bool kyber_bio_merge (struct request_queue *q,struct bio *bio,unsigned int nr_segs) { +struct blk_mq_ctx *ctx =blk_mq_get_ctx (q); +struct blk_mq_hw_ctx *hctx =blk_mq_map_queue (q, bio->bi_opf, ctx);struct kyber_hctx_data *khd = hctx->sched_data; -struct blk_mq_ctx *ctx =blk_mq_get_ctx (hctx->queue);struct kyber_ctx_queue *kcq = &khd->kcqs[ctx->index_hw[hctx->type]];unsigned int sched_domain =kyber_sched_domain (bio->bi_opf);struct list_head *rq_list = &kcq->rq_list[sched_domain];
block/mq-deadline.c +1 -2
@@ -461,10 +461,9 @@ static int dd_request_merge(struct request_queue *q, struct request **rq,return ELEVATOR_NO_MERGE ; } -static bool dd_bio_merge (struct blk_mq_hw_ctx *hctx,struct bio *bio, +static bool dd_bio_merge (struct request_queue *q,struct bio *bio,unsigned int nr_segs) { -struct request_queue *q = hctx->queue;struct deadline_data *dd = q->elevator->elevator_data;struct request *free =NULL ;bool ret;
include/linux/elevator.h +1 -1
@@ -34,7 +34,7 @@ struct elevator_mq_ops {void (*depth_updated)(struct blk_mq_hw_ctx *);bool (*allow_merge)(struct request_queue *,struct request *,struct bio *); -bool (*bio_merge)(struct blk_mq_hw_ctx *,struct bio *,unsigned int ); +bool (*bio_merge)(struct request_queue *,struct bio *,unsigned int );int (*request_merge)(struct request_queue *q,struct request **,struct bio *);void (*request_merged)(struct request_queue *,struct request *,enum elv_merge );void (*requests_merged)(struct request_queue *,struct request *,struct request *);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 271/329 nvmet: add lba to sect conversion helpers
In reply to Greg Kroah-HartmanFrom: Chaitanya Kulkarni <[email protected]>
[ Upstream commit 193fcf371f9e3705c14a0bf1d4bfc44af0f7c124 ]
In this preparation patch, we add helpers to convert lbas to sectors & sectors to lba. This is needed to eliminate code duplication in the ZBD backend.
Use these helpers in the block device backend.
--- drivers/nvme/target/io-cmd-bdev.c | 8 +++----- drivers/nvme/target/nvmet.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-)
drivers/nvme/target/io-cmd-bdev.c +3 -5
@@ -256,8 +256,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)if (is_pci_p2pdma_page (sg_page (req->sg))) op |=REQ_NOMERGE ; - sector =le64_to_cpu (req->cmd->rw.slba); - sector <<= (req->ns->blksize_shift -9 ); + sector =nvmet_lba_to_sect (req->ns, req->cmd->rw.slba);if (req->transfer_len <=NVMET_MAX_INLINE_DATA_LEN ) { bio = &req->b.inline_bio;
@@ -345,7 +344,7 @@ static u16 nvmet_bdev_discard_range(struct nvmet_req *req,int ret; ret =__blkdev_issue_discard (ns->bdev, -le64_to_cpu (range->slba) << (ns->blksize_shift -9 ), +nvmet_lba_to_sect (ns, range->slba),le32_to_cpu (range->nlb) << (ns->blksize_shift -9 ),GFP_KERNEL ,0 , bio);if (ret && ret != -EOPNOTSUPP ) {
@@ -414,8 +413,7 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)if (!nvmet_check_transfer_len (req,0 ))return ; - sector =le64_to_cpu (write_zeroes->slba) << - (req->ns->blksize_shift -9 ); + sector =nvmet_lba_to_sect (req->ns, write_zeroes->slba); nr_sector = (((sector_t )le16_to_cpu (write_zeroes->length) +1 ) << (req->ns->blksize_shift -9 ));
drivers/nvme/target/nvmet.h +10 -0
@@ -603,4 +603,14 @@ static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns) return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple); } +static inline __le64 nvmet_sect_to_lba (struct nvmet_ns *ns,sector_t sect) +{ +return cpu_to_le64 (sect >> (ns->blksize_shift -SECTOR_SHIFT )); +} + +static inline sector_t nvmet_lba_to_sect (struct nvmet_ns *ns,__le64 lba) +{ +return le64_to_cpu (lba) << (ns->blksize_shift -SECTOR_SHIFT ); +} +#endif /* _NVMET_H */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 272/329 nvmet: fix inline bio check for bdev-ns
In reply to Greg Kroah-HartmanFrom: Chaitanya Kulkarni <[email protected]>
[ Upstream commit 608a969046e6e0567d05a166be66c77d2dd8220b ]
When handling rw commands, for inline bio case we only consider transfer size. This works well when req->sg_cnt fits into the req->inline_bvec, but it will result in the warning in __bio_add_page() when req->sg_cnt > NVMET_MAX_INLINE_BVEC.
Consider an I/O size 32768 and first page is not aligned to the page boundary, then I/O is split in following manner :-
[ 2206.256140] nvmet: sg->length 3440 sg->offset 656 [ 2206.256144] nvmet: sg->length 4096 sg->offset 0 [ 2206.256148] nvmet: sg->length 4096 sg->offset 0 [ 2206.256152] nvmet: sg->length 4096 sg->offset 0 [ 2206.256155] nvmet: sg->length 4096 sg->offset 0 [ 2206.256159] nvmet: sg->length 4096 sg->offset 0 [ 2206.256163] nvmet: sg->length 4096 sg->offset 0 [ 2206.256166] nvmet: sg->length 4096 sg->offset 0 [ 2206.256170] nvmet: sg->length 656 sg->offset 0
Now the req->transfer_size == NVMET_MAX_INLINE_DATA_LEN i.e. 32768, but the req->sg_cnt is (9) > NVMET_MAX_INLINE_BIOVEC which is (8). This will result in the following warning message :-
nvmet_bdev_execute_rw()
bio_add_page() __bio_add_page() WARN_ON_ONCE(bio_full(bio, len));
This scenario is very hard to reproduce on the nvme-loop transport only with rw commands issued with the passthru IOCTL interface from the host application and the data buffer is allocated with the malloc() and not the posix_memalign().
--- drivers/nvme/target/io-cmd-bdev.c | 2 +- drivers/nvme/target/nvmet.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-)
drivers/nvme/target/io-cmd-bdev.c +1 -1
@@ -258,7 +258,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) sector =nvmet_lba_to_sect (req->ns, req->cmd->rw.slba); -if (req->transfer_len <=NVMET_MAX_INLINE_DATA_LEN ) { +if (nvmet_use_inline_bvec (req)) { bio = &req->b.inline_bio;bio_init (bio, req->inline_bvec,ARRAY_SIZE (req->inline_bvec)); }else {
drivers/nvme/target/nvmet.h +6 -0
@@ -613,4 +613,10 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba) return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT); } +static inline bool nvmet_use_inline_bvec (struct nvmet_req *req) +{ +return req->transfer_len <=NVMET_MAX_INLINE_DATA_LEN && + req->sg_cnt <=NVMET_MAX_INLINE_BIOVEC ; +} +#endif /* _NVMET_H */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 273/329 nvmet: fix inline bio check for passthru
In reply to Greg Kroah-HartmanFrom: Chaitanya Kulkarni <[email protected]>
[ Upstream commit ab96de5def854d8fc51280b6a20597e64b14ac31 ]
When handling passthru commands, for inline bio allocation we only consider the transfer size. This works well when req->sg_cnt fits into the req->inline_bvec, but it will result in the early return from bio_add_hw_page() when req->sg_cnt > NVMET_MAX_INLINE_BVEC.
Consider an I/O of size 32768 and first buffer is not aligned to the page boundary, then I/O is split in following manner :-
[ 2206.256140] nvmet: sg->length 3440 sg->offset 656 [ 2206.256144] nvmet: sg->length 4096 sg->offset 0 [ 2206.256148] nvmet: sg->length 4096 sg->offset 0 [ 2206.256152] nvmet: sg->length 4096 sg->offset 0 [ 2206.256155] nvmet: sg->length 4096 sg->offset 0 [ 2206.256159] nvmet: sg->length 4096 sg->offset 0 [ 2206.256163] nvmet: sg->length 4096 sg->offset 0 [ 2206.256166] nvmet: sg->length 4096 sg->offset 0 [ 2206.256170] nvmet: sg->length 656 sg->offset 0
Now the req->transfer_size == NVMET_MAX_INLINE_DATA_LEN i.e. 32768, but the req->sg_cnt is (9) > NVMET_MAX_INLINE_BIOVEC which is (8). This will result in early return in the following code path :-
nvmet_bdev_execute_rw()
bio_add_pc_page() bio_add_hw_page() if (bio_full(bio, len)) return 0;
Use previously introduced helper nvmet_use_inline_bvec() to consider req->sg_cnt when using inline bio. This only affects nvme-loop transport.
--- drivers/nvme/target/passthru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/target/passthru.c +1 -1
@@ -194,7 +194,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)if (req->sg_cnt >BIO_MAX_PAGES )return -EINVAL ; -if (req->transfer_len <=NVMET_MAX_INLINE_DATA_LEN ) { +if (nvmet_use_inline_bvec (req)) { bio = &req->p.inline_bio;bio_init (bio, req->inline_bvec,ARRAY_SIZE (req->inline_bvec)); }else {
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 274/329 nvmet-rdma: Fix NULL deref when SEND is completed with error
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit 8cc365f9559b86802afc0208389f5c8d46b4ad61 ]
When running some traffic and taking down the link on peer, a retry counter exceeded error is received. This leads to nvmet_rdma_error_comp which tried accessing the cq_context to obtain the queue. The cq_context is no longer valid after the fix to use shared CQ mechanism and should be obtained similar to how it is obtained in other functions from the wc->qp.
[ 905.786331] nvmet_rdma: SEND for CQE 0x00000000e3337f90 failed with status transport retry counter exceeded (12). [ 905.832048] BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 [ 905.839919] PGD 0 P4D 0 [ 905.842464] Oops: 0000 1 SMP NOPTI [ 905.846144] CPU: 13 PID: 1557 Comm: kworker/13:1H Kdump: loaded Tainted: G OE --------- - - 4.18.0-304.el8.x86_64 #1 [ 905.872135] RIP: 0010:nvmet_rdma_error_comp+0x5/0x1b [nvmet_rdma] [ 905.878259] Code: 19 4f c0 e8 89 b3 a5 f6 e9 5b e0 ff ff 0f b7 75 14 4c 89 ea 48 c7 c7 08 1a 4f c0 e8 71 b3 a5 f6 e9 4b e0 ff ff 0f 1f 44 00 00 <48> 8b 47 48 48 85 c0 74 08 48 89 c7 e9 98 bf 49 00 e9 c3 e3 ff ff [ 905.897135] RSP: 0018:ffffab601c45fe28 EFLAGS: 00010246 [ 905.902387] RAX: 0000000000000065 RBX: ffff9e729ea2f800 RCX: 0000000000000000 [ 905.909558] RDX: 0000000000000000 RSI: ffff9e72df9567c8 RDI: 0000000000000000 [ 905.916731] RBP: ffff9e729ea2b400 R08: 000000000000074d R09: 0000000000000074 [ 905.923903] R10: 0000000000000000 R11: ffffab601c45fcc0 R12: 0000000000000010 [ 905.931074] R13: 0000000000000000 R14: 0000000000000010 R15: ffff9e729ea2f400 [ 905.938247] FS: 0000000000000000(0000) GS:ffff9e72df940000(0000) knlGS:0000000000000000 [ 905.938249] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 905.950067] nvmet_rdma: SEND for CQE 0x00000000c7356cca failed with status transport retry counter exceeded (12). [ 905.961855] CR2: 0000000000000048 CR3: 000000678d010004 CR4: 00000000007706e0 [ 905.961855] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 905.961856] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 905.961857] PKRU: 55555554 [ 906.010315] Call Trace: [ 906.012778] __ib_process_cq+0x89/0x170 [ib_core] [ 906.017509] ib_cq_poll_work+0x26/0x80 [ib_core] [ 906.022152] process_one_work+0x1a7/0x360 [ 906.026182] ? create_worker+0x1a0/0x1a0 [ 906.030123] worker_thread+0x30/0x390 [ 906.033802] ? create_worker+0x1a0/0x1a0 [ 906.037744] kthread+0x116/0x130 [ 906.040988] ? kthread_flush_work_fn+0x10/0x10 [ 906.045456] ret_from_fork+0x1f/0x40
--- drivers/nvme/target/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/nvme/target/rdma.c +2 -2
@@ -700,7 +700,7 @@ static void nvmet_rdma_send_done(struct ib_cq *cq, struct ib_wc *wc) {struct nvmet_rdma_rsp *rsp = container_of(wc->wr_cqe, struct nvmet_rdma_rsp, send_cqe); -struct nvmet_rdma_queue *queue = cq->cq_context; +struct nvmet_rdma_queue *queue = wc->qp->qp_context;nvmet_rdma_release_rsp (rsp);
@@ -786,7 +786,7 @@ static void nvmet_rdma_write_data_done(struct ib_cq *cq, struct ib_wc *wc) {struct nvmet_rdma_rsp *rsp = container_of(wc->wr_cqe, struct nvmet_rdma_rsp, write_cqe); -struct nvmet_rdma_queue *queue = cq->cq_context; +struct nvmet_rdma_queue *queue = wc->qp->qp_context;struct rdma_cm_id *cm_id = rsp->queue->cm_id;u16 status;
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 275/329 f2fs: compress: fix to free compress page correctly
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
[ Upstream commit a12cc5b423d4f36dc1a1ea3911e49cf9dff43898 ]
In error path of f2fs_write_compressed_pages(), it needs to call f2fs_compress_free_page() to release temporary page.
--- fs/f2fs/compress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/f2fs/compress.c +2 -1
@@ -1343,7 +1343,8 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,for (i =0 ; i < cc->nr_cpages; i++) {if (!cc->cpages[i])continue ; -f2fs_put_page (cc->cpages[i],1 ); +f2fs_compress_free_page (cc->cpages[i]); + cc->cpages[i] =NULL ; } out_put_cic:kmem_cache_free (cic_entry_slab, cic);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 276/329 f2fs: compress: fix race condition of overwrite vs truncate
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
[ Upstream commit a949dc5f2c5cfe0c910b664650f45371254c0744 ]
pos_fsstress testcase complains a panic as belew:
------------[ cut here ]------------ kernel BUG at fs/f2fs/compress.c:1082! invalid opcode: 0000 [#1] SMP PTI CPU: 4 PID: 2753477 Comm: kworker/u16:2 Tainted: G OE 5.12.0-rc1-custom #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 Workqueue: writeback wb_workfn (flush-252:16) RIP: 0010:prepare_compress_overwrite+0x4c0/0x760 [f2fs] Call Trace: f2fs_prepare_compress_overwrite+0x5f/0x80 [f2fs] f2fs_write_cache_pages+0x468/0x8a0 [f2fs] f2fs_write_data_pages+0x2a4/0x2f0 [f2fs] do_writepages+0x38/0xc0 __writeback_single_inode+0x44/0x2a0 writeback_sb_inodes+0x223/0x4d0 __writeback_inodes_wb+0x56/0xf0 wb_writeback+0x1dd/0x290 wb_workfn+0x309/0x500 process_one_work+0x220/0x3c0 worker_thread+0x53/0x420 kthread+0x12f/0x150 ret_from_fork+0x22/0x30
The root cause is truncate() may race with overwrite as below, so that one reference count left in page can not guarantee the page attaching in mapping tree all the time, after truncation, later find_lock_page() may return NULL pointer.
- prepare_compress_overwrite
- f2fs_pagecache_get_page
- unlock_page
- f2fs_setattr
- truncate_setsize
- truncate_inode_page
- delete_from_page_cache
- find_lock_page
Fix this by avoiding referencing updated page.
--- fs/f2fs/compress.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-)
fs/f2fs/compress.c +12 -23
@@ -123,19 +123,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)f2fs_drop_rpages (cc, len, true); } -static void f2fs_put_rpages_mapping (struct address_space *mapping, -pgoff_t start,int len) -{ -int i; - -for (i =0 ; i < len; i++) { -struct page *page =find_get_page (mapping, start + i); - -put_page (page); -put_page (page); - } -} -static void f2fs_put_rpages_wbc (struct compress_ctx *cc,struct writeback_control *wbc,bool redirty,int unlock) {
@@ -1008,7 +995,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, }if (PageUptodate (page)) -unlock_page (page); +f2fs_put_page (page,1 );else f2fs_compress_ctx_add_page (cc, page); }
@@ -1018,32 +1005,34 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, ret =f2fs_read_multi_pages (cc, &bio, cc->cluster_size, &last_block_in_bio, false, true); +f2fs_put_rpages (cc);f2fs_destroy_compress_ctx (cc);if (ret) - goto release_pages; + goto out;if (bio)f2fs_submit_bio (sbi, bio,DATA ); ret =f2fs_init_compress_ctx (cc);if (ret) - goto release_pages; + goto out; }for (i =0 ; i < cc->cluster_size; i++) {f2fs_bug_on (sbi, cc->rpages[i]); page =find_lock_page (mapping, start_idx + i); -f2fs_bug_on (sbi, !page); +if (!page) { +/* page can be truncated */ + goto release_and_retry; + }f2fs_wait_on_page_writeback (page,DATA , true, true); -f2fs_compress_ctx_add_page (cc, page); -f2fs_put_page (page,0 );if (!PageUptodate (page)) { +release_and_retry: +f2fs_put_rpages (cc);f2fs_unlock_rpages (cc, i +1 ); -f2fs_put_rpages_mapping (mapping, start_idx, - cc->cluster_size);f2fs_destroy_compress_ctx (cc); goto retry; }
@@ -1075,10 +1064,10 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, } unlock_pages: +f2fs_put_rpages (cc);f2fs_unlock_rpages (cc, i); -release_pages: -f2fs_put_rpages_mapping (mapping, start_idx, i);f2fs_destroy_compress_ctx (cc); +out:return ret; }
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 277/329 f2fs: compress: fix to assign cc.cluster_idx correctly
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
[ Upstream commit 8bfbfb0ddd706b1ce2e89259ecc45f192c0ec2bf ]
In f2fs_destroy_compress_ctx(), after f2fs_destroy_compress_ctx(), cc.cluster_idx will be cleared w/ NULL_CLUSTER, f2fs_cluster_blocks() may check wrong cluster metadata, fix it.
--- fs/f2fs/compress.c | 17 +++++++++-------- fs/f2fs/data.c | 6 +++--- fs/f2fs/f2fs.h | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-)
fs/f2fs/compress.c +9 -8
@@ -151,13 +151,14 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc)return cc->rpages ?0 : -ENOMEM ; } -void f2fs_destroy_compress_ctx (struct compress_ctx *cc) +void f2fs_destroy_compress_ctx (struct compress_ctx *cc,bool reuse) {page_array_free (cc->inode, cc->rpages, cc->cluster_size); cc->rpages =NULL ; cc->nr_rpages =0 ; cc->nr_cpages =0 ; - cc->cluster_idx =NULL_CLUSTER ; +if (!reuse) + cc->cluster_idx =NULL_CLUSTER ; }void f2fs_compress_ctx_add_page (struct compress_ctx *cc,struct page *page)
@@ -1006,7 +1007,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, ret =f2fs_read_multi_pages (cc, &bio, cc->cluster_size, &last_block_in_bio, false, true);f2fs_put_rpages (cc); -f2fs_destroy_compress_ctx (cc); +f2fs_destroy_compress_ctx (cc, true);if (ret) goto out;if (bio)
@@ -1033,7 +1034,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, release_and_retry:f2fs_put_rpages (cc);f2fs_unlock_rpages (cc, i +1 ); -f2fs_destroy_compress_ctx (cc); +f2fs_destroy_compress_ctx (cc, true); goto retry; } }
@@ -1066,7 +1067,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, unlock_pages:f2fs_put_rpages (cc);f2fs_unlock_rpages (cc, i); -f2fs_destroy_compress_ctx (cc); +f2fs_destroy_compress_ctx (cc, true); out:return ret; }
@@ -1102,7 +1103,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,set_cluster_dirty (&cc);f2fs_put_rpages_wbc (&cc,NULL , false,1 ); -f2fs_destroy_compress_ctx (&cc); +f2fs_destroy_compress_ctx (&cc, false);return first_index; }
@@ -1321,7 +1322,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,f2fs_put_rpages (cc);page_array_free (cc->inode, cc->cpages, cc->nr_cpages); cc->cpages =NULL ; -f2fs_destroy_compress_ctx (cc); +f2fs_destroy_compress_ctx (cc, false);return 0 ; out_destroy_crypt:
@@ -1483,7 +1484,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc, err =f2fs_write_raw_pages (cc, submitted, wbc, io_type);f2fs_put_rpages_wbc (cc, wbc, false,0 ); destroy_out: -f2fs_destroy_compress_ctx (cc); +f2fs_destroy_compress_ctx (cc, false);return err; }
fs/f2fs/data.c +3 -3
@@ -2405,7 +2405,7 @@ static int f2fs_mpage_readpages(struct inode *inode, max_nr_pages, &last_block_in_bio, rac != NULL, false); -f2fs_destroy_compress_ctx (&cc); +f2fs_destroy_compress_ctx (&cc, false);if (ret) goto set_error_page; }
@@ -2450,7 +2450,7 @@ static int f2fs_mpage_readpages(struct inode *inode, max_nr_pages, &last_block_in_bio, rac != NULL, false); - f2fs_destroy_compress_ctx(&cc); + f2fs_destroy_compress_ctx(&cc, false); } }#endif
@@ -3154,7 +3154,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping, } }if (f2fs_compressed_file (inode)) -f2fs_destroy_compress_ctx (&cc); +f2fs_destroy_compress_ctx (&cc, false);#endif if (retry) { index =0 ;
fs/f2fs/f2fs.h +1 -1
@@ -3894,7 +3894,7 @@ void f2fs_free_dic(struct decompress_io_ctx *dic);void f2fs_decompress_end_io (struct page **rpages,unsigned int cluster_size,bool err,bool verity);int f2fs_init_compress_ctx (struct compress_ctx *cc); -void f2fs_destroy_compress_ctx (struct compress_ctx *cc); +void f2fs_destroy_compress_ctx (struct compress_ctx *cc,bool reuse);void f2fs_init_compress_info (struct f2fs_sb_info *sbi);int f2fs_init_page_array_cache (struct f2fs_sb_info *sbi);void f2fs_destroy_page_array_cache (struct f2fs_sb_info *sbi);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 278/329 nbd: Fix NULL pointer in flush_workqueue
In reply to Greg Kroah-HartmanFrom: Sun Ke <[email protected]>
[ Upstream commit 79ebe9110fa458d58f1fceb078e2068d7ad37390 ]
Open /dev/nbdX first, the config_refs will be 1 and the pointers in nbd_device are still null. Disconnect /dev/nbdX, then reference a null recv_workq. The protection by config_refs in nbd_genl_disconnect is useless.
[ 656.366194] BUG: kernel NULL pointer dereference, address: 0000000000000020 [ 656.368943] #PF: supervisor write access in kernel mode [ 656.369844] #PF: error_code(0x0002) - not-present page [ 656.370717] PGD 10cc87067 P4D 10cc87067 PUD 1074b4067 PMD 0 [ 656.371693] Oops: 0002 [#1] SMP [ 656.372242] CPU: 5 PID: 7977 Comm: nbd-client Not tainted 5.11.0-rc5-00040-g76c057c84d28 #1 [ 656.373661] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20190727_073836-buildvm-ppc64le-16.ppc.fedoraproject.org-3.fc31 04/01/2014 [ 656.375904] RIP: 0010:mutex_lock+0x29/0x60 [ 656.376627] Code: 00 0f 1f 44 00 00 55 48 89 fd 48 83 05 6f d7 fe 08 01 e8 7a c3 ff ff 48 83 05 6a d7 fe 08 01 31 c0 65 48 8b 14 25 00 6d 01 00 <f0> 48 0f b1 55 d [ 656.378934] RSP: 0018:ffffc900005eb9b0 EFLAGS: 00010246 [ 656.379350] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 656.379915] RDX: ffff888104cf2600 RSI: ffffffffaae8f452 RDI: 0000000000000020 [ 656.380473] RBP: 0000000000000020 R08: 0000000000000000 R09: ffff88813bd6b318 [ 656.381039] R10: 00000000000000c7 R11: fefefefefefefeff R12: ffff888102710b40 [ 656.381599] R13: ffffc900005eb9e0 R14: ffffffffb2930680 R15: ffff88810770ef00 [ 656.382166] FS: 00007fdf117ebb40(0000) GS:ffff88813bd40000(0000) knlGS:0000000000000000 [ 656.382806] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 656.383261] CR2: 0000000000000020 CR3: 0000000100c84000 CR4: 00000000000006e0 [ 656.383819] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 656.384370] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 656.384927] Call Trace: [ 656.385111] flush_workqueue+0x92/0x6c0 [ 656.385395] nbd_disconnect_and_put+0x81/0xd0 [ 656.385716] nbd_genl_disconnect+0x125/0x2a0 [ 656.386034] genl_family_rcv_msg_doit.isra.0+0x102/0x1b0 [ 656.386422] genl_rcv_msg+0xfc/0x2b0 [ 656.386685] ? nbd_ioctl+0x490/0x490 [ 656.386954] ? genl_family_rcv_msg_doit.isra.0+0x1b0/0x1b0 [ 656.387354] netlink_rcv_skb+0x62/0x180 [ 656.387638] genl_rcv+0x34/0x60 [ 656.387874] netlink_unicast+0x26d/0x590 [ 656.388162] netlink_sendmsg+0x398/0x6c0 [ 656.388451] ? netlink_rcv_skb+0x180/0x180 [ 656.388750] ____sys_sendmsg+0x1da/0x320 [ 656.389038] ? ____sys_recvmsg+0x130/0x220 [ 656.389334] ___sys_sendmsg+0x8e/0xf0 [ 656.389605] ? ___sys_recvmsg+0xa2/0xf0 [ 656.389889] ? handle_mm_fault+0x1671/0x21d0 [ 656.390201] __sys_sendmsg+0x6d/0xe0 [ 656.390464] __x64_sys_sendmsg+0x23/0x30 [ 656.390751] do_syscall_64+0x45/0x70 [ 656.391017] entry_SYSCALL_64_after_hwframe+0x44/0xa9
To fix it, just add if (nbd->recv_workq) to nbd_disconnect_and_put().
--- drivers/block/nbd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/block/nbd.c +2 -1
@@ -2000,7 +2000,8 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)* config ref and try to destroy the workqueue from inside the work * queue. */ -flush_workqueue (nbd->recv_workq); +if (nbd->recv_workq) +flush_workqueue (nbd->recv_workq);if (test_and_clear_bit (NBD_RT_HAS_CONFIG_REF , &nbd->config->runtime_flags))nbd_config_put (nbd);
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 279/329 blk-mq: plug request for shared sbitmap
In reply to Greg Kroah-HartmanFrom: Ming Lei <[email protected]>
[ Upstream commit 03f26d8f11403295de445b6e4e0e57ac57755791 ]
In case of shared sbitmap, request won't be held in plug list any more sine commit 32bc15afed04 ("blk-mq: Facilitate a shared sbitmap per tagset"), this way makes request merge from flush plug list & batching submission not possible, so cause performance regression.
Yanhui reports performance regression when running sequential IO test(libaio, 16 jobs, 8 depth for each job) in VM, and the VM disk is emulated with image stored on xfs/megaraid_sas.
Fix the issue by recovering original behavior to allow to hold request in plug list.
--- block/blk-mq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
block/blk-mq.c +3 -2
@@ -2189,8 +2189,9 @@ blk_qc_t blk_mq_submit_bio(struct bio *bio)/* Bypass scheduler for flush requests */ blk_insert_flush (rq);blk_mq_run_hw_queue (data.hctx, true); - }else if (plug && (q->nr_hw_queues ==1 || q->mq_ops->commit_rqs || - !blk_queue_nonrot (q))) { + }else if (plug && (q->nr_hw_queues ==1 || +blk_mq_is_sbitmap_shared (rq->mq_hctx->flags) || + q->mq_ops->commit_rqs || !blk_queue_nonrot (q))) {/* * Use plugging if we have a ->commit_rqs() hook as well, as * we know the driver uses bd->last in a smart fashion.
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 280/329 blk-mq: Swap two calls in blk_mq_exit_queue()
In reply to Greg Kroah-HartmanFrom: Bart Van Assche <[email protected]>
[ Upstream commit 630ef623ed26c18a457cdc070cf24014e50129c2 ]
If a tag set is shared across request queues (e.g. SCSI LUNs) then the block layer core keeps track of the number of active request queues in tags->active_queues. blk_mq_tag_busy() and blk_mq_tag_idle() update that atomic counter if the hctx flag BLK_MQ_F_TAG_QUEUE_SHARED is set. Make sure that blk_mq_exit_queue() calls blk_mq_tag_idle() before that flag is cleared by blk_mq_del_queue_tag_set().
--- block/blk-mq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
block/blk-mq.c +4 -2
@@ -3244,10 +3244,12 @@ EXPORT_SYMBOL(blk_mq_init_allocated_queue);/* tags can _not_ be used after returning from blk_mq_exit_queue */ void blk_mq_exit_queue (struct request_queue *q) { -struct blk_mq_tag_set *set = q->tag_set; +struct blk_mq_tag_set *set = q->tag_set; -blk_mq_del_queue_tag_set (q); +/* Checks hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED. */ blk_mq_exit_hw_queues (q, set, set->nr_hw_queues); +/* May clear BLK_MQ_F_TAG_QUEUE_SHARED in hctx->flags. */ +blk_mq_del_queue_tag_set (q); }static int __blk_mq_alloc_rq_maps (struct blk_mq_tag_set *set)
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerPATCH 281/329 usb: dwc3: omap: improve extcon initialization
In reply to Greg Kroah-HartmanFrom: Marcel Hamer <[email protected]>
commit e17b02d4970913233d543c79c9c66e72cac05bdd upstream.
When extcon is used in combination with dwc3, it is assumed that the dwc3 registers are untouched and as such are only configured if VBUS is valid or ID is tied to ground.
In case VBUS is not valid or ID is floating, the registers are not configured as such during driver initialization, causing a wrong default state during boot.
If the registers are not in a default state, because they are for instance touched by a boot loader, this can cause for a kernel error.
--- drivers/usb/dwc3/dwc3-omap.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/usb/dwc3/dwc3-omap.c +5 -0
@@ -437,8 +437,13 @@ static int dwc3_omap_extcon_register(strif (extcon_get_state (edev,EXTCON_USB ) == true)dwc3_omap_set_mailbox (omap,OMAP_DWC3_VBUS_VALID ); +else +dwc3_omap_set_mailbox (omap,OMAP_DWC3_VBUS_OFF ); +if (extcon_get_state (edev,EXTCON_USB_HOST ) == true)dwc3_omap_set_mailbox (omap,OMAP_DWC3_ID_GROUND ); +else +dwc3_omap_set_mailbox (omap,OMAP_DWC3_ID_FLOAT ); omap->edev = edev; }
Greg Kroah-Hartman
maintainerPATCH 282/329 usb: dwc3: pci: Enable usb2-gadget-lpm-disable for Intel Merrifield
In reply to Greg Kroah-HartmanFrom: Ferry Toth <[email protected]>
commit 04357fafea9c7ed34525eb9680c760245c3bb958 upstream.
On Intel Merrifield LPM is causing host to reset port after a timeout. By disabling LPM entirely this is prevented.
--- drivers/usb/dwc3/dwc3-pci.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/dwc3/dwc3-pci.c +1 -0
@@ -120,6 +120,7 @@ static const struct property_entry dwc3_PROPERTY_ENTRY_STRING ("linux,extcon-name" ,"mrfld_bcove_pwrsrc" ),PROPERTY_ENTRY_BOOL ("snps,dis_u3_susphy_quirk" ),PROPERTY_ENTRY_BOOL ("snps,dis_u2_susphy_quirk" ), +PROPERTY_ENTRY_BOOL ("snps,usb2-gadget-lpm-disable" ), PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), {} };
Greg Kroah-Hartman
maintainerPATCH 283/329 usb: xhci: Increase timeout for HC halt
In reply to Greg Kroah-HartmanFrom: Maximilian Luz <[email protected]>
commit ca09b1bea63ab83f4cca3a2ae8bc4f597ec28851 upstream.
On some devices (specifically the SC8180x based Surface Pro X with QCOM04A6) HC halt / xhci_halt() times out during boot. Manually binding the xhci-hcd driver at some point later does not exhibit this behavior. To work around this, double XHCI_MAX_HALT_USEC, which also resolves this issue.
--- drivers/usb/host/xhci-ext-caps.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/usb/host/xhci-ext-caps.h +3 -2
@@ -7,8 +7,9 @@* Author: Sarah Sharp * Some code borrowed from the Linux EHCI driver. */ -/* Up to 16 ms to halt an HC */ -#define XHCI_MAX_HALT_USEC (16*1000) + +/* HC should halt within 16 ms, but use 32 ms as some hosts take longer */ +#define XHCI_MAX_HALT_USEC (32 * 1000)/* HC not running - set to 1 when run/stop bit is cleared. */ #define XHCI_STS_HALT (1<<0)
Greg Kroah-Hartman
maintainerPATCH 284/329 usb: dwc2: Fix gadget DMA unmap direction
In reply to Greg Kroah-HartmanFrom: Phil Elwell <[email protected]>
commit 75a41ce46bae6cbe7d3bb2584eb844291d642874 upstream.
The dwc2 gadget support maps and unmaps DMA buffers as necessary. When mapping and unmapping it uses the direction of the endpoint to select the direction of the DMA transfer, but this fails for Control OUT transfers because the unmap occurs after the endpoint direction has been reversed for the status phase.
A possible solution would be to unmap the buffer before the direction is changed, but a safer, less invasive fix is to remember the buffer direction independently of the endpoint direction.
--- drivers/usb/dwc2/core.h | 2 ++ drivers/usb/dwc2/gadget.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/usb/dwc2/core.h +2 -0
@@ -112,6 +112,7 @@ struct dwc2_hsotg_req;* @debugfs: File entry for debugfs file for this endpoint. * @dir_in: Set to true if this endpoint is of the IN direction, which * means that it is sending data to the Host. +* @map_dir: Set to the value of dir_in when the DMA buffer is mapped. * @index: The index for the endpoint registers. * @mc: Multi Count - number of transactions per microframe * @interval: Interval for periodic endpoints, in frames or microframes.
@@ -161,6 +162,7 @@ struct dwc2_hsotg_ep {unsigned short fifo_index;unsigned char dir_in; +unsigned char map_dir;unsigned char index;unsigned char mc;u16 interval;
drivers/usb/dwc2/gadget.c +2 -1
@@ -422,7 +422,7 @@ static void dwc2_hsotg_unmap_dma(struct {struct usb_request *req = &hs_req->req; -usb_gadget_unmap_request (&hsotg->gadget, req, hs_ep->dir_in); +usb_gadget_unmap_request (&hsotg->gadget, req, hs_ep->map_dir); }/*
@@ -1242,6 +1242,7 @@ static int dwc2_hsotg_map_dma(struct dwc {int ret; + hs_ep->map_dir = hs_ep->dir_in; ret =usb_gadget_map_request (&hsotg->gadget, req, hs_ep->dir_in);if (ret) goto dma_error;
Greg Kroah-Hartman
maintainerPATCH 285/329 usb: core: hub: fix race condition about TRSMRCY of resume
In reply to Greg Kroah-HartmanFrom: Chunfeng Yun <[email protected]>
commit 975f94c7d6c306b833628baa9aec3f79db1eb3a1 upstream.
This may happen if the port becomes resume status exactly when usb_port_resume() gets port status, it still need provide a TRSMCRY time before access the device.
--- drivers/usb/core/hub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/usb/core/hub.c +3 -3
@@ -3593,9 +3593,6 @@ int usb_port_resume(struct usb_device *u* sequence. */ status =hub_port_status (hub, port1, &portstatus, &portchange); - -/* TRSMRCY = 10 msec */ -msleep (10 ); } SuspendCleared:
@@ -3610,6 +3607,9 @@ int usb_port_resume(struct usb_device *uusb_clear_port_feature (hub->hdev, port1,USB_PORT_FEAT_C_SUSPEND ); } + +/* TRSMRCY = 10 msec */ +msleep (10 ); }if (udev->persist_enabled)
Greg Kroah-Hartman
maintainerPATCH 286/329 usb: dwc3: gadget: Enable suspend events
In reply to Greg Kroah-HartmanFrom: Jack Pham <[email protected]>
commit d1d90dd27254c44d087ad3f8b5b3e4fff0571f45 upstream.
commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler") introduced (nearly 5 years ago!) an interrupt handler for U3/L1-L2 suspend events. The problem is that these events aren't currently enabled in the DEVTEN register so the handler is never even invoked. Fix this simply by enabling the corresponding bit in dwc3_gadget_enable_irq() using the same revision check as found in the handler.
--- drivers/usb/dwc3/gadget.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/dwc3/gadget.c +4 -0
@@ -2206,6 +2206,10 @@ static void dwc3_gadget_enable_irq(struc if (DWC3_VER_IS_PRIOR(DWC3, 250A)) reg |=DWC3_DEVTEN_ULSTCNGEN ; +/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */ + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + reg |=DWC3_DEVTEN_EOPFEN ; +dwc3_writel (dwc->regs,DWC3_DEVTEN , reg); }
Greg Kroah-Hartman
maintainerPATCH 287/329 usb: dwc3: gadget: Return success always for kick transfer in ep queue
In reply to Greg Kroah-HartmanFrom: Wesley Cheng <[email protected]>
commit 18ffa988dbae69cc6e9949cddd9606f6fe533894 upstream.
If an error is received when issuing a start or update transfer command, the error handler will stop all active requests (including the current USB request), and call dwc3_gadget_giveback() to notify function drivers of the requests which have been stopped. Avoid returning an error for kick transfer during EP queue, to remove duplicate cleanup operations on the request being queued.
--- drivers/usb/dwc3/gadget.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/dwc3/gadget.c +3 -1
@@ -1676,7 +1676,9 @@ static int __dwc3_gadget_ep_queue(struct } } -return __dwc3_gadget_kick_transfer (dep); +__dwc3_gadget_kick_transfer (dep); + +return 0 ; } static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
Greg Kroah-Hartman
maintainerPATCH 288/329 usb: typec: ucsi: Retrieve all the PDOs instead of just the first 4
In reply to Greg Kroah-HartmanFrom: Jack Pham <[email protected]>
commit 1f4642b72be79757f050924a9b9673b6a02034bc upstream.
commit 4dbc6a4ef06d ("usb: typec: ucsi: save power data objects in PD mode") introduced retrieval of the PDOs when connected to a PD-capable source. But only the first 4 PDOs are received since that is the maximum number that can be fetched at a time given the MESSAGE_IN length limitation (16 bytes). However, as per the PD spec a connected source may advertise up to a maximum of 7 PDOs.
If such a source is connected it's possible the PPM could have negotiated a power contract with one of the PDOs at index greater than 4, and would be reflected in the request data object's (RDO) object position field. This would result in an out-of-bounds access when the rdo_index() is used to index into the src_pdos array in ucsi_psy_get_voltage_now().
With the help of the UBSAN -fsanitize=array-bounds checker enabled this exact issue is revealed when connecting to a PD source adapter that advertise 5 PDOs and the PPM enters a contract having selected the 5th one.
[ 151.545106][ T70] Unexpected kernel BRK exception at EL1 [ 151.545112][ T70] Internal error: BRK handler: f2005512 [#1] PREEMPT SMP ... [ 151.545499][ T70] pc : ucsi_psy_get_prop+0x208/0x20c [ 151.545507][ T70] lr : power_supply_show_property+0xc0/0x328 ... [ 151.545542][ T70] Call trace: [ 151.545544][ T70] ucsi_psy_get_prop+0x208/0x20c [ 151.545546][ T70] power_supply_uevent+0x1a4/0x2f0 [ 151.545550][ T70] dev_uevent+0x200/0x384 [ 151.545555][ T70] kobject_uevent_env+0x1d4/0x7e8 [ 151.545557][ T70] power_supply_changed_work+0x174/0x31c [ 151.545562][ T70] process_one_work+0x244/0x6f0 [ 151.545564][ T70] worker_thread+0x3e0/0xa64
We can resolve this by instead retrieving and storing up to the maximum of 7 PDOs in the con->src_pdos array. This would involve two calls to the GET_PDOS command.
--- drivers/usb/typec/ucsi/ucsi.c | 41 ++++++++++++++++++++++++++++++++--------- drivers/usb/typec/ucsi/ucsi.h | 6 ++++-- 2 files changed, 36 insertions(+), 11 deletions(-)
drivers/usb/typec/ucsi/ucsi.c +32 -9
@@ -495,7 +495,8 @@ static void ucsi_unregister_altmodes(str } } -static void ucsi_get_pdos (struct ucsi_connector *con,int is_partner) +static int ucsi_get_pdos (struct ucsi_connector *con,int is_partner, +u32 *pdos,int offset,int num_pdos) {struct ucsi *ucsi = con->ucsi;u64 command;
@@ -503,17 +504,39 @@ static void ucsi_get_pdos(struct ucsi_co command =UCSI_COMMAND (UCSI_GET_PDOS ) |UCSI_CONNECTOR_NUMBER (con->num); command |=UCSI_GET_PDOS_PARTNER_PDO (is_partner); - command |=UCSI_GET_PDOS_NUM_PDOS (UCSI_MAX_PDOS -1 ); + command |=UCSI_GET_PDOS_PDO_OFFSET (offset); + command |=UCSI_GET_PDOS_NUM_PDOS (num_pdos -1 ); command |=UCSI_GET_PDOS_SRC_PDOS ; - ret =ucsi_send_command (ucsi, command, con->src_pdos, -sizeof (con->src_pdos)); -if (ret <0 ) { + ret =ucsi_send_command (ucsi, command, pdos + offset, + num_pdos *sizeof (u32)); +if (ret <0 )dev_err (ucsi->dev,"UCSI_GET_PDOS failed (%d)\n" , ret); +if (ret ==0 && offset ==0 ) +dev_warn (ucsi->dev,"UCSI_GET_PDOS returned 0 bytes\n" ); + +return ret; +} + +static void ucsi_get_src_pdos (struct ucsi_connector *con,int is_partner) +{ +int ret; + +/* UCSI max payload means only getting at most 4 PDOs at a time */ + ret =ucsi_get_pdos (con,1 , con->src_pdos,0 ,UCSI_MAX_PDOS ); +if (ret <0 )return ; - } + con->num_pdos = ret /sizeof (u32);/* number of bytes to 32-bit PDOs */ -if (ret ==0 ) -dev_warn (ucsi->dev,"UCSI_GET_PDOS returned 0 bytes\n" ); +if (con->num_pdos <UCSI_MAX_PDOS ) +return ; + +/* get the remaining PDOs, if any */ + ret =ucsi_get_pdos (con,1 , con->src_pdos,UCSI_MAX_PDOS , +PDO_MAX_OBJECTS -UCSI_MAX_PDOS ); +if (ret <0 ) +return ; + + con->num_pdos += ret /sizeof (u32); }static void ucsi_pwr_opmode_change (struct ucsi_connector *con)
@@ -522,7 +545,7 @@ static void ucsi_pwr_opmode_change(struccase UCSI_CONSTAT_PWR_OPMODE_PD : con->rdo = con->status.request_data_obj;typec_set_pwr_opmode (con->port,TYPEC_PWR_MODE_PD ); -ucsi_get_pdos (con,1 ); +ucsi_get_src_pdos (con,1 );break ;case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 : con->rdo =0 ;
drivers/usb/typec/ucsi/ucsi.h +4 -2
@@ -8,6 +8,7 @@#include <linux/power_supply.h> #include <linux/types.h> #include <linux/usb/typec.h> +#include <linux/usb/pd.h> /* -------------------------------------------------------------------------- */
@@ -133,7 +134,9 @@ void ucsi_connector_change(struct ucsi */* GET_PDOS command bits */ #define UCSI_GET_PDOS_PARTNER_PDO (_r_) ((u64)(_r_) << 23) +#define UCSI_GET_PDOS_PDO_OFFSET (_r_) ((u64)(_r_) << 24)#define UCSI_GET_PDOS_NUM_PDOS (_r_) ((u64)(_r_) << 32) +#define UCSI_MAX_PDOS (4)#define UCSI_GET_PDOS_SRC_PDOS ((u64)1 << 34)/* -------------------------------------------------------------------------- */
@@ -301,7 +304,6 @@ struct ucsi {#define UCSI_MAX_SVID 5#define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) -#define UCSI_MAX_PDOS (4)#define UCSI_TYPEC_VSAFE5V 5000#define UCSI_TYPEC_1_5_CURRENT 1500
@@ -329,7 +331,7 @@ struct ucsi_connector {struct power_supply *psy;struct power_supply_desc psy_desc;u32 rdo; -u32 src_pdos[UCSI_MAX_PDOS ]; +u32 src_pdos[PDO_MAX_OBJECTS ];int num_pdos; };
Greg Kroah-Hartman
maintainerPATCH 289/329 usb: typec: ucsi: Put fwnode in any case during ->probe()
In reply to Greg Kroah-HartmanFrom: Andy Shevchenko <[email protected]>
commit b9a0866a5bdf6a4643a52872ada6be6184c6f4f2 upstream.
device_for_each_child_node() bumps a reference counting of a returned variable. We have to balance it whenever we return to the caller.
--- drivers/usb/typec/ucsi/ucsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/usb/typec/ucsi/ucsi.c +4 -1
@@ -995,6 +995,7 @@ static const struct typec_operations ucs .pr_set = ucsi_pr_swap }; +/* Caller must call fwnode_handle_put() after use */ static struct fwnode_handle *ucsi_find_fwnode (struct ucsi_connector *con) {struct fwnode_handle *fwnode;
@@ -1028,7 +1029,7 @@ static int ucsi_register_port(struct ucs command |=UCSI_CONNECTOR_NUMBER (con->num); ret =ucsi_send_command (ucsi, command, &con->cap,sizeof (con->cap));if (ret <0 ) - goto out; + goto out_unlock;if (con->cap.op_mode &UCSI_CONCAP_OPMODE_DRP ) cap->data =TYPEC_PORT_DRD ;
@@ -1124,6 +1125,8 @@ static int ucsi_register_port(struct ucstrace_ucsi_register_port (con->num, &con->status); out: +fwnode_handle_put (cap->fwnode); +out_unlock:mutex_unlock (&con->lock);return ret; }
Greg Kroah-Hartman
maintainerPATCH 290/329 xhci-pci: Allow host runtime PM as default for Intel Alder Lake xHCI
In reply to Greg Kroah-HartmanFrom: Abhijeet Rao <[email protected]>
commit b813511135e8b84fa741afdfbab4937919100bef upstream.
In the same way as Intel Tiger Lake TCSS (Type-C Subsystem) the Alder Lake TCSS xHCI needs to be runtime suspended whenever possible to allow the TCSS hardware block to enter D3cold and thus save energy.
--- drivers/usb/host/xhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/host/xhci-pci.c +3 -1
@@ -57,6 +57,7 @@#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI 0x461e#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
@@ -243,7 +244,8 @@ static void xhci_pci_quirks(struct devic pdev->device ==PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI || pdev->device ==PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI || pdev->device ==PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI)) + pdev->device ==PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI)) xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
Greg Kroah-Hartman
maintainerPATCH 291/329 xhci: Do not use GFP_KERNEL in (potentially) atomic context
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
commit dda32c00c9a0fa103b5d54ef72c477b7aa993679 upstream.
'xhci_urb_enqueue()' is passed a 'mem_flags' argument, because "URBs may be submitted in interrupt context" (see comment related to 'usb_submit_urb()' in 'drivers/usb/core/urb.c')
So this flag should be used in all the calling chain. Up to now, 'xhci_check_maxpacket()' which is only called from 'xhci_urb_enqueue()', uses GFP_KERNEL.
Be safe and pass the mem_flags to this function as well.
--- drivers/usb/host/xhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/usb/host/xhci.c +3 -3
@@ -1523,7 +1523,7 @@ static int xhci_configure_endpoint(struc* we need to issue an evaluate context command and wait on it. */ static int xhci_check_maxpacket (struct xhci_hcd *xhci,unsigned int slot_id, -unsigned int ep_index,struct urb *urb) +unsigned int ep_index,struct urb *urb,gfp_t mem_flags) {struct xhci_container_ctx *out_ctx;struct xhci_input_control_ctx *ctrl_ctx;
@@ -1554,7 +1554,7 @@ static int xhci_check_maxpacket(struct x* changes max packet sizes. */ - command =xhci_alloc_command (xhci, true,GFP_KERNEL ); + command =xhci_alloc_command (xhci, true, mem_flags);if (!command)return -ENOMEM ;
@@ -1648,7 +1648,7 @@ static int xhci_urb_enqueue(struct usb_h*/ if (urb->dev->speed ==USB_SPEED_FULL ) { ret =xhci_check_maxpacket (xhci, slot_id, - ep_index, urb); + ep_index, urb, mem_flags);if (ret <0 ) {xhci_urb_free_priv (urb_priv); urb->hcpriv =NULL ;
Greg Kroah-Hartman
maintainerPATCH 292/329 xhci: Add reset resume quirk for AMD xhci controller.
In reply to Greg Kroah-HartmanFrom: Sandeep Singh <[email protected]>
commit 3c128781d8da463761495aaf8898c9ecb4e71528 upstream.
One of AMD xhci controller require reset on resume. Occasionally AMD xhci controller does not respond to Stop endpoint command.
Once the issue happens controller goes into bad state and in that case controller needs to be reset.
--- drivers/usb/host/xhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/host/xhci-pci.c +3 -1
@@ -167,8 +167,10 @@ static void xhci_pci_quirks(struct devic (pdev->device == 0x15e0 || pdev->device == 0x15e1)) xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND; -if (pdev->vendor ==PCI_VENDOR_ID_AMD && pdev->device ==0x15e5 ) +if (pdev->vendor ==PCI_VENDOR_ID_AMD && pdev->device ==0x15e5 ) { xhci->quirks |=XHCI_DISABLE_SPARSE ; + xhci->quirks |=XHCI_RESET_ON_RESUME ; + }if (pdev->vendor ==PCI_VENDOR_ID_AMD ) xhci->quirks |=XHCI_TRUST_TX_LENGTH ;
Greg Kroah-Hartman
maintainerPATCH 293/329 iio: core: fix ioctl handlers removal
In reply to Greg Kroah-HartmanFrom: Tomasz Duszynski <[email protected]>
commit 901f84de0e16bde10a72d7eb2f2eb73fcde8fa1a upstream.
Currently ioctl handlers are removed twice. For the first time during iio_device_unregister() then later on inside iio_device_unregister_eventset() and iio_buffers_free_sysfs_and_mask(). Double free leads to kernel panic.
Fix this by not touching ioctl handlers list directly but rather letting code responsible for registration call the matching cleanup routine itself.
--- drivers/iio/industrialio-core.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/iio/industrialio-core.c +0 -6
@@ -1827,9 +1827,6 @@ EXPORT_SYMBOL(__iio_device_register);**/ void iio_device_unregister (struct iio_dev *indio_dev) { -struct iio_dev_opaque *iio_dev_opaque =to_iio_dev_opaque (indio_dev); -struct iio_ioctl_handler *h, *t; -cdev_device_del (&indio_dev->chrdev, &indio_dev->dev);mutex_lock (&indio_dev->info_exist_lock);
@@ -1840,9 +1837,6 @@ void iio_device_unregister(struct iio_de indio_dev->info =NULL ; -list_for_each_entry_safe (h, t, &iio_dev_opaque->ioctl_handlers, entry) -list_del (&h->entry); -iio_device_wakeup_eventset (indio_dev);iio_buffer_wakeup_poll (indio_dev);
Greg Kroah-Hartman
maintainerPATCH 294/329 iio: gyro: mpu3050: Fix reported temperature value
In reply to Greg Kroah-HartmanFrom: Dmitry Osipenko <[email protected]>
commit f73c730774d88a14d7b60feee6d0e13570f99499 upstream.
The raw temperature value is a 16-bit signed integer. The sign casting is missing in the code, which results in a wrong temperature reported by userspace tools, fix it.
Datasheet: https://www.cdiweb.com/datasheets/invensense/mpu-3000a.pdf
--- drivers/iio/gyro/mpu3050-core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/iio/gyro/mpu3050-core.c +11 -2
@@ -272,7 +272,16 @@ static int mpu3050_read_raw(struct iio_dcase IIO_CHAN_INFO_OFFSET :switch (chan->type) {case IIO_TEMP : -/* The temperature scaling is (x+23000)/280 Celsius */ +/* +* The temperature scaling is (x+23000)/280 Celsius +* for the "best fit straight line" temperature range +* of -30C..85C. The 23000 includes room temperature +* offset of +35C, 280 is the precision scale and x is +* the 16-bit signed integer reported by hardware. +* +* Temperature value itself represents temperature of +* the sensor die. +*/ *val =23000 ;return IIO_VAL_INT ;default :
@@ -329,7 +338,7 @@ static int mpu3050_read_raw(struct iio_d goto out_read_raw_unlock; } - *val =be16_to_cpu (raw_val); + *val = (s16 )be16_to_cpu (raw_val); ret =IIO_VAL_INT ; goto out_read_raw_unlock;
Greg Kroah-Hartman
maintainerPATCH 295/329 iio: tsl2583: Fix division by a zero lux_val
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
commit af0e1871d79cfbb91f732d2c6fa7558e45c31038 upstream.
The lux_val returned from tsl2583_get_lux can potentially be zero, so check for this to avoid a division by zero and an overflowed gain_trim_val.
Fixes clang scan-build warning:
drivers/iio/light/tsl2583.c:345:40: warning: Either the condition 'lux_val<0' is redundant or there is division by zero at line 345. [zerodivcond]
--- drivers/iio/light/tsl2583.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/iio/light/tsl2583.c +8 -0
@@ -341,6 +341,14 @@ static int tsl2583_als_calibrate(structreturn lux_val; } +/* Avoid division by zero of lux_value later on */ +if (lux_val ==0 ) { +dev_err (&chip->client->dev, +"%s: lux_val of 0 will produce out of range trim_value\n" , + __func__); +return -ENODATA ; + } + gain_trim_val = (unsigned int )(((chip->als_settings.als_cal_target) * chip->als_settings.als_gain_trim) / lux_val);if ((gain_trim_val <250 ) || (gain_trim_val >4000 )) {
Greg Kroah-Hartman
maintainerPATCH 296/329 cdc-wdm: untangle a circular dependency between callback and softint
In reply to Greg Kroah-HartmanFrom: Oliver Neukum <[email protected]>
commit 18abf874367456540846319574864e6ff32752e2 upstream.
We have a cycle of callbacks scheduling works which submit URBs with those callbacks. This needs to be blocked, stopped and unblocked to untangle the circle.
--- drivers/usb/class/cdc-wdm.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
drivers/usb/class/cdc-wdm.c +22 -8
@@ -321,12 +321,23 @@ exit: } -static void kill_urbs (struct wdm_device *desc) +static void poison_urbs (struct wdm_device *desc) {/* the order here is essential */ -usb_kill_urb (desc->command); -usb_kill_urb (desc->validity); -usb_kill_urb (desc->response); +usb_poison_urb (desc->command); +usb_poison_urb (desc->validity); +usb_poison_urb (desc->response); +} + +static void unpoison_urbs (struct wdm_device *desc) +{ +/* +* the order here is not essential +* it is symmetrical just to be nice +*/ +usb_unpoison_urb (desc->response); +usb_unpoison_urb (desc->validity); +usb_unpoison_urb (desc->command); }static void free_urbs (struct wdm_device *desc)
@@ -741,11 +752,12 @@ static int wdm_release(struct inode *inoif (!desc->count) {if (!test_bit (WDM_DISCONNECTING , &desc->flags)) {dev_dbg (&desc->intf->dev,"wdm_release: cleanup\n" ); -kill_urbs (desc); +poison_urbs (desc);spin_lock_irq (&desc->iuspin); desc->resp_count =0 ;spin_unlock_irq (&desc->iuspin); desc->manage_power (desc->intf,0 ); +unpoison_urbs (desc); }else {/* must avoid dev_printk here as desc->intf is invalid */ pr_debug (KBUILD_MODNAME " %s: device gone - cleaning up\n" , __func__);
@@ -1037,9 +1049,9 @@ static void wdm_disconnect(struct usb_inwake_up_all (&desc->wait);mutex_lock (&desc->rlock);mutex_lock (&desc->wlock); +poison_urbs (desc);cancel_work_sync (&desc->rxwork);cancel_work_sync (&desc->service_outs_intr); -kill_urbs (desc);mutex_unlock (&desc->wlock);mutex_unlock (&desc->rlock);
@@ -1080,9 +1092,10 @@ static int wdm_suspend(struct usb_interfset_bit (WDM_SUSPENDING , &desc->flags);spin_unlock_irq (&desc->iuspin);/* callback submits work - order is essential */ -kill_urbs (desc); +poison_urbs (desc);cancel_work_sync (&desc->rxwork);cancel_work_sync (&desc->service_outs_intr); +unpoison_urbs (desc); }if (!PMSG_IS_AUTO (message)) {mutex_unlock (&desc->wlock);
@@ -1140,7 +1153,7 @@ static int wdm_pre_reset(struct usb_intewake_up_all (&desc->wait);mutex_lock (&desc->rlock);mutex_lock (&desc->wlock); -kill_urbs (desc); +poison_urbs (desc);cancel_work_sync (&desc->rxwork);cancel_work_sync (&desc->service_outs_intr);return 0 ;
@@ -1151,6 +1164,7 @@ static int wdm_post_reset(struct usb_intstruct wdm_device *desc =wdm_find_device (intf);int rv; +unpoison_urbs (desc);clear_bit (WDM_OVERFLOW , &desc->flags);clear_bit (WDM_RESETTING , &desc->flags); rv =recover_from_urb_loss (desc);
Greg Kroah-Hartman
maintainerPATCH 297/329 xen/gntdev: fix gntdev_mmap() error exit path
In reply to Greg Kroah-HartmanFrom: Juergen Gross <[email protected]>
commit 970655aa9b42461f8394e4457307005bdeee14d9 upstream.
Commit d3eeb1d77c5d0af ("xen/gntdev: use mmu_interval_notifier_insert") introduced an error in gntdev_mmap(): in case the call of mmu_interval_notifier_insert_locked() fails the exit path should not call mmu_interval_notifier_remove(), as this might result in NULL dereferences.
One reason for failure is e.g. a signal pending for the running process.
--- drivers/xen/gntdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/xen/gntdev.c +3 -1
@@ -1005,8 +1005,10 @@ static int gntdev_mmap(struct file *flip err =mmu_interval_notifier_insert_locked ( &map->notifier, vma->vm_mm, vma->vm_start, vma->vm_end - vma->vm_start, &gntdev_mmu_ops); -if (err) +if (err) { + map->vma =NULL ; goto out_unlock_put; + } }mutex_unlock (&priv->lock);