5.10.121-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 299/452 ASoC: atmel-classd: Remove endianness flag on class d component
In reply to Greg Kroah-HartmanFrom: Charles Keepax <[email protected]>
[ Upstream commit 0104d52a6a69b06b0e8167f7c1247e8c76aca070 ]
The endianness flag should have been removed when the driver was ported across from having both a CODEC and CPU side component, to just having a CPU component and using the dummy for the CODEC. The endianness flag is used to indicate that the device is completely ambivalent to the endianness of the data, typically due to the endianness being lost over the hardware link (ie. the link defines bit ordering). It's usage didn't have any effect when the driver had both a CPU and CODEC component, since the union of those equals the CPU side settings, but now causes the driver to falsely report it supports big endian. Correct this by removing the flag.
--- sound/soc/atmel/atmel-classd.c | 1 - 1 file changed, 1 deletion(-)
sound/soc/atmel/atmel-classd.c +0 -1
@@ -458,7 +458,6 @@ static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = { .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, };/* ASoC sound card */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 300/452 proc: fix dentry/inode overinstantiating under /proc/${pid}/net
In reply to Greg Kroah-HartmanFrom: Alexey Dobriyan <[email protected]>
[ Upstream commit 7055197705709c59b8ab77e6a5c7d46d61edd96e ]
When a process exits, /proc/${pid}, and /proc/${pid}/net dentries are flushed. However some leaf dentries like /proc/${pid}/net/arp_cache aren't. That's because respective PDEs have proc_misc_d_revalidate() hook which returns 1 and leaves dentries/inodes in the LRU.
Force revalidation/lookup on everything under /proc/${pid}/net by inheriting proc_net_dentry_ops.
--- fs/proc/generic.c | 3 +++ fs/proc/proc_net.c | 3 +++ 2 files changed, 6 insertions(+)
fs/proc/generic.c +3 -0
@@ -453,6 +453,9 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,proc_set_user (ent, (*parent)->uid, (*parent)->gid); ent->proc_dops = &proc_misc_dentry_ops; +/* Revalidate everything under /proc/${pid}/net */ +if ((*parent)->proc_dops == &proc_net_dentry_ops) +pde_force_lookup (ent); out:return ent;
fs/proc/proc_net.c +3 -0
@@ -362,6 +362,9 @@ static __net_init int proc_net_ns_init(struct net *net)proc_set_user (netd, uid, gid); +/* Seed dentry revalidation for /proc/${pid}/net */ +pde_force_lookup (netd); + err = -EEXIST ; net_statd =proc_net_mkdir (net,"stat" , netd);if (!net_statd)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 301/452 ipc/mqueue: use get_tree_nodev() in mqueue_get_tree()
In reply to Greg Kroah-HartmanFrom: Waiman Long <[email protected]>
[ Upstream commit d60c4d01a98bc1942dba6e3adc02031f5519f94b ]
When running the stress-ng clone benchmark with multiple testing threads, it was found that there were significant spinlock contention in sget_fc(). The contended spinlock was the sb_lock. It is under heavy contention because the following code in the critcal section of sget_fc():
hlist_for_each_entry(old, &fc->fs_type->fs_supers, s_instances) {
if (test(old, fc))
goto share_extant_sb;
}After testing with added instrumentation code, it was found that the benchmark could generate thousands of ipc namespaces with the corresponding number of entries in the mqueue's fs_supers list where the namespaces are the key for the search. This leads to excessive time in scanning the list for a match.
Looking back at the mqueue calling sequence leading to sget_fc():
mq_init_ns()
=> mq_create_mount()
=> fc_mount()
=> vfs_get_tree()
=> mqueue_get_tree()
=> get_tree_keyed()
=> vfs_get_super()
=> sget_fc()
Currently, mq_init_ns() is the only mqueue function that will indirectly call mqueue_get_tree() with a newly allocated ipc namespace as the key for searching. As a result, there will never be a match with the exising ipc namespaces stored in the mqueue's fs_supers list.
So using get_tree_keyed() to do an existing ipc namespace search is just a waste of time. Instead, we could use get_tree_nodev() to eliminate the useless search. By doing so, we can greatly reduce the sb_lock hold time and avoid the spinlock contention problem in case a large number of ipc namespaces are present.
Of course, if the code is modified in the future to allow mqueue_get_tree() to be called with an existing ipc namespace instead of a new one, we will have to use get_tree_keyed() in this case.
The following stress-ng clone benchmark command was run on a 2-socket 48-core Intel system:
./stress-ng --clone 32 --verbose --oomable --metrics-brief -t 20
The "bogo ops/s" increased from 5948.45 before patch to 9137.06 after patch. This is an increase of 54% in performance.
--- ipc/mqueue.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
ipc/mqueue.c +14 -0
@@ -45,6 +45,7 @@struct mqueue_fs_context {struct ipc_namespace *ipc_ns; +bool newns;/* Set if newly created ipc namespace */ };#define MQUEUE_MAGIC 0x19800202
@@ -424,6 +425,14 @@ static int mqueue_get_tree(struct fs_context *fc) {struct mqueue_fs_context *ctx = fc->fs_private; +/* +* With a newly created ipc namespace, we don't need to do a search +* for an ipc namespace match, but we still need to set s_fs_info. +*/ +if (ctx->newns) { + fc->s_fs_info = ctx->ipc_ns; +return get_tree_nodev (fc, mqueue_fill_super); + }return get_tree_keyed (fc, mqueue_fill_super, ctx->ipc_ns); }
@@ -451,6 +460,10 @@ static int mqueue_init_fs_context(struct fs_context *fc)return 0 ; } +/* +* mq_init_ns() is currently the only caller of mq_create_mount(). +* So the ns parameter is always a newly created ipc namespace. +*/ static struct vfsmount *mq_create_mount (struct ipc_namespace *ns) {struct mqueue_fs_context *ctx;
@@ -462,6 +475,7 @@ static struct vfsmount *mq_create_mount(struct ipc_namespace *ns)return ERR_CAST (fc); ctx = fc->fs_private; + ctx->newns = true;put_ipc_ns (ctx->ipc_ns); ctx->ipc_ns =get_ipc_ns (ns);put_user_ns (fc->user_ns);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 302/452 PCI: imx6: Fix PERST# start-up sequence
In reply to Greg Kroah-HartmanFrom: Francesco Dolcini <[email protected]>
[ Upstream commit a6809941c1f17f455db2cf4ca19c6d8c8746ec25 ]
According to the PCIe standard the PERST# signal (reset-gpio in fsl,imx* compatible dts) should be kept asserted for at least 100 usec before the PCIe refclock is stable, should be kept asserted for at least 100 msec after the power rails are stable and the host should wait at least 100 msec after it is de-asserted before accessing the configuration space of any attached device.
Quoted 1 line
From PCIe CEM r2.0, sec 2.6.2
T-PVPERL: Power stable to PERST# inactive - 100 msec
T-PERST-CLK: REFCLK stable before PERST# inactive - 100 usec.
Quoted 1 line
From PCIe r5.0, sec 6.6.1
With a Downstream Port that does not support Link speeds greater than 5.0 GT/s, software must wait a minimum of 100 ms before sending a Configuration Request to the device immediately below that Port.
Failure to do so could prevent PCIe devices to be working correctly, and this was experienced with real devices.
Move reset assert to imx6_pcie_assert_core_reset(), this way we ensure that PERST# is asserted before enabling any clock, move de-assert to the end of imx6_pcie_deassert_core_reset() after the clock is enabled and deemed stable and add a new delay of 100 msec just afterward.
--- drivers/pci/controller/dwc/pci-imx6.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/pci/controller/dwc/pci-imx6.c +14 -9
@@ -401,6 +401,11 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)dev_err (dev,"failed to disable vpcie regulator: %d\n" , ret); } + +/* Some boards don't have PCIe reset GPIO. */ +if (gpio_is_valid (imx6_pcie->reset_gpio)) +gpio_set_value_cansleep (imx6_pcie->reset_gpio, + imx6_pcie->gpio_active_high); }static unsigned int imx6_pcie_grp_offset (const struct imx6_pcie *imx6_pcie)
@@ -523,15 +528,6 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)/* allow the clocks to stabilize */ usleep_range (200 ,500 ); -/* Some boards don't have PCIe reset GPIO. */ -if (gpio_is_valid (imx6_pcie->reset_gpio)) { -gpio_set_value_cansleep (imx6_pcie->reset_gpio, - imx6_pcie->gpio_active_high); -msleep (100 ); -gpio_set_value_cansleep (imx6_pcie->reset_gpio, - !imx6_pcie->gpio_active_high); - } -switch (imx6_pcie->drvdata->variant) {case IMX8MQ :reset_control_deassert (imx6_pcie->pciephy_reset);
@@ -574,6 +570,15 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)break ; } +/* Some boards don't have PCIe reset GPIO. */ +if (gpio_is_valid (imx6_pcie->reset_gpio)) { +msleep (100 ); +gpio_set_value_cansleep (imx6_pcie->reset_gpio, + !imx6_pcie->gpio_active_high); +/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ +msleep (100 ); + } +return ; err_ref_clk:
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 303/452 tty: fix deadlock caused by calling printk() under tty_port->lock
In reply to Greg Kroah-HartmanFrom: Qi Zheng <[email protected]>
[ Upstream commit 6b9dbedbe3499fef862c4dff5217cf91f34e43b3 ]
pty_write() invokes kmalloc() which may invoke a normal printk() to print failure message. This can cause a deadlock in the scenario reported by syz-bot below:
CPU0 CPU1 CPU2
---- ---- ----
lock(console_owner);
lock(&port_lock_key);
lock(&port->lock);
lock(&port_lock_key);
lock(&port->lock); lock(console_owner);
As commit dbdda842fe96 ("printk: Add console owner and waiter logic to load balance console writes") said, such deadlock can be prevented by using printk_deferred() in kmalloc() (which is invoked in the section guarded by the port->lock). But there are too many printk() on the kmalloc() path, and kmalloc() can be called from anywhere, so changing printk() to printk_deferred() is too complicated and inelegant.
Therefore, this patch chooses to specify __GFP_NOWARN to kmalloc(), so that printk() will not be called, and this deadlock problem can be avoided.
Syzbot reported the following lockdep error:
======================================================
WARNING: possible circular locking dependency detected
5.4.143-00237-g08ccc19a-dirty #10 Not tainted
------------------------------------------------------
syz-executor.4/29420 is trying to acquire lock:ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: console_trylock_spinning kernel/printk/printk.c:1752 [inline] ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: vprintk_emit+0x2ca/0x470 kernel/printk/printk.c:2023
but task is already holding lock:ffff8880119c9158 (&port->lock){-.-.}-{2:2}, at: pty_write+0xf4/0x1f0 drivers/tty/pty.c:120
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (&port->lock){-.-.}-{2:2}:
__raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
_raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
tty_port_tty_get drivers/tty/tty_port.c:288 [inline] <-- lock(&port->lock);
tty_port_default_wakeup+0x1d/0xb0 drivers/tty/tty_port.c:47
serial8250_tx_chars+0x530/0xa80 drivers/tty/serial/8250/8250_port.c:1767
serial8250_handle_irq.part.0+0x31f/0x3d0 drivers/tty/serial/8250/8250_port.c:1854
serial8250_handle_irq drivers/tty/serial/8250/8250_port.c:1827 [inline] <-- lock(&port_lock_key);
serial8250_default_handle_irq+0xb2/0x220 drivers/tty/serial/8250/8250_port.c:1870
serial8250_interrupt+0xfd/0x200 drivers/tty/serial/8250/8250_core.c:126
__handle_irq_event_percpu+0x109/0xa50 kernel/irq/handle.c:156
[...]-> #1 (&port_lock_key){-.-.}-{2:2}:
__raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
_raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
serial8250_console_write+0x184/0xa40 drivers/tty/serial/8250/8250_port.c:3198
<-- lock(&port_lock_key);
call_console_drivers kernel/printk/printk.c:1819 [inline]
console_unlock+0x8cb/0xd00 kernel/printk/printk.c:2504
vprintk_emit+0x1b5/0x470 kernel/printk/printk.c:2024 <-- lock(console_owner);
vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
printk+0xba/0xed kernel/printk/printk.c:2084
register_console+0x8b3/0xc10 kernel/printk/printk.c:2829
univ8250_console_init+0x3a/0x46 drivers/tty/serial/8250/8250_core.c:681
console_init+0x49d/0x6d3 kernel/printk/printk.c:2915
start_kernel+0x5e9/0x879 init/main.c:713
secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:241-> #0 (console_owner){....}-{0:0}:
[...]
lock_acquire+0x127/0x340 kernel/locking/lockdep.c:4734
console_trylock_spinning kernel/printk/printk.c:1773 [inline] <-- lock(console_owner);
vprintk_emit+0x307/0x470 kernel/printk/printk.c:2023
vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
printk+0xba/0xed kernel/printk/printk.c:2084
fail_dump lib/fault-inject.c:45 [inline]
should_fail+0x67b/0x7c0 lib/fault-inject.c:144
__should_failslab+0x152/0x1c0 mm/failslab.c:33
should_failslab+0x5/0x10 mm/slab_common.c:1224
slab_pre_alloc_hook mm/slab.h:468 [inline]
slab_alloc_node mm/slub.c:2723 [inline]
slab_alloc mm/slub.c:2807 [inline]
__kmalloc+0x72/0x300 mm/slub.c:3871
kmalloc include/linux/slab.h:582 [inline]
tty_buffer_alloc+0x23f/0x2a0 drivers/tty/tty_buffer.c:175
__tty_buffer_request_room+0x156/0x2a0 drivers/tty/tty_buffer.c:273
tty_insert_flip_string_fixed_flag+0x93/0x250 drivers/tty/tty_buffer.c:318
tty_insert_flip_string include/linux/tty_flip.h:37 [inline]
pty_write+0x126/0x1f0 drivers/tty/pty.c:122 <-- lock(&port->lock);
n_tty_write+0xa7a/0xfc0 drivers/tty/n_tty.c:2356
do_tty_write drivers/tty/tty_io.c:961 [inline]
tty_write+0x512/0x930 drivers/tty/tty_io.c:1045
__vfs_write+0x76/0x100 fs/read_write.c:494
[...]other info that might help us debug this:
Chain exists of: console_owner --> &port_lock_key --> &port->lock
--- drivers/tty/tty_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/tty/tty_buffer.c +2 -1
@@ -172,7 +172,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)have queued and recycle that ? */ if (atomic_read (&port->buf.mem_used) > port->buf.mem_limit)return NULL ; - p =kmalloc (sizeof (struct tty_buffer ) +2 * size,GFP_ATOMIC ); + p =kmalloc (sizeof (struct tty_buffer ) +2 * size, +GFP_ATOMIC | __GFP_NOWARN);if (p ==NULL )return NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 304/452 crypto: sun8i-ss - rework handling of IV
In reply to Greg Kroah-HartmanFrom: Corentin Labbe <[email protected]>
[ Upstream commit 359e893e8af456be2fefabe851716237df289cbf ]
sun8i-ss fail handling IVs when doing decryption of multiple SGs in-place. It should backup the last block of each SG source for using it later as IVs.
In the same time remove allocation on requests path for storing all IVs.
--- .../allwinner/sun8i-ss/sun8i-ss-cipher.c | 115 ++++++++++++------ .../crypto/allwinner/sun8i-ss/sun8i-ss-core.c | 30 +++-- drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h | 14 ++- 3 files changed, 107 insertions(+), 52 deletions(-)
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +77 -38
@@ -93,6 +93,68 @@ static int sun8i_ss_cipher_fallback(struct skcipher_request *areq)return err; } +static int sun8i_ss_setup_ivs (struct skcipher_request *areq) +{ +struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (areq); +struct sun8i_cipher_tfm_ctx *op =crypto_skcipher_ctx (tfm); +struct sun8i_ss_dev *ss = op->ss; +struct sun8i_cipher_req_ctx *rctx =skcipher_request_ctx (areq); +struct scatterlist *sg = areq->src; +unsigned int todo, offset; +unsigned int len = areq->cryptlen; +unsigned int ivsize =crypto_skcipher_ivsize (tfm); +struct sun8i_ss_flow *sf = &ss->flows[rctx->flow]; +int i =0 ; +u32 a; +int err; + + rctx->ivlen = ivsize; +if (rctx->op_dir &SS_DECRYPTION ) { + offset = areq->cryptlen - ivsize; +scatterwalk_map_and_copy (sf->biv, areq->src, offset, + ivsize,0 ); + } + +/* we need to copy all IVs from source in case DMA is bi-directionnal */ +while (sg && len) { +if (sg_dma_len (sg) ==0 ) { + sg =sg_next (sg); +continue ; + } +if (i ==0 ) +memcpy (sf->iv[0 ], areq->iv, ivsize); + a =dma_map_single (ss->dev, sf->iv[i], ivsize,DMA_TO_DEVICE ); +if (dma_mapping_error (ss->dev, a)) { +memzero_explicit (sf->iv[i], ivsize); +dev_err (ss->dev,"Cannot DMA MAP IV\n" ); + err = -EFAULT ; + goto dma_iv_error; + } + rctx->p_iv[i] = a; +/* we need to setup all others IVs only in the decrypt way */ +if (rctx->op_dir &SS_ENCRYPTION ) +return 0 ; + todo =min (len,sg_dma_len (sg)); + len -= todo; + i++; +if (i <MAX_SG ) { + offset = sg->length - ivsize; +scatterwalk_map_and_copy (sf->iv[i], sg, offset, ivsize,0 ); + } + rctx->niv = i; + sg =sg_next (sg); + } + +return 0 ; +dma_iv_error: + i--; +while (i >=0 ) { +dma_unmap_single (ss->dev, rctx->p_iv[i], ivsize,DMA_TO_DEVICE ); +memzero_explicit (sf->iv[i], ivsize); + } +return err; +} +static int sun8i_ss_cipher (struct skcipher_request *areq) {struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (areq);
@@ -101,9 +163,9 @@ static int sun8i_ss_cipher(struct skcipher_request *areq)struct sun8i_cipher_req_ctx *rctx =skcipher_request_ctx (areq);struct skcipher_alg *alg =crypto_skcipher_alg (tfm);struct sun8i_ss_alg_template *algt; +struct sun8i_ss_flow *sf = &ss->flows[rctx->flow];struct scatterlist *sg;unsigned int todo, len, offset, ivsize; -void *backup_iv =NULL ;int nr_sgs =0 ;int nr_sgd =0 ;int err =0 ;
@@ -134,30 +196,9 @@ static int sun8i_ss_cipher(struct skcipher_request *areq) ivsize =crypto_skcipher_ivsize (tfm);if (areq->iv &&crypto_skcipher_ivsize (tfm) >0 ) { - rctx->ivlen = ivsize; - rctx->biv =kzalloc (ivsize,GFP_KERNEL |GFP_DMA ); -if (!rctx->biv) { - err = -ENOMEM ; + err =sun8i_ss_setup_ivs (areq); +if (err) goto theend_key; - } -if (rctx->op_dir &SS_DECRYPTION ) { - backup_iv =kzalloc (ivsize,GFP_KERNEL ); -if (!backup_iv) { - err = -ENOMEM ; - goto theend_key; - } - offset = areq->cryptlen - ivsize; -scatterwalk_map_and_copy (backup_iv, areq->src, offset, - ivsize,0 ); - } -memcpy (rctx->biv, areq->iv, ivsize); - rctx->p_iv =dma_map_single (ss->dev, rctx->biv, rctx->ivlen, -DMA_TO_DEVICE ); -if (dma_mapping_error (ss->dev, rctx->p_iv)) { -dev_err (ss->dev,"Cannot DMA MAP IV\n" ); - err = -ENOMEM ; - goto theend_iv; - } }if (areq->src == areq->dst) { nr_sgs = dma_map_sg(ss->dev, areq->src, sg_nents(areq->src),
@@ -240,21 +281,19 @@ static int sun8i_ss_cipher(struct skcipher_request *areq) } theend_iv: -if (rctx->p_iv) -dma_unmap_single (ss->dev, rctx->p_iv, rctx->ivlen, -DMA_TO_DEVICE ); -if (areq->iv && ivsize >0 ) { -if (rctx->biv) { - offset = areq->cryptlen - ivsize; -if (rctx->op_dir &SS_DECRYPTION ) { -memcpy (areq->iv, backup_iv, ivsize); -kfree_sensitive (backup_iv); - }else { -scatterwalk_map_and_copy (areq->iv, areq->dst, offset, - ivsize,0 ); - } -kfree (rctx->biv); +for (i =0 ; i < rctx->niv; i++) { +dma_unmap_single (ss->dev, rctx->p_iv[i], ivsize,DMA_TO_DEVICE ); +memzero_explicit (sf->iv[i], ivsize); + } + + offset = areq->cryptlen - ivsize; +if (rctx->op_dir &SS_DECRYPTION ) { +memcpy (areq->iv, sf->biv, ivsize); +memzero_explicit (sf->biv, ivsize); + }else { +scatterwalk_map_and_copy (areq->iv, areq->dst, offset, + ivsize,0 ); } }
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +21 -9
@@ -66,6 +66,7 @@ int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx const char *name) {int flow = rctx->flow; +unsigned int ivlen = rctx->ivlen;u32 v =SS_START ;int i;
@@ -104,15 +105,14 @@ int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctxmutex_lock (&ss->mlock);writel (rctx->p_key, ss->base +SS_KEY_ADR_REG ); -if (i ==0 ) { -if (rctx->p_iv) -writel (rctx->p_iv, ss->base +SS_IV_ADR_REG ); - }else { -if (rctx->biv) { -if (rctx->op_dir ==SS_ENCRYPTION ) -writel (rctx->t_dst[i -1 ].addr + rctx->t_dst[i -1 ].len *4 - rctx->ivlen, ss->base +SS_IV_ADR_REG ); +if (ivlen) { +if (rctx->op_dir ==SS_ENCRYPTION ) { +if (i ==0 ) +writel (rctx->p_iv[0 ], ss->base +SS_IV_ADR_REG );else -writel (rctx->t_src[i -1 ].addr + rctx->t_src[i -1 ].len *4 - rctx->ivlen, ss->base +SS_IV_ADR_REG ); +writel (rctx->t_dst[i -1 ].addr + rctx->t_dst[i -1 ].len *4 - ivlen, ss->base +SS_IV_ADR_REG ); + }else { +writel (rctx->p_iv[i], ss->base +SS_IV_ADR_REG ); } }
@@ -464,7 +464,7 @@ static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)*/ static int allocate_flows (struct sun8i_ss_dev *ss) { -int i, err; +int i, j, err; ss->flows =devm_kcalloc (ss->dev,MAXFLOW ,sizeof (struct sun8i_ss_flow ),GFP_KERNEL );
@@ -474,6 +474,18 @@ static int allocate_flows(struct sun8i_ss_dev *ss)for (i =0 ; i <MAXFLOW ; i++) {init_completion (&ss->flows[i].complete); + ss->flows[i].biv =devm_kmalloc (ss->dev,AES_BLOCK_SIZE , +GFP_KERNEL |GFP_DMA ); +if (!ss->flows[i].biv) + goto error_engine; + +for (j =0 ; j <MAX_SG ; j++) { + ss->flows[i].iv[j] =devm_kmalloc (ss->dev,AES_BLOCK_SIZE , +GFP_KERNEL |GFP_DMA ); +if (!ss->flows[i].iv[j]) + goto error_engine; + } + ss->flows[i].engine =crypto_engine_alloc_init (ss->dev, true);if (!ss->flows[i].engine) {dev_err (ss->dev,"Cannot allocate engine\n" );
drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h +9 -5
@@ -120,11 +120,15 @@ struct sginfo {* @complete: completion for the current task on this flow * @status: set to 1 by interrupt if task is done * @stat_req: number of request done by this flow +* @iv: list of IV to use for each step +* @biv: buffer which contain the backuped IV */ struct sun8i_ss_flow {struct crypto_engine *engine;struct completion complete;int status; +u8 *iv[MAX_SG ]; +u8 *biv;#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG unsigned long stat_req;#endif
@@ -163,28 +167,28 @@ struct sun8i_ss_dev {* @t_src: list of mapped SGs with their size * @t_dst: list of mapped SGs with their size * @p_key: DMA address of the key -* @p_iv: DMA address of the IV +* @p_iv: DMA address of the IVs +* @niv: Number of IVs DMA mapped * @method: current algorithm for this request * @op_mode: op_mode for this request * @op_dir: direction (encrypt vs decrypt) for this request * @flow: the flow to use for this request -* @ivlen: size of biv +* @ivlen: size of IVs * @keylen: keylen for this request -* @biv: buffer which contain the IV * @fallback_req: request struct for invoking the fallback skcipher TFM */ struct sun8i_cipher_req_ctx {struct sginfo t_src[MAX_SG ];struct sginfo t_dst[MAX_SG ];u32 p_key; -u32 p_iv; +u32 p_iv[MAX_SG ]; +int niv;u32 method;u32 op_mode;u32 op_dir;int flow;unsigned int ivlen;unsigned int keylen; -void *biv;struct skcipher_request fallback_req;// keep at the end };
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 305/452 crypto: sun8i-ss - handle zero sized sg
In reply to Greg Kroah-HartmanFrom: Corentin Labbe <[email protected]>
[ Upstream commit c149e4763d28bb4c0e5daae8a59f2c74e889f407 ]
sun8i-ss does not handle well the possible zero sized sg.
--- drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +9 -1
@@ -379,13 +379,21 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq) } len = areq->nbytes; -for_each_sg (areq->src, sg, nr_sgs, i) { + sg = areq->src; + i =0 ; +while (len >0 && sg) { +if (sg_dma_len (sg) ==0 ) { + sg =sg_next (sg); +continue ; + } rctx->t_src[i].addr =sg_dma_address (sg); todo =min (len,sg_dma_len (sg)); rctx->t_src[i].len = todo /4 ; len -= todo; rctx->t_dst[i].addr = addr_res; rctx->t_dst[i].len = digestsize /4 ; + sg =sg_next (sg); + i++; }if (len >0 ) {dev_err (ss->dev,"remaining len %d\n" , len);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 306/452 crypto: cryptd - Protect per-CPU resource by disabling BH.
In reply to Greg Kroah-HartmanFrom: Sebastian Andrzej Siewior <[email protected]>
[ Upstream commit 91e8bcd7b4da182e09ea19a2c73167345fe14c98 ]
The access to cryptd_queue::cpu_queue is synchronized by disabling preemption in cryptd_enqueue_request() and disabling BH in cryptd_queue_worker(). This implies that access is allowed from BH.
If cryptd_enqueue_request() is invoked from preemptible context _and_ soft interrupt then this can lead to list corruption since cryptd_enqueue_request() is not protected against access from soft interrupt.
Replace get_cpu() in cryptd_enqueue_request() with local_bh_disable() to ensure BH is always disabled.
Remove preempt_disable() from cryptd_queue_worker() since it is not needed because local_bh_disable() ensures synchronisation.
--- crypto/cryptd.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)
crypto/cryptd.c +11 -12
@@ -39,6 +39,10 @@ struct cryptd_cpu_queue { };struct cryptd_queue { +/* +* Protected by disabling BH to allow enqueueing from softinterrupt and +* dequeuing from kworker (cryptd_queue_worker()). +*/ struct cryptd_cpu_queue __percpu *cpu_queue; };
@@ -125,28 +129,28 @@ static void cryptd_fini_queue(struct cryptd_queue *queue)static int cryptd_enqueue_request (struct cryptd_queue *queue,struct crypto_async_request *request) { -int cpu, err; +int err;struct cryptd_cpu_queue *cpu_queue;refcount_t *refcnt; - cpu =get_cpu (); +local_bh_disable (); cpu_queue =this_cpu_ptr (queue->cpu_queue); err =crypto_enqueue_request (&cpu_queue->queue, request); refcnt =crypto_tfm_ctx (request->tfm);if (err == -ENOSPC ) - goto out_put_cpu; + goto out; -queue_work_on (cpu, cryptd_wq, &cpu_queue->work); +queue_work_on (smp_processor_id (), cryptd_wq, &cpu_queue->work);if (!refcount_read (refcnt)) - goto out_put_cpu; + goto out;refcount_inc (refcnt); -out_put_cpu: -put_cpu (); +out: +local_bh_enable ();return err; }
@@ -162,15 +166,10 @@ static void cryptd_queue_worker(struct work_struct *work) cpu_queue = container_of(work, struct cryptd_cpu_queue, work);/* * Only handle one request at a time to avoid hogging crypto workqueue. -* preempt_disable/enable is used to prevent being preempted by -* cryptd_enqueue_request(). local_bh_disable/enable is used to prevent -* cryptd_enqueue_request() being accessed from software interrupts. */ local_bh_disable (); -preempt_disable (); backlog =crypto_get_backlog (&cpu_queue->queue); req =crypto_dequeue_request (&cpu_queue->queue); -preempt_enable ();local_bh_enable ();if (!req)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 307/452 Input: sparcspkr - fix refcount leak in bbc_beep_probe
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit c8994b30d71d64d5dcc9bc0edbfdf367171aa96f ]
of_find_node_by_path() calls of_find_node_opts_by_path(), which returns a node pointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak.
--- drivers/input/misc/sparcspkr.c | 1 + 1 file changed, 1 insertion(+)
drivers/input/misc/sparcspkr.c +1 -0
@@ -205,6 +205,7 @@ static int bbc_beep_probe(struct platform_device *op) info = &state->u.bbc; info->clock_freq =of_getintprop_default (dp,"clock-frequency" ,0 ); +of_node_put (dp);if (!info->clock_freq) goto out_free;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 308/452 PCI/AER: Clear MULTI_ERR_COR/UNCOR_RCV bits
In reply to Greg Kroah-HartmanFrom: Kuppuswamy Sathyanarayanan <[email protected]>
[ Upstream commit 203926da2bff8e172200a2f11c758987af112d4a ]
When a Root Port or Root Complex Event Collector receives an error Message e.g., ERR_COR, it sets PCI_ERR_ROOT_COR_RCV in the Root Error Status register and logs the Requester ID in the Error Source Identification register. If it receives a second ERR_COR Message before software clears PCI_ERR_ROOT_COR_RCV, hardware sets PCI_ERR_ROOT_MULTI_COR_RCV and the Requester ID is lost.
In the following scenario, PCI_ERR_ROOT_MULTI_COR_RCV was never cleared:
- hardware receives ERR_COR message
- hardware sets PCI_ERR_ROOT_COR_RCV
- aer_irq() entered
- aer_irq(): status = pci_read_config_dword(PCI_ERR_ROOT_STATUS)
- aer_irq(): now status == PCI_ERR_ROOT_COR_RCV
- hardware receives second ERR_COR message
- hardware sets PCI_ERR_ROOT_MULTI_COR_RCV
- aer_irq(): pci_write_config_dword(PCI_ERR_ROOT_STATUS, status)
- PCI_ERR_ROOT_COR_RCV is cleared; PCI_ERR_ROOT_MULTI_COR_RCV is set
- aer_irq() entered again
- aer_irq(): status = pci_read_config_dword(PCI_ERR_ROOT_STATUS)
- aer_irq(): now status == PCI_ERR_ROOT_MULTI_COR_RCV
- aer_irq() exits because PCI_ERR_ROOT_COR_RCV not set
- PCI_ERR_ROOT_MULTI_COR_RCV is still set
The same problem occurred with ERR_NONFATAL/ERR_FATAL Messages and PCI_ERR_ROOT_UNCOR_RCV and PCI_ERR_ROOT_MULTI_UNCOR_RCV.
Fix the problem by queueing an AER event and clearing the Root Error Status bits when any of these bits are set:
PCI_ERR_ROOT_COR_RCV
PCI_ERR_ROOT_UNCOR_RCV
PCI_ERR_ROOT_MULTI_COR_RCV
PCI_ERR_ROOT_MULTI_UNCOR_RCV
See the bugzilla link for details from Eric about how to reproduce this problem.
--- drivers/pci/pcie/aer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/pci/pcie/aer.c +6 -1
@@ -101,6 +101,11 @@ struct aer_stats {#define ERR_COR_ID (d) (d & 0xffff)#define ERR_UNCOR_ID (d) (d >> 16) +#define AER_ERR_STATUS_MASK (PCI_ERR_ROOT_UNCOR_RCV | \ + PCI_ERR_ROOT_COR_RCV | \ + PCI_ERR_ROOT_MULTI_COR_RCV | \ + PCI_ERR_ROOT_MULTI_UNCOR_RCV) +static int pcie_aer_disable;static pci_ers_result_t aer_root_reset (struct pci_dev *dev);
@@ -1187,7 +1192,7 @@ static irqreturn_t aer_irq(int irq, void *context)struct aer_err_source e_src = {};pci_read_config_dword (rp, aer +PCI_ERR_ROOT_STATUS , &e_src.status); -if (!(e_src.status & (PCI_ERR_ROOT_UNCOR_RCV |PCI_ERR_ROOT_COR_RCV ))) +if (!(e_src.status &AER_ERR_STATUS_MASK ))return IRQ_NONE ;pci_read_config_dword (rp, aer +PCI_ERR_ROOT_ERR_SRC , &e_src.id);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 309/452 hwrng: omap3-rom - fix using wrong clk_disable() in omap_rom_rng_runtime_resume()
In reply to Greg Kroah-HartmanFrom: Yang Yingliang <[email protected]>
[ Upstream commit e4e62bbc6aba49a5edb3156ec65f6698ff37d228 ]
'ddata->clk' is enabled by clk_prepare_enable(), it should be disabled by clk_disable_unprepare().
--- drivers/char/hw_random/omap3-rom-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/hw_random/omap3-rom-rng.c +1 -1
@@ -92,7 +92,7 @@ static int __maybe_unused omap_rom_rng_runtime_resume(struct device *dev) r = ddata->rom_rng_call (0 ,0 ,RNG_GEN_PRNG_HW_INIT );if (r !=0 ) { -clk_disable (ddata->clk); +clk_disable_unprepare (ddata->clk);dev_err (dev,"HW init failed: %d\n" , r);return -EIO ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 310/452 powerpc/64: Only WARN if __pa()/__va() called with bad addresses
In reply to Greg Kroah-HartmanFrom: Michael Ellerman <[email protected]>
[ Upstream commit c4bce84d0bd3f396f702d69be2e92bbd8af97583 ]
We added checks to __pa() / __va() to ensure they're only called with appropriate addresses. But using BUG_ON() is too strong, it means virt_addr_valid() will BUG when DEBUG_VIRTUAL is enabled.
Instead switch them to warnings, arm64 does the same.
--- arch/powerpc/include/asm/page.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/page.h +5 -2
@@ -216,6 +216,9 @@ static inline bool pfn_valid(unsigned long pfn)#define __pa (x) ((phys_addr_t)(unsigned long)(x) - VIRT_PHYS_OFFSET)#else #ifdef CONFIG_PPC64 + +#define VIRTUAL_WARN_ON (x) WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && (x)) +/* * gcc miscompiles (unsigned long)(&static_var) - PAGE_OFFSET * with -mcmodel=medium, so we use & and | instead of - and + on 64-bit.
@@ -223,13 +226,13 @@ static inline bool pfn_valid(unsigned long pfn)*/ #define __va (x) \ ({ \ - VIRTUAL_BUG_ON((unsigned long)(x) >= PAGE_OFFSET); \ + VIRTUAL_WARN_ON((unsigned long)(x) >= PAGE_OFFSET); \ (void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET); \ })#define __pa (x) \ ({ \ - VIRTUAL_BUG_ON((unsigned long)(x) < PAGE_OFFSET); \ + VIRTUAL_WARN_ON((unsigned long)(x) < PAGE_OFFSET); \ (unsigned long)(x) & 0x0fffffffffffffffUL; \ })
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 311/452 powerpc/perf: Fix the threshold compare group constraint for power9
In reply to Greg Kroah-HartmanFrom: Kajol Jain <[email protected]>
[ Upstream commit ab0cc6bbf0c812731c703ec757fcc3fc3a457a34 ]
Thresh compare bits for a event is used to program thresh compare field in Monitor Mode Control Register A (MMCRA: 9-18 bits for power9). When scheduling events as a group, all events in that group should match value in threshold bits (like thresh compare, thresh control, thresh select). Otherwise event open for the sibling events should fail. But in the current code, incase thresh compare bits are not valid, we are not failing in group_constraint function which can result in invalid group schduling.
Fix the issue by returning -1 incase event is threshold and threshold compare value is not valid.
Thresh control bits in the event code is used to program thresh_ctl field in Monitor Mode Control Register A (MMCRA: 48-55). In below example, the scheduling of group events PM_MRK_INST_CMPL (873534401e0) and PM_THRESH_MET (8734340101ec) is expected to fail as both event request different thresh control bits and invalid thresh compare value.
Result before the patch changes:
[command]# perf stat -e "{r8735340401e0,r8734340101ec}" sleep 1
Performance counter stats for 'sleep 1':
11,048 r8735340401e0
1,967 r8734340101ec
1.001354036 seconds time elapsed
0.001421000 seconds user
0.000000000 seconds sysResult after the patch changes:
[command]# perf stat -e "{r8735340401e0,r8734340101ec}" sleep 1 Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (r8735340401e0)./bin/dmesg | grep -i perf may provide additional information.
--- arch/powerpc/perf/isa207-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/perf/isa207-common.c +2 -1
@@ -363,7 +363,8 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)if (event_is_threshold (event) &&is_thresh_cmp_valid (event)) { mask |=CNST_THRESH_MASK ; value |=CNST_THRESH_VAL (event >>EVENT_THRESH_SHIFT ); - } + }else if (event_is_threshold (event)) +return -1 ; }else {/* * Special case for PM_MRK_FAB_RSP_MATCH and PM_MRK_FAB_RSP_MATCH_CYC,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 312/452 macintosh: via-pmu and via-cuda need RTC_LIB
In reply to Greg Kroah-HartmanFrom: Randy Dunlap <[email protected]>
[ Upstream commit 9a9c5ff5fff87eb1a43db0d899473554e408fd7b ]
Fix build when RTC_LIB is not set/enabled.
Eliminates these build errors:
m68k-linux-ld: drivers/macintosh/via-pmu.o: in function `pmu_set_rtc_time':drivers/macintosh/via-pmu.c:1769: undefined reference to `rtc_tm_to_time64'
m68k-linux-ld: drivers/macintosh/via-cuda.o: in function `cuda_set_rtc_time':drivers/macintosh/via-cuda.c:797: undefined reference to `rtc_tm_to_time64'
--- drivers/macintosh/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
drivers/macintosh/Kconfig +2 -0
@@ -44,6 +44,7 @@ config ADB_IOP config ADB_CUDA bool "Support for Cuda/Egret based Macs and PowerMacs" depends on (ADB || PPC_PMAC) && !PPC_PMAC64 + select RTC_LIB help This provides support for Cuda/Egret based Macintosh and Power Macintosh systems. This includes most m68k based Macs,
@@ -57,6 +58,7 @@ config ADB_CUDA config ADB_PMU bool "Support for PMU based PowerMacs and PowerBooks" depends on PPC_PMAC || MAC + select RTC_LIB help On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the PMU is an embedded microprocessor whose primary function is to
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 313/452 powerpc/fsl_rio: Fix refcount leak in fsl_rio_setup
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit fcee96924ba1596ca80a6770b2567ca546f9a482 ]
of_parse_phandle() returns a node pointer with refcount incremented, we should use of_node_put() on it when not need anymore. Add missing of_node_put() to avoid refcount leak.
--- arch/powerpc/sysdev/fsl_rio.c | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/sysdev/fsl_rio.c +2 -0
@@ -505,8 +505,10 @@ int fsl_rio_setup(struct platform_device *dev)if (rc) {dev_err (&dev->dev,"Can't get %pOF property 'reg'\n" , rmu_node); +of_node_put (rmu_node); goto err_rmu; } +of_node_put (rmu_node); rmu_regs_win =ioremap (rmu_regs.start,resource_size (&rmu_regs));if (!rmu_regs_win) {dev_err (&dev->dev,"Unable to map rmu register window\n" );
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 314/452 mfd: davinci_voicecodec: Fix possible null-ptr-deref davinci_vc_probe()
In reply to Greg Kroah-HartmanFrom: Yang Yingliang <[email protected]>
[ Upstream commit 311242c7703df0da14c206260b7e855f69cb0264 ]
It will cause null-ptr-deref when using 'res', if platform_get_resource() returns NULL, so move using 'res' after devm_ioremap_resource() that will check it to avoid null-ptr-deref.
And use devm_platform_get_and_ioremap_resource() to simplify code.
--- drivers/mfd/davinci_voicecodec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/mfd/davinci_voicecodec.c +2 -4
@@ -46,14 +46,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) }clk_enable (davinci_vc->clk); - res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); - - fifo_base = (dma_addr_t )res->start; - davinci_vc->base =devm_ioremap_resource (&pdev->dev, res); + davinci_vc->base =devm_platform_get_and_ioremap_resource (pdev,0 , &res);if (IS_ERR (davinci_vc->base)) { ret =PTR_ERR (davinci_vc->base); goto fail; } + fifo_base = (dma_addr_t )res->start; davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev, davinci_vc->base,
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 315/452 mailbox: forward the hrtimer if not queued and under a lock
In reply to Greg Kroah-HartmanFrom: Björn Ardö <[email protected]>
[ Upstream commit bca1a1004615efe141fd78f360ecc48c60bc4ad5 ]
This reverts commit c7dacf5b0f32957b24ef29df1207dc2cd8307743, "mailbox: avoid timer start from callback"
The previous commit was reverted since it lead to a race that caused the hrtimer to not be started at all. The check for hrtimer_active() in msg_submit() will return true if the callback function txdone_hrtimer() is currently running. This function could return HRTIMER_NORESTART and then the timer will not be restarted, and also msg_submit() will not start the timer. This will lead to a message actually being submitted but no timer will start to check for its compleation.
The original fix that added checking hrtimer_active() was added to avoid a warning with hrtimer_forward. Looking in the kernel another solution to avoid this warning is to check hrtimer_is_queued() before calling hrtimer_forward_now() instead. This however requires a lock so the timer is not started by msg_submit() inbetween this check and the hrtimer_forward() call.
--- drivers/mailbox/mailbox.c | 19 +++++++++++++------ include/linux/mailbox_controller.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-)
drivers/mailbox/mailbox.c +13 -6
@@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan) exit:spin_unlock_irqrestore (&chan->lock, flags); -/* kick start the timer immediately to avoid delays */ if (!err && (chan->txdone_method &TXDONE_BY_POLL )) { -/* but only if not already active */ -if (!hrtimer_active (&chan->mbox->poll_hrt)) -hrtimer_start (&chan->mbox->poll_hrt,0 ,HRTIMER_MODE_REL ); +/* kick start the timer immediately to avoid delays */ +spin_lock_irqsave (&chan->mbox->poll_hrt_lock, flags); +hrtimer_start (&chan->mbox->poll_hrt,0 ,HRTIMER_MODE_REL ); +spin_unlock_irqrestore (&chan->mbox->poll_hrt_lock, flags); } }
@@ -120,20 +120,26 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) container_of(hrtimer, struct mbox_controller, poll_hrt);bool txdone, resched = false;int i; +unsigned long flags;for (i =0 ; i < mbox->num_chans; i++) {struct mbox_chan *chan = &mbox->chans[i];if (chan->active_req && chan->cl) { - resched = true; txdone = chan->mbox->ops->last_tx_done (chan);if (txdone)tx_tick (chan,0 ); +else + resched = true; } }if (resched) { -hrtimer_forward_now (hrtimer,ms_to_ktime (mbox->txpoll_period)); +spin_lock_irqsave (&mbox->poll_hrt_lock, flags); +if (!hrtimer_is_queued (hrtimer)) +hrtimer_forward_now (hrtimer,ms_to_ktime (mbox->txpoll_period)); +spin_unlock_irqrestore (&mbox->poll_hrt_lock, flags); +return HRTIMER_RESTART ; }return HRTIMER_NORESTART ;
@@ -500,6 +506,7 @@ int mbox_controller_register(struct mbox_controller *mbox)hrtimer_init (&mbox->poll_hrt,CLOCK_MONOTONIC ,HRTIMER_MODE_REL ); mbox->poll_hrt.function = txdone_hrtimer; +spin_lock_init (&mbox->poll_hrt_lock); }for (i =0 ; i < mbox->num_chans; i++) {
include/linux/mailbox_controller.h +1 -0
@@ -83,6 +83,7 @@ struct mbox_controller { const struct of_phandle_args *sp);/* Internal to API */ struct hrtimer poll_hrt; +spinlock_t poll_hrt_lock;struct list_head node; };
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 316/452 RDMA/hfi1: Prevent use of lock before it is initialized
In reply to Greg Kroah-HartmanFrom: Douglas Miller <[email protected]>
[ Upstream commit 05c03dfd09c069c4ffd783b47b2da5dcc9421f2c ]
If there is a failure during probe of hfi1 before the sdma_map_lock is initialized, the call to hfi1_free_devdata() will attempt to use a lock that has not been initialized. If the locking correctness validator is on then an INFO message and stack trace resembling the following may be seen:
INFO: trying to register non-static key.
The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator.
Call Trace: register_lock_class+0x11b/0x880 __lock_acquire+0xf3/0x7930 lock_acquire+0xff/0x2d0 _raw_spin_lock_irq+0x46/0x60 sdma_clean+0x42a/0x660 [hfi1] hfi1_free_devdata+0x3a7/0x420 [hfi1] init_one+0x867/0x11a0 [hfi1] pci_device_probe+0x40e/0x8d0
The use of sdma_map_lock in sdma_clean() is for freeing the sdma_map memory, and sdma_map is not allocated/initialized until after sdma_map_lock has been initialized. This code only needs to be run if sdma_map is not NULL, and so checking for that condition will avoid trying to use the lock before it is initialized.
--- drivers/infiniband/hw/hfi1/sdma.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/infiniband/hw/hfi1/sdma.c +7 -5
@@ -1330,11 +1330,13 @@ void sdma_clean(struct hfi1_devdata *dd, size_t num_engines)kvfree (sde->tx_ring); sde->tx_ring =NULL ; } -spin_lock_irq (&dd->sde_map_lock); -sdma_map_free (rcu_access_pointer (dd->sdma_map)); -RCU_INIT_POINTER (dd->sdma_map,NULL ); -spin_unlock_irq (&dd->sde_map_lock); -synchronize_rcu (); +if (rcu_access_pointer (dd->sdma_map)) { +spin_lock_irq (&dd->sde_map_lock); +sdma_map_free (rcu_access_pointer (dd->sdma_map)); +RCU_INIT_POINTER (dd->sdma_map,NULL ); +spin_unlock_irq (&dd->sde_map_lock); +synchronize_rcu (); + }kfree (dd->per_sdma); dd->per_sdma =NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 317/452 Input: stmfts - do not leave device disabled in stmfts_input_open
In reply to Greg Kroah-HartmanFrom: Dmitry Torokhov <[email protected]>
[ Upstream commit 5f76955ab1e43e5795a9631b22ca4f918a0ae986 ]
The commit 26623eea0da3 attempted to deal with potential leak of runtime PM counter when opening the touchscreen device, however it ended up erroneously dropping the counter in the case of successfully enabling the device.
Let's address this by using pm_runtime_resume_and_get() and then executing pm_runtime_put_sync() only when we fail to send "sense on" command to the device.
--- drivers/input/touchscreen/stmfts.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/input/touchscreen/stmfts.c +8 -8
@@ -337,13 +337,15 @@ static int stmfts_input_open(struct input_dev *dev)struct stmfts_data *sdata =input_get_drvdata (dev);int err; - err =pm_runtime_get_sync (&sdata->client->dev); -if (err <0 ) - goto out; + err =pm_runtime_resume_and_get (&sdata->client->dev); +if (err) +return err; err =i2c_smbus_write_byte (sdata->client,STMFTS_MS_MT_SENSE_ON ); -if (err) - goto out; +if (err) { +pm_runtime_put_sync (&sdata->client->dev); +return err; + }mutex_lock (&sdata->mutex); sdata->running = true;
@@ -366,9 +368,7 @@ static int stmfts_input_open(struct input_dev *dev) "failed to enable touchkey\n"); } -out: -pm_runtime_put_noidle (&sdata->client->dev); -return err; +return 0 ; }static void stmfts_input_close (struct input_dev *dev)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 318/452 OPP: call of_node_put() on error path in _bandwidth_supported()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit 907ed123b9d096c73e9361f6cd4097f0691497f2 ]
This code does not call of_node_put(opp_np) if of_get_next_available_child() returns NULL. But it should.
--- drivers/opp/of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/opp/of.c +1 -1
@@ -346,11 +346,11 @@ static int _bandwidth_supported(struct device *dev, struct opp_table *opp_table)/* Checking only first OPP is sufficient */ np =of_get_next_available_child (opp_np,NULL ); +of_node_put (opp_np);if (!np) {dev_err (dev,"OPP table empty\n" );return -EINVAL ; } -of_node_put (opp_np); prop =of_find_property (np,"opp-peak-kBps" ,NULL );of_node_put (np);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 319/452 f2fs: fix dereference of stale list iterator after loop body
In reply to Greg Kroah-HartmanFrom: Jakob Koschel <[email protected]>
[ Upstream commit 2aaf51dd39afb6d01d13f1e6fe20b684733b37d5 ]
The list iterator variable will be a bogus pointer if no break was hit. Dereferencing it (cur->page in this case) could load an out-of-bounds/undefined value making it unsafe to use that in the comparision to determine if the specific element was found.
Since 'cur->page' *can* be out-ouf-bounds it cannot be guaranteed that by chance (or intention of an attacker) it matches the value of 'page' even though the correct element was not found.
This is fixed by using a separate list iterator variable for the loop and only setting the original variable if a suitable element was found. Then determing if the element was found is simply checking if the variable is set.
--- fs/f2fs/segment.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
fs/f2fs/segment.c +6 -3
@@ -356,16 +356,19 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page)struct f2fs_sb_info *sbi =F2FS_I_SB (inode);struct list_head *head = &fi->inmem_pages;struct inmem_pages *cur =NULL ; +struct inmem_pages *tmp;f2fs_bug_on (sbi, !IS_ATOMIC_WRITTEN_PAGE (page));mutex_lock (&fi->inmem_lock); -list_for_each_entry (cur, head, list) { -if (cur->page == page) +list_for_each_entry (tmp, head, list) { +if (tmp->page == page) { + cur = tmp;break ; + } } -f2fs_bug_on (sbi,list_empty (head) || cur->page != page); +f2fs_bug_on (sbi, !cur);list_del (&cur->list);mutex_unlock (&fi->inmem_lock);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 320/452 iommu/mediatek: Add list_del in mtk_iommu_remove
In reply to Greg Kroah-HartmanFrom: Yong Wu <[email protected]>
[ Upstream commit ee55f75e4bcade81d253163641b63bef3e76cac4 ]
Lack the list_del in the mtk_iommu_remove, and remove bus_set_iommu(*, NULL) since there may be several iommu HWs. we can not bus_set_iommu null when one iommu driver unbind.
This could be a fix for mt2712 which support 2 M4U HW and list them.
--- drivers/iommu/mtk_iommu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iommu/mtk_iommu.c +1 -2
@@ -768,8 +768,7 @@ static int mtk_iommu_remove(struct platform_device *pdev)iommu_device_sysfs_remove (&data->iommu);iommu_device_unregister (&data->iommu); -if (iommu_present (&platform_bus_type)) -bus_set_iommu (&platform_bus_type,NULL ); +list_del (&data->list);clk_disable_unprepare (data->bclk);devm_free_irq (&pdev->dev, data->irq, data);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 321/452 i2c: at91: use dma safe buffers
In reply to Greg Kroah-HartmanFrom: Michael Walle <[email protected]>
[ Upstream commit 03fbb903c8bf7e53e101e8d9a7b261264317c411 ]
The supplied buffer might be on the stack and we get the following error message:
[ 3.312058] at91_i2c e0070600.i2c: rejecting DMA map of vmalloc memory
Use i2c_{get,put}_dma_safe_msg_buf() to get a DMA-able memory region if necessary.
--- drivers/i2c/busses/i2c-at91-master.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/i2c/busses/i2c-at91-master.c +11 -0
@@ -657,6 +657,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)unsigned int_addr_flag =0 ;struct i2c_msg *m_start = msg;bool is_read; +u8 *dma_buf;dev_dbg (&adap->dev,"at91_xfer: processing %d messages:\n" , num);
@@ -704,7 +705,17 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->msg = m_start; dev->recv_len_abort = false; +if (dev->use_dma) { + dma_buf =i2c_get_dma_safe_msg_buf (m_start,1 ); +if (!dma_buf) { + ret = -ENOMEM ; + goto out; + } + dev->buf = dma_buf; + } + ret =at91_do_twi_transfer (dev); +i2c_put_dma_safe_msg_buf (dma_buf, m_start, !ret); ret = (ret <0 ) ? ret : num; out:
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 322/452 cpufreq: mediatek: add missing platform_driver_unregister() on error in mtk_cpufreq_driver_init
In reply to Greg Kroah-HartmanFrom: Qinglang Miao <[email protected]>
[ Upstream commit 2f05c19d9ef4f5a42634f83bdb0db596ffc0dd30 ]
Add the missing platform_driver_unregister() before return from mtk_cpufreq_driver_init in the error handling case when failed to register mtk-cpufreq platform device
--- drivers/cpufreq/mediatek-cpufreq.c | 1 + 1 file changed, 1 insertion(+)
drivers/cpufreq/mediatek-cpufreq.c +1 -0
@@ -573,6 +573,7 @@ static int __init mtk_cpufreq_driver_init(void) pdev =platform_device_register_simple ("mtk-cpufreq" ,-1 ,NULL ,0 );if (IS_ERR (pdev)) {pr_err ("failed to register mtk-cpufreq platform device\n" ); +platform_driver_unregister (&mtk_cpufreq_platdrv);return PTR_ERR (pdev); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 323/452 cpufreq: mediatek: Use module_init and add module_exit
In reply to Greg Kroah-HartmanFrom: Jia-Wei Chang <[email protected]>
[ Upstream commit b7070187c81cb90549d7561c0e750d7c7eb751f4 ]
- Use module_init instead of device_initcall.
- Add a function for module_exit to unregister driver.
--- drivers/cpufreq/mediatek-cpufreq.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/cpufreq/mediatek-cpufreq.c +7 -1
@@ -579,7 +579,13 @@ static int __init mtk_cpufreq_driver_init(void)return 0 ; } -device_initcall (mtk_cpufreq_driver_init); +module_init (mtk_cpufreq_driver_init) + +static void __exit mtk_cpufreq_driver_exit(void) +{ +platform_driver_unregister (&mtk_cpufreq_platdrv); +} +module_exit(mtk_cpufreq_driver_exit) MODULE_DESCRIPTION("MediaTek CPUFreq driver");MODULE_AUTHOR ("Pi-Cheng Chen <[email protected]>" );
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 324/452 cpufreq: mediatek: Unregister platform device on exit
In reply to Greg Kroah-HartmanFrom: Rex-BC Chen <[email protected]>
[ Upstream commit f126fbadce92b92c3a7be41e4abc1fbae93ae2ef ]
We register the platform device when driver inits. However, we do not unregister it when driver exits.
To resolve this, we declare the platform data to be a global static variable and rename it to be "cpufreq_pdev". With this global variable, we can do platform_device_unregister() when driver exits.
--- drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/cpufreq/mediatek-cpufreq.c +6 -4
@@ -44,6 +44,8 @@ struct mtk_cpu_dvfs_info {bool need_voltage_tracking; }; +static struct platform_device *cpufreq_pdev; +static LIST_HEAD (dvfs_info_list);static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup (int cpu)
@@ -546,7 +548,6 @@ static int __init mtk_cpufreq_driver_init(void) {struct device_node *np;const struct of_device_id *match; -struct platform_device *pdev;int err; np =of_find_node_by_path ("/" );
@@ -570,11 +571,11 @@ static int __init mtk_cpufreq_driver_init(void)* and the device registration codes are put here to handle defer * probing. */ - pdev =platform_device_register_simple ("mtk-cpufreq" ,-1 ,NULL ,0 ); -if (IS_ERR (pdev)) { + cpufreq_pdev =platform_device_register_simple ("mtk-cpufreq" ,-1 ,NULL ,0 ); +if (IS_ERR (cpufreq_pdev)) {pr_err ("failed to register mtk-cpufreq platform device\n" );platform_driver_unregister (&mtk_cpufreq_platdrv); -return PTR_ERR (pdev); +return PTR_ERR (cpufreq_pdev); }return 0 ;
@@ -583,6 +584,7 @@ module_init(mtk_cpufreq_driver_init) static void __exit mtk_cpufreq_driver_exit(void) { +platform_device_unregister (cpufreq_pdev);platform_driver_unregister (&mtk_cpufreq_platdrv); }module_exit (mtk_cpufreq_driver_exit)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 325/452 MIPS: Loongson: Use hwmon_device_register_with_groups() to register hwmon
In reply to Greg Kroah-HartmanFrom: Guenter Roeck <[email protected]>
[ Upstream commit abae018a03821be2b65c01ebe2bef06fd7d85a4c ]
Calling hwmon_device_register_with_info() with NULL dev and/or chip information parameters is an ABI abuse and not a real conversion to the new API. Also, the code creates sysfs attributes _after_ creating the hwmon device, which is racy and unsupported to start with. On top of that, the removal code tries to remove the name attribute which is owned by the hwmon core.
Use hwmon_device_register_with_groups() to register the hwmon device instead.
In the future, the hwmon subsystem will reject calls to hwmon_device_register_with_info with NULL dev or chip/info parameters. Without this patch, the hwmon device will fail to register.
--- drivers/platform/mips/cpu_hwmon.c | 127 ++++++++++-------------------- 1 file changed, 41 insertions(+), 86 deletions(-)
drivers/platform/mips/cpu_hwmon.c +41 -86
@@ -55,55 +55,6 @@ int loongson3_cpu_temp(int cpu)static int nr_packages;static struct device *cpu_hwmon_dev; -static SENSOR_DEVICE_ATTR(name, 0444, NULL, NULL, 0); - -static struct attribute *cpu_hwmon_attributes[] = { - &sensor_dev_attr_name.dev_attr.attr, -NULL -}; - -/* Hwmon device attribute group */ -static struct attribute_group cpu_hwmon_attribute_group = { - .attrs = cpu_hwmon_attributes, -}; - -static ssize_t get_cpu_temp (struct device *dev, -struct device_attribute *attr,char *buf); -static ssize_t cpu_temp_label (struct device *dev, -struct device_attribute *attr,char *buf); - -static SENSOR_DEVICE_ATTR(temp1_input, 0444, get_cpu_temp, NULL, 1); -static SENSOR_DEVICE_ATTR(temp1_label, 0444, cpu_temp_label, NULL, 1); -static SENSOR_DEVICE_ATTR(temp2_input, 0444, get_cpu_temp, NULL, 2); -static SENSOR_DEVICE_ATTR(temp2_label, 0444, cpu_temp_label, NULL, 2); -static SENSOR_DEVICE_ATTR(temp3_input, 0444, get_cpu_temp, NULL, 3); -static SENSOR_DEVICE_ATTR(temp3_label, 0444, cpu_temp_label, NULL, 3); -static SENSOR_DEVICE_ATTR(temp4_input, 0444, get_cpu_temp, NULL, 4); -static SENSOR_DEVICE_ATTR(temp4_label, 0444, cpu_temp_label, NULL, 4); - -static const struct attribute *hwmon_cputemp[4 ][3 ] = { - { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_label.dev_attr.attr, -NULL - }, - { - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp2_label.dev_attr.attr, -NULL - }, - { - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp3_label.dev_attr.attr, -NULL - }, - { - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp4_label.dev_attr.attr, -NULL - } -}; -static ssize_t cpu_temp_label (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -121,24 +72,47 @@ static ssize_t get_cpu_temp(struct device *dev,return sprintf (buf,"%d\n" , value); } -static int create_sysfs_cputemp_files (struct kobject *kobj) -{ -int i, ret =0 ; - -for (i =0 ; i < nr_packages; i++) - ret =sysfs_create_files (kobj, hwmon_cputemp[i]); +static SENSOR_DEVICE_ATTR(temp1_input, 0444, get_cpu_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_label, 0444, cpu_temp_label, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_input, 0444, get_cpu_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_label, 0444, cpu_temp_label, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_input, 0444, get_cpu_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp3_label, 0444, cpu_temp_label, NULL, 3); +static SENSOR_DEVICE_ATTR(temp4_input, 0444, get_cpu_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp4_label, 0444, cpu_temp_label, NULL, 4); -return ret; -} +static struct attribute *cpu_hwmon_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_label.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_label.dev_attr.attr, +NULL +}; -static void remove_sysfs_cputemp_files (struct kobject *kobj) +static umode_t cpu_hwmon_is_visible (struct kobject *kobj, +struct attribute *attr,int i) { -int i; +int id = i /2 ; -for (i =0 ; i < nr_packages; i++) -sysfs_remove_files (kobj, hwmon_cputemp[i]); +if (id < nr_packages) +return attr->mode; +return 0 ; } +static struct attribute_group cpu_hwmon_group = { + .attrs = cpu_hwmon_attributes, + .is_visible = cpu_hwmon_is_visible, +}; + +static const struct attribute_group *cpu_hwmon_groups[] = { + &cpu_hwmon_group, +NULL +}; +#define CPU_THERMAL_THRESHOLD 90000static struct delayed_work thermal_work;
@@ -159,50 +133,31 @@ static void do_thermal_timer(struct work_struct *work)static int __init loongson_hwmon_init (void ) { -int ret; -pr_info ("Loongson Hwmon Enter...\n" );if (cpu_has_csr ()) csr_temp_enable =csr_readl (LOONGSON_CSR_FEATURES ) &LOONGSON_CSRF_TEMP ; - cpu_hwmon_dev =hwmon_device_register_with_info (NULL ,"cpu_hwmon" ,NULL ,NULL ,NULL ); -if (IS_ERR (cpu_hwmon_dev)) { - ret =PTR_ERR (cpu_hwmon_dev); -pr_err ("hwmon_device_register fail!\n" ); - goto fail_hwmon_device_register; - } - nr_packages = loongson_sysconf.nr_cpus / loongson_sysconf.cores_per_package; - ret =create_sysfs_cputemp_files (&cpu_hwmon_dev->kobj); -if (ret) { -pr_err ("fail to create cpu temperature interface!\n" ); - goto fail_create_sysfs_cputemp_files; + cpu_hwmon_dev =hwmon_device_register_with_groups (NULL ,"cpu_hwmon" , +NULL , cpu_hwmon_groups); +if (IS_ERR (cpu_hwmon_dev)) { +pr_err ("hwmon_device_register fail!\n" ); +return PTR_ERR (cpu_hwmon_dev); }INIT_DEFERRABLE_WORK (&thermal_work, do_thermal_timer);schedule_delayed_work (&thermal_work,msecs_to_jiffies (20000 )); -return ret; - -fail_create_sysfs_cputemp_files: -sysfs_remove_group (&cpu_hwmon_dev->kobj, - &cpu_hwmon_attribute_group); -hwmon_device_unregister (cpu_hwmon_dev); - -fail_hwmon_device_register: -return ret; +return 0 ; } static void __exit loongson_hwmon_exit(void) {cancel_delayed_work_sync (&thermal_work); -remove_sysfs_cputemp_files (&cpu_hwmon_dev->kobj); -sysfs_remove_group (&cpu_hwmon_dev->kobj, - &cpu_hwmon_attribute_group);hwmon_device_unregister (cpu_hwmon_dev); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 326/452 i2c: at91: Initialize dma_buf in at91_twi_xfer()
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
[ Upstream commit 6977262c2eee111645668fe9e235ef2f5694abf7 ]
Clang warns:
drivers/i2c/busses/i2c-at91-master.c:707:6: warning: variable 'dma_buf' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
if (dev->use_dma) {
^~~~~~~~~~~~
drivers/i2c/busses/i2c-at91-master.c:717:27: note: uninitialized use occurs here
i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret);
^~~~~~~Initialize dma_buf to NULL, as i2c_put_dma_safe_msg_buf() is a no-op when the first argument is NULL, which will work for the !dev->use_dma case.
--- drivers/i2c/busses/i2c-at91-master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-at91-master.c +1 -1
@@ -657,7 +657,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)unsigned int_addr_flag =0 ;struct i2c_msg *m_start = msg;bool is_read; -u8 *dma_buf; +u8 *dma_buf =NULL ;dev_dbg (&adap->dev,"at91_xfer: processing %d messages:\n" , num);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 327/452 dmaengine: idxd: Fix the error handling path in idxd_cdev_register()
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit aab08c1aac01097815fbcf10fce7021d2396a31f ]
If a call to alloc_chrdev_region() fails, the already allocated resources are leaking.
Add the needed error handling path to fix the leak.
--- drivers/dma/idxd/cdev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/dma/idxd/cdev.c +7 -1
@@ -266,10 +266,16 @@ int idxd_cdev_register(void) rc =alloc_chrdev_region (&ictx[i].devt,0 ,MINORMASK , ictx[i].name);if (rc) -return rc; + goto err_free_chrdev_region; }return 0 ; + +err_free_chrdev_region: +for (i--; i >=0 ; i--) +unregister_chrdev_region (ictx[i].devt,MINORMASK ); + +return rc; }void idxd_cdev_remove (void )
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 328/452 NFS: Do not report EINTR/ERESTARTSYS as mapping errors
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit cea9ba7239dcc84175041174304c6cdeae3226e5 ]
If the attempt to flush data was interrupted due to a local signal, then just requeue the writes back for I/O.
--- fs/nfs/write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/write.c +1 -1
@@ -1411,7 +1411,7 @@ static void nfs_async_write_error(struct list_head *head, int error)while (!list_empty (head)) { req =nfs_list_entry (head->next);nfs_list_remove_request (req); -if (nfs_error_is_fatal (error)) +if (nfs_error_is_fatal_on_server (error))nfs_write_error (req, error);else nfs_redirty_request (req);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 329/452 NFS: fsync() should report filesystem errors over EINTR/ERESTARTSYS
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit 9641d9bc9b75f11f70646f5c6ee9f5f519a1012e ]
If the commit to disk is interrupted, we should still first check for filesystem errors so that we can report them in preference to the error due to the signal.
--- fs/nfs/file.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
fs/nfs/file.c +5 -4
@@ -208,15 +208,16 @@ static int nfs_file_fsync_commit(struct file *file, int datasync) {struct inode *inode =file_inode (file); -int ret; +int ret, ret2;dprintk ("NFS: fsync file(%pD2) datasync %d\n" , file, datasync);nfs_inc_stats (inode,NFSIOS_VFSFSYNC ); ret =nfs_commit_inode (inode,FLUSH_SYNC ); -if (ret <0 ) -return ret; -return file_check_and_advance_wb_err (file); + ret2 =file_check_and_advance_wb_err (file); +if (ret2 <0 ) +return ret2; +return ret; }int
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 330/452 NFS: Do not report flush errors in nfs_write_end()
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit d95b26650e86175e4a97698d89bc1626cd1df0c6 ]
If we do flush cached writebacks in nfs_write_end() due to the imminent expiration of an RPCSEC_GSS session, then we should defer reporting any resulting errors until the calls to file_check_and_advance_wb_err() in nfs_file_write() and nfs_file_fsync().
--- fs/nfs/file.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
fs/nfs/file.c +2 -5
@@ -390,11 +390,8 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,return status;NFS_I (mapping->host)->write_io += copied; -if (nfs_ctx_key_to_expire (ctx, mapping->host)) { - status =nfs_wb_all (mapping->host); -if (status <0 ) -return status; - } +if (nfs_ctx_key_to_expire (ctx, mapping->host)) +nfs_wb_all (mapping->host);return copied; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 331/452 NFS: Dont report errors from nfs_pageio_complete() more than once
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit c5e483b77cc2edb318da152abe07e33006b975fd ]
Since errors from nfs_pageio_complete() are already being reported through nfs_async_write_error(), we should not be returning them to the callers of do_writepages() as well. They will end up being reported through the generic mechanism instead.
--- fs/nfs/write.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
fs/nfs/write.c +1 -8
@@ -675,11 +675,7 @@ static int nfs_writepage_locked(struct page *page, err =nfs_do_writepage (page, wbc, &pgio); pgio.pg_error =0 ;nfs_pageio_complete (&pgio); -if (err <0 ) -return err; -if (nfs_error_is_fatal (pgio.pg_error)) -return pgio.pg_error; -return 0 ; +return err; }int nfs_writepage (struct page *page,struct writeback_control *wbc)
@@ -730,9 +726,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)if (err <0 ) goto out_err; - err = pgio.pg_error; -if (nfs_error_is_fatal (err)) - goto out_err;return 0 ; out_err:return err;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 332/452 NFSv4/pNFS: Do not fail I/O when we fail to allocate the pNFS layout
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit 3764a17e31d579cf9b4bd0a69894b577e8d75702 ]
Commit 587f03deb69b caused pnfs_update_layout() to stop returning ENOMEM when the memory allocation fails, and hence causes it to fall back to trying to do I/O through the MDS. There is no guarantee that this will fare any better. If we're failing the pNFS layout allocation, then we should just redirty the page and retry later.
--- fs/nfs/pnfs.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfs/pnfs.c +2 -0
@@ -2006,6 +2006,7 @@ pnfs_update_layout(struct inode *ino, lo =pnfs_find_alloc_layout (ino, ctx, gfp_flags);if (lo ==NULL ) {spin_unlock (&ino->i_lock); + lseg =ERR_PTR (-ENOMEM );trace_pnfs_update_layout (ino, pos, count, iomode, lo, lseg,PNFS_UPDATE_LAYOUT_NOMEM ); goto out;
@@ -2134,6 +2135,7 @@ pnfs_update_layout(struct inode *ino, lgp =pnfs_alloc_init_layoutget_args (ino, ctx, &stateid, &arg, gfp_flags);if (!lgp) { + lseg =ERR_PTR (-ENOMEM );trace_pnfs_update_layout (ino, pos, count, iomode, lo,NULL ,PNFS_UPDATE_LAYOUT_NOMEM );nfs_layoutget_end (lo);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 333/452 video: fbdev: clcdfb: Fix refcount leak in clcdfb_of_vram_setup
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit b23789a59fa6f00e98a319291819f91fbba0deb8 ]
of_parse_phandle() returns a node pointer with refcount incremented, we should use of_node_put() on it when not need anymore. Add missing of_node_put() to avoid refcount leak.
--- drivers/video/fbdev/amba-clcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/video/fbdev/amba-clcd.c +4 -1
@@ -771,12 +771,15 @@ static int clcdfb_of_vram_setup(struct clcd_fb *fb)return -ENODEV ; fb->fb.screen_base =of_iomap (memory,0 ); -if (!fb->fb.screen_base) +if (!fb->fb.screen_base) { +of_node_put (memory);return -ENOMEM ; + } fb->fb.fix.smem_start =of_translate_address (memory,of_get_address (memory,0 , &size,NULL )); fb->fb.fix.smem_len = size; +of_node_put (memory);return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 334/452 dmaengine: stm32-mdma: remove GISR1 register
In reply to Greg Kroah-HartmanFrom: Amelie Delaunay <[email protected]>
[ Upstream commit 9d6a2d92e450926c483e45eaf426080a19219f4e ]
GISR1 was described in a not up-to-date documentation when the stm32-mdma driver has been developed. This register has not been added in reference manual of STM32 SoC with MDMA, which have only 32 MDMA channels. So remove it from stm32-mdma driver.
--- drivers/dma/stm32-mdma.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-)
drivers/dma/stm32-mdma.c +5 -16
@@ -40,7 +40,6 @@ STM32_MDMA_SHIFT(mask))#define STM32_MDMA_GISR0 0x0000/* MDMA Int Status Reg 1 */ -#define STM32_MDMA_GISR1 0x0004/* MDMA Int Status Reg 2 */ /* MDMA Channel x interrupt/status register */ #define STM32_MDMA_CISR (x) (0x40 + 0x40 * (x))/* x = 0..62 */
@@ -196,7 +195,7 @@#define STM32_MDMA_MAX_BUF_LEN 128#define STM32_MDMA_MAX_BLOCK_LEN 65536 -#define STM32_MDMA_MAX_CHANNELS 63 +#define STM32_MDMA_MAX_CHANNELS 32#define STM32_MDMA_MAX_REQUESTS 256#define STM32_MDMA_MAX_BURST 128#define STM32_MDMA_VERY_HIGH_PRIORITY 0x11
@@ -1350,21 +1349,11 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)/* Find out which channel generates the interrupt */ status =readl_relaxed (dmadev->base +STM32_MDMA_GISR0 ); -if (status) { - id =__ffs (status); - }else { - status =readl_relaxed (dmadev->base +STM32_MDMA_GISR1 ); -if (!status) { -dev_dbg (mdma2dev (dmadev),"spurious it\n" ); -return IRQ_NONE ; - } - id =__ffs (status); -/* -* As GISR0 provides status for channel id from 0 to 31, -* so GISR1 provides status for channel id from 32 to 62 -*/ - id +=32 ; +if (!status) { +dev_dbg (mdma2dev (dmadev),"spurious it\n" ); +return IRQ_NONE ; } + id =__ffs (status); chan = &dmadev->chan[id];if (!chan) {
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 335/452 dmaengine: stm32-mdma: rework interrupt handler
In reply to Greg Kroah-HartmanFrom: Amelie Delaunay <[email protected]>
[ Upstream commit 1d3dd68749b9f4a4da272f39608d03b4bae0b69f ]
To avoid multiple entries in MDMA interrupt handler for each flag&interrupt enable, manage all flags set at once.
--- drivers/dma/stm32-mdma.c | 64 +++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 30 deletions(-)
drivers/dma/stm32-mdma.c +34 -30
@@ -1345,7 +1345,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) {struct stm32_mdma_device *dmadev = devid;struct stm32_mdma_chan *chan = devid; -u32 reg, id, ien, status, flag; +u32 reg, id, ccr, ien, status;/* Find out which channel generates the interrupt */ status =readl_relaxed (dmadev->base +STM32_MDMA_GISR0 );
@@ -1357,67 +1357,71 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid) chan = &dmadev->chan[id];if (!chan) { -dev_dbg (mdma2dev (dmadev),"MDMA channel not initialized\n" ); - goto exit; +dev_warn (mdma2dev (dmadev),"MDMA channel not initialized\n" ); +return IRQ_NONE ; }/* Handle interrupt for the channel */ spin_lock (&chan->vchan.lock); - status =stm32_mdma_read (dmadev,STM32_MDMA_CISR (chan->id)); - ien =stm32_mdma_read (dmadev,STM32_MDMA_CCR (chan->id)); - ien &=STM32_MDMA_CCR_IRQ_MASK ; - ien >>=1 ; + status =stm32_mdma_read (dmadev,STM32_MDMA_CISR (id)); +/* Mask Channel ReQuest Active bit which can be set in case of MEM2MEM */ + status &= ~STM32_MDMA_CISR_CRQA ; + ccr =stm32_mdma_read (dmadev,STM32_MDMA_CCR (id)); + ien = (ccr &STM32_MDMA_CCR_IRQ_MASK ) >>1 ;if (!(status & ien)) {spin_unlock (&chan->vchan.lock); -dev_dbg (chan2dev (chan), -"spurious it (status=0x%04x, ien=0x%04x)\n" , - status, ien); +dev_warn (chan2dev (chan), +"spurious it (status=0x%04x, ien=0x%04x)\n" , + status, ien);return IRQ_NONE ; } - flag =__ffs (status & ien); - reg =STM32_MDMA_CIFCR (chan->id); + reg =STM32_MDMA_CIFCR (id); -switch (1 << flag) { -case STM32_MDMA_CISR_TEIF : - id = chan->id; - status =readl_relaxed (dmadev->base +STM32_MDMA_CESR (id)); -dev_err (chan2dev (chan),"Transfer Err: stat=0x%08x\n" , status); +if (status &STM32_MDMA_CISR_TEIF ) { +dev_err (chan2dev (chan),"Transfer Err: stat=0x%08x\n" , +readl_relaxed (dmadev->base +STM32_MDMA_CESR (id)));stm32_mdma_set_bits (dmadev, reg,STM32_MDMA_CIFCR_CTEIF ); -break ; + status &= ~STM32_MDMA_CISR_TEIF ; + } -case STM32_MDMA_CISR_CTCIF : +if (status &STM32_MDMA_CISR_CTCIF ) {stm32_mdma_set_bits (dmadev, reg,STM32_MDMA_CIFCR_CCTCIF ); + status &= ~STM32_MDMA_CISR_CTCIF ;stm32_mdma_xfer_end (chan); -break ; + } -case STM32_MDMA_CISR_BRTIF : +if (status &STM32_MDMA_CISR_BRTIF ) {stm32_mdma_set_bits (dmadev, reg,STM32_MDMA_CIFCR_CBRTIF ); -break ; + status &= ~STM32_MDMA_CISR_BRTIF ; + } -case STM32_MDMA_CISR_BTIF : +if (status &STM32_MDMA_CISR_BTIF ) {stm32_mdma_set_bits (dmadev, reg,STM32_MDMA_CIFCR_CBTIF ); + status &= ~STM32_MDMA_CISR_BTIF ; chan->curr_hwdesc++;if (chan->desc && chan->desc->cyclic) {if (chan->curr_hwdesc == chan->desc->count) chan->curr_hwdesc =0 ;vchan_cyclic_callback (&chan->desc->vdesc); } -break ; + } -case STM32_MDMA_CISR_TCIF : +if (status &STM32_MDMA_CISR_TCIF ) {stm32_mdma_set_bits (dmadev, reg,STM32_MDMA_CIFCR_CLTCIF ); -break ; + status &= ~STM32_MDMA_CISR_TCIF ; + } -default : -dev_err (chan2dev (chan),"it %d unhandled (status=0x%04x)\n" , -1 << flag, status); +if (status) { +stm32_mdma_set_bits (dmadev, reg, status); +dev_err (chan2dev (chan),"DMA error: status=0x%08x\n" , status); +if (!(ccr &STM32_MDMA_CCR_EN )) +dev_err (chan2dev (chan),"chan disabled by HW\n" ); }spin_unlock (&chan->vchan.lock); -exit:return IRQ_HANDLED ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 336/452 dmaengine: stm32-mdma: fix chan initialization in stm32_mdma_irq_handler()
In reply to Greg Kroah-HartmanFrom: Amelie Delaunay <[email protected]>
[ Upstream commit da3b8ddb464bd49b6248d00ca888ad751c9e44fd ]
The parameter to pass back to the handler function when irq has been requested is a struct stm32_mdma_device pointer, not a struct stm32_mdma_chan pointer.
Even if chan is reinit later in the function, remove this wrong initialization.
--- drivers/dma/stm32-mdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/stm32-mdma.c +1 -1
@@ -1344,7 +1344,7 @@ static void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan)static irqreturn_t stm32_mdma_irq_handler (int irq,void *devid) {struct stm32_mdma_device *dmadev = devid; -struct stm32_mdma_chan *chan = devid; +struct stm32_mdma_chan *chan;u32 reg, id, ccr, ien, status;/* Find out which channel generates the interrupt */
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 337/452 iommu/amd: Increase timeout waiting for GA log enablement
In reply to Greg Kroah-HartmanFrom: Joerg Roedel <[email protected]>
[ Upstream commit 42bb5aa043382f09bef2cc33b8431be867c70f8e ]
On some systems it can take a long time for the hardware to enable the GA log of the AMD IOMMU. The current wait time is only 0.1ms, but testing showed that it can take up to 14ms for the GA log to enter running state after it has been enabled.
Sometimes the long delay happens when booting the system, sometimes only on resume. Adjust the timeout accordingly to not print a warning when hardware takes a longer than usual.
There has already been an attempt to fix this with commit
9b45a7738eec ("iommu/amd: Fix loop timeout issue in iommu_ga_log_enable()")
But that commit was based on some wrong math and did not fix the issue in all cases.
--- drivers/iommu/amd/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/amd/init.c +1 -1
@@ -84,7 +84,7 @@#define ACPI_DEVFLAG_LINT1 0x80#define ACPI_DEVFLAG_ATSDIS 0x10000000 -#define LOOP_TIMEOUT 100000 +#define LOOP_TIMEOUT 2000000/* * ACPI table definitions *
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 338/452 i2c: npcm: Fix timeout calculation
In reply to Greg Kroah-HartmanFrom: Tali Perry <[email protected]>
[ Upstream commit 288b204492fddf28889cea6dc95a23976632c7a0 ]
Use adap.timeout for timeout calculation instead of hard-coded value of 35ms.
--- drivers/i2c/busses/i2c-npcm7xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/i2c/busses/i2c-npcm7xx.c +4 -4
@@ -2047,7 +2047,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,u16 nwrite, nread;u8 *write_data, *read_data;u8 slave_addr; -int timeout; +unsigned long timeout;int ret =0 ;bool read_block = false;bool read_PEC = false;
@@ -2099,13 +2099,13 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,* 9: bits per transaction (including the ack/nack) */ timeout_usec = (2 *9 *USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); - timeout =max (msecs_to_jiffies (35 ),usecs_to_jiffies (timeout_usec)); + timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec));if (nwrite >=32 *1024 || nread >=32 *1024 ) {dev_err (bus->dev,"i2c%d buffer too big\n" , bus->num);return -EINVAL ; } - time_left = jiffies +msecs_to_jiffies (DEFAULT_STALL_COUNT ) +1 ; + time_left = jiffies + timeout +1 ; do { /* * we must clear slave address immediately when the bus is not
@@ -2269,7 +2269,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) adap = &bus->adap; adap->owner =THIS_MODULE ; adap->retries =3 ; - adap->timeout =HZ ; + adap->timeout =msecs_to_jiffies (35 ); adap->algo = &npcm_i2c_algo; adap->quirks = &npcm_i2c_quirks; adap->algo_data = bus;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 339/452 i2c: npcm: Correct register access width
In reply to Greg Kroah-HartmanFrom: Tyrone Ting <[email protected]>
[ Upstream commit ea9f8426d17620214ee345ffb77ee6cc196ff14f ]
The SMBnCTL3 register is 8-bit wide and the 32-bit access was always incorrect, but simply didn't cause a visible error on the 32-bit machine.
On the 64-bit machine, the kernel message reports that ESR value is 0x96000021. Checking Arm Architecture Reference Manual Armv8 suggests that it's the alignment fault.
SMBnCTL3's address is 0xE.
--- drivers/i2c/busses/i2c-npcm7xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/i2c/busses/i2c-npcm7xx.c +2 -2
@@ -359,14 +359,14 @@ static int npcm_i2c_get_SCL(struct i2c_adapter *_adap) { struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); -return !!(I2CCTL3_SCL_LVL &ioread32 (bus->reg +NPCM_I2CCTL3 )); +return !!(I2CCTL3_SCL_LVL &ioread8 (bus->reg +NPCM_I2CCTL3 )); }static int npcm_i2c_get_SDA (struct i2c_adapter *_adap) { struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); -return !!(I2CCTL3_SDA_LVL &ioread32 (bus->reg +NPCM_I2CCTL3 )); +return !!(I2CCTL3_SDA_LVL &ioread8 (bus->reg +NPCM_I2CCTL3 )); }static inline u16 npcm_i2c_get_index (struct npcm_i2c *bus)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 340/452 i2c: npcm: Handle spurious interrupts
In reply to Greg Kroah-HartmanFrom: Tali Perry <[email protected]>
[ Upstream commit e5222d408de2a88e6b206c38217b48d092184553 ]
On some platforms in rare cases (1 to 100,000 transactions), the i2c gets a spurious interrupt which means that we enter an interrupt but in the interrupt handler we don't find any status bit that points to the reason we got this interrupt.
This may be a case of a rare HW issue or signal integrity issue that is still under investigation.
In order to overcome this we are doing the following:
1. Disable incoming interrupts in master mode only when slave mode is not enabled.
2. Clear end of busy (EOB) after every interrupt.
3. Clear other status bits (just in case since we found them cleared)
4. Return correct status during the interrupt that will finish the transaction.
On next xmit transaction if the bus is still busy the master will issue a recovery process before issuing the new transaction.
--- drivers/i2c/busses/i2c-npcm7xx.c | 91 ++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 29 deletions(-)
drivers/i2c/busses/i2c-npcm7xx.c +62 -29
@@ -563,6 +563,15 @@ static inline void npcm_i2c_nack(struct npcm_i2c *bus)iowrite8 (val, bus->reg +NPCM_I2CCTL1 ); } +static inline void npcm_i2c_clear_master_status (struct npcm_i2c *bus) +{ +u8 val; + +/* Clear NEGACK, STASTR and BER bits */ + val =NPCM_I2CST_BER |NPCM_I2CST_NEGACK |NPCM_I2CST_STASTR ; +iowrite8 (val, bus->reg +NPCM_I2CST ); +} +#if IS_ENABLED (CONFIG_I2C_SLAVE )static void npcm_i2c_slave_int_enable (struct npcm_i2c *bus,bool enable) {
@@ -642,8 +651,8 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)iowrite8 (NPCM_I2CCST_BB , bus->reg +NPCM_I2CCST );iowrite8 (0xFF , bus->reg +NPCM_I2CST ); -/* Clear EOB bit */ -iowrite8 (NPCM_I2CCST3_EO_BUSY , bus->reg +NPCM_I2CCST3 ); +/* Clear and disable EOB */ +npcm_i2c_eob_int (bus, false);/* Clear all fifo bits: */ iowrite8 (NPCM_I2CFIF_CTS_CLR_FIFO , bus->reg +NPCM_I2CFIF_CTS );
@@ -655,6 +664,9 @@ static void npcm_i2c_reset(struct npcm_i2c *bus) }#endif +/* clear status bits for spurious interrupts */ +npcm_i2c_clear_master_status (bus); + bus->state =I2C_IDLE ; }
@@ -815,15 +827,6 @@ static void npcm_i2c_read_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo) } } -static inline void npcm_i2c_clear_master_status (struct npcm_i2c *bus) -{ -u8 val; - -/* Clear NEGACK, STASTR and BER bits */ - val =NPCM_I2CST_BER |NPCM_I2CST_NEGACK |NPCM_I2CST_STASTR ; -iowrite8 (val, bus->reg +NPCM_I2CST ); -} -static void npcm_i2c_master_abort (struct npcm_i2c *bus) {/* Only current master is allowed to issue a stop condition */
@@ -1231,7 +1234,16 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) ret =IRQ_HANDLED ; }/* SDAST */ -return ret; +/* +* if irq is not one of the above, make sure EOB is disabled and all +* status bits are cleared. +*/ +if (ret ==IRQ_NONE ) { +npcm_i2c_eob_int (bus, false); +npcm_i2c_clear_master_status (bus); + } + +return IRQ_HANDLED ; }static int npcm_i2c_reg_slave (struct i2c_client *client)
@@ -1467,6 +1479,9 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)npcm_i2c_eob_int (bus, false);npcm_i2c_master_stop (bus); +/* Clear SDA Status bit (by reading dummy byte) */ +npcm_i2c_rd_byte (bus); +/* * The bus is released from stall only after the SW clears * NEGACK bit. Then a Stop condition is sent.
@@ -1474,6 +1489,8 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)npcm_i2c_clear_master_status (bus);readx_poll_timeout_atomic (ioread8, bus->reg +NPCM_I2CCST , val, !(val &NPCM_I2CCST_BUSY ),10 ,200 ); +/* verify no status bits are still set after bus is released */ +npcm_i2c_clear_master_status (bus); } bus->state =I2C_IDLE ;
@@ -1672,10 +1689,10 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)int iter =27 ;if ((npcm_i2c_get_SDA (_adap) ==1 ) && (npcm_i2c_get_SCL (_adap) ==1 )) { -dev_dbg (bus->dev,"bus%d recovery skipped, bus not stuck" , - bus->num); +dev_dbg (bus->dev,"bus%d-0x%x recovery skipped, bus not stuck" , + bus->num, bus->dest_addr);npcm_i2c_reset (bus); -return status; +return 0 ; }npcm_i2c_int_enable (bus, false);
@@ -1909,6 +1926,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ)return -EINVAL ; +npcm_i2c_int_enable (bus, false);npcm_i2c_disable (bus);/* Configure FIFO mode : */
@@ -1937,10 +1955,17 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, val = (val |NPCM_I2CCTL1_NMINTE ) & ~NPCM_I2CCTL1_RWS ;iowrite8 (val, bus->reg +NPCM_I2CCTL1 ); -npcm_i2c_int_enable (bus, true); -npcm_i2c_reset (bus); +/* check HW is OK: SDA and SCL should be high at this point. */ +if ((npcm_i2c_get_SDA (&bus->adap) ==0 ) || (npcm_i2c_get_SCL (&bus->adap) ==0 )) { +dev_err (bus->dev,"I2C%d init fail: lines are low\n" , bus->num); +dev_err (bus->dev,"SDA=%d SCL=%d\n" ,npcm_i2c_get_SDA (&bus->adap), +npcm_i2c_get_SCL (&bus->adap)); +return -ENXIO ; + } + +npcm_i2c_int_enable (bus, true);return 0 ; }
@@ -1988,10 +2013,14 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)#if IS_ENABLED (CONFIG_I2C_SLAVE )if (bus->slave) { bus->master_or_slave =I2C_SLAVE ; -return npcm_i2c_int_slave_handler (bus); +if (npcm_i2c_int_slave_handler (bus)) +return IRQ_HANDLED ; }#endif -return IRQ_NONE ; +/* clear status bits for spurious interrupts */ +npcm_i2c_clear_master_status (bus); + +return IRQ_HANDLED ; } static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus,
@@ -2048,7 +2077,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,u8 *write_data, *read_data;u8 slave_addr;unsigned long timeout; -int ret =0 ;bool read_block = false;bool read_PEC = false;u8 bus_busy;
@@ -2138,12 +2166,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, bus->read_block_use = read_block;reinit_completion (&bus->cmd_complete); -if (!npcm_i2c_master_start_xmit (bus, slave_addr, nwrite, nread, - write_data, read_data, read_PEC, - read_block)) - ret = -EBUSY ; -if (ret != -EBUSY ) { +npcm_i2c_int_enable (bus, true); + +if (npcm_i2c_master_start_xmit (bus, slave_addr, nwrite, nread, + write_data, read_data, read_PEC, + read_block)) { time_left =wait_for_completion_timeout (&bus->cmd_complete, timeout);
@@ -2157,26 +2185,31 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } } } - ret = bus->cmd_err;/* if there was BER, check if need to recover the bus: */ if (bus->cmd_err == -EAGAIN ) - ret =i2c_recover_bus (adap); + bus->cmd_err =i2c_recover_bus (adap);/* * After any type of error, check if LAST bit is still set, * due to a HW issue. * It cannot be cleared without resetting the module. */ -if (bus->cmd_err && - (NPCM_I2CRXF_CTL_LAST_PEC &ioread8 (bus->reg +NPCM_I2CRXF_CTL ))) +else if (bus->cmd_err && + (NPCM_I2CRXF_CTL_LAST_PEC &ioread8 (bus->reg +NPCM_I2CRXF_CTL )))npcm_i2c_reset (bus); +/* after any xfer, successful or not, stall and EOB must be disabled */ +npcm_i2c_stall_after_start (bus, false); +npcm_i2c_eob_int (bus, false); +#if IS_ENABLED (CONFIG_I2C_SLAVE )/* reenable slave if it was enabled */ if (bus->slave)iowrite8 ((bus->slave->addr &0x7F ) |NPCM_I2CADDR_SAEN , bus->reg +NPCM_I2CADDR1 ); +#else +npcm_i2c_int_enable (bus, false);#endif return bus->cmd_err; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 341/452 i2c: rcar: fix PM ref counts in probe error paths
In reply to Greg Kroah-HartmanFrom: Kuninori Morimoto <[email protected]>
[ Upstream commit 3fe2ec59db1a7569e18594b9c0cf1f4f1afd498e ]
We have to take care of ID_P_PM_BLOCKED when bailing out during probe.
--- drivers/i2c/busses/i2c-rcar.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/i2c/busses/i2c-rcar.c +9 -6
@@ -999,8 +999,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)pm_runtime_enable (dev);pm_runtime_get_sync (dev); ret =rcar_i2c_clock_calculate (priv); -if (ret <0 ) - goto out_pm_put; +if (ret <0 ) { +pm_runtime_put (dev); + goto out_pm_disable; + }rcar_i2c_write (priv,ICSAR ,0 );/* Gen2: must be 0 if not using slave */
@@ -1029,19 +1031,19 @@ static int rcar_i2c_probe(struct platform_device *pdev) ret =platform_get_irq (pdev,0 );if (ret <0 ) - goto out_pm_disable; + goto out_pm_put; priv->irq = ret; ret =devm_request_irq (dev, priv->irq, irqhandler, irqflags,dev_name (dev), priv);if (ret <0 ) {dev_err (dev,"cannot get irq %d\n" , priv->irq); - goto out_pm_disable; + goto out_pm_put; }platform_set_drvdata (pdev, priv); ret =i2c_add_numbered_adapter (adap);if (ret <0 ) - goto out_pm_disable; + goto out_pm_put;if (priv->flags &ID_P_HOST_NOTIFY ) { priv->host_notify_client =i2c_new_slave_host_notify_device (adap);
@@ -1058,7 +1060,8 @@ static int rcar_i2c_probe(struct platform_device *pdev) out_del_device:i2c_del_adapter (&priv->adap); out_pm_put: -pm_runtime_put (dev); +if (priv->flags &ID_P_PM_BLOCKED ) +pm_runtime_put (dev); out_pm_disable:pm_runtime_disable (dev);return ret;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 342/452 perf c2c: Use stdio interface if slang is not supported
In reply to Greg Kroah-HartmanFrom: Leo Yan <[email protected]>
[ Upstream commit c4040212bc97d16040712a410335f93bc94d2262 ]
If the slang lib is not installed on the system, perf c2c tool disables TUI mode and roll back to use stdio mode; but the flag 'c2c.use_stdio' is missed to set true and thus it wrongly applies UI quirks in the function ui_quirks().
This commit forces to use stdio interface if slang is not supported, and it can avoid to apply the UI quirks and show the correct metric header.
Before:
=================================================
Shared Cache Line Distribution Pareto
=================================================
-------------------------------------------------------------------------------
0 0 0 99 0 0 0 0xaaaac17d6000
-------------------------------------------------------------------------------
0.00% 0.00% 6.06% 0.00% 0.00% 0.00% 0x20 N/A 0 0xaaaac17c25ac 0 0 43 375 18469 2 [.] 0x00000000000025ac memstress memstress[25ac] 0
0.00% 0.00% 93.94% 0.00% 0.00% 0.00% 0x29 N/A 0 0xaaaac17c3e88 0 0 173 180 135 2 [.] 0x0000000000003e88 memstress memstress[3e88] 0After:
=================================================
Shared Cache Line Distribution Pareto
=================================================
-------------------------------------------------------------------------------
0 0 0 99 0 0 0 0xaaaac17d6000
-------------------------------------------------------------------------------
0.00% 0.00% 6.06% 0.00% 0.00% 0.00% 0x20 N/A 0 0xaaaac17c25ac 0 0 43 375 18469 2 [.] 0x00000000000025ac memstress memstress[25ac] 0
0.00% 0.00% 93.94% 0.00% 0.00% 0.00% 0x29 N/A 0 0xaaaac17c3e88 0 0 173 180 135 2 [.] 0x0000000000003e88 memstress memstress[3e88] 0--- tools/perf/builtin-c2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/builtin-c2c.c +4 -2
@@ -2694,9 +2694,7 @@ static int perf_c2c__report(int argc, const char **argv) "the input file to process"),OPT_INCR ('N' ,"node-info" , &c2c.node_info,"show extra node info in report (repeat for more info)" ), -#ifdef HAVE_SLANG_SUPPORTOPT_BOOLEAN (0 ,"stdio" , &c2c.use_stdio,"Use the stdio interface" ), -#endifOPT_BOOLEAN (0 ,"stats" , &c2c.stats_only,"Display only statistic tables (implies --stdio)" ), OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
@@ -2725,6 +2723,10 @@ static int perf_c2c__report(int argc, const char **argv)if (argc)usage_with_options (report_c2c_usage, options); +#ifndef HAVE_SLANG_SUPPORT + c2c.use_stdio = true; +#endif +if (c2c.stats_only) c2c.use_stdio = true;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 343/452 perf jevents: Fix event syntax error caused by ExtSel
In reply to Greg Kroah-HartmanFrom: Zhengjun Xing <[email protected]>
[ Upstream commit f4df0dbbe62ee8e4405a57b27ccd54393971c773 ]
In the origin code, when "ExtSel" is 1, the eventcode will change to "eventcode |= 1 << 21”. For event “UNC_Q_RxL_CREDITS_CONSUMED_VN0.DRS", its "ExtSel" is "1", its eventcode will change from 0x1E to 0x20001E, but in fact the eventcode should <=0x1FF, so this will cause the parse fail:
# perf stat -e "UNC_Q_RxL_CREDITS_CONSUMED_VN0.DRS" -a sleep 0.1
event syntax error: '.._RxL_CREDITS_CONSUMED_VN0.DRS'
\___ value too big for format, maximum is 511On the perf kernel side, the kernel assumes the valid bits are continuous. It will adjust the 0x100 (bit 8 for perf tool) to bit 21 in HW.
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
So the perf tool follows the kernel side and just set bit8 other than bit21.
--- tools/perf/pmu-events/jevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/pmu-events/jevents.c +1 -1
@@ -579,7 +579,7 @@ static int json_events(const char *fn, }else if (json_streq (map, field,"ExtSel" )) {char *code =NULL ;addfield (map, &code,"" ,"" , val); - eventcode |=strtoul (code,NULL ,0 ) <<21 ; + eventcode |=strtoul (code,NULL ,0 ) <<8 ;free (code); }else if (json_streq (map, field,"EventName" )) {addfield (map, &je.name,"" ,"" , val);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 344/452 f2fs: fix to avoid f2fs_bug_on() in dec_valid_node_count()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 4d17e6fe9293d57081ffdc11e1cf313e25e8fd9e upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215897
I have encountered a bug in F2FS file system in kernel v5.17.
The kernel should enable CONFIG_KASAN=y and CONFIG_KASAN_INLINE=y. You can reproduce the bug by running the following commands:
The kernel message is shown below:
kernel BUG at fs/f2fs/f2fs.h:2511!
Call Trace: f2fs_remove_inode_page+0x2a2/0x830 f2fs_evict_inode+0x9b7/0x1510 evict+0x282/0x4e0 do_unlinkat+0x33a/0x540 __x64_sys_unlinkat+0x8e/0xd0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae
The root cause is: .total_valid_block_count or .total_valid_node_count could fuzzed to zero, then once dec_valid_node_count() was called, it will cause BUG_ON(), this patch fixes to print warning info and set SBI_NEED_FSCK into CP instead of panic.
--- fs/f2fs/f2fs.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
fs/f2fs/f2fs.h +10 -4
@@ -2284,11 +2284,17 @@ static inline void dec_valid_node_count( {spin_lock (&sbi->stat_lock); -f2fs_bug_on (sbi, !sbi->total_valid_block_count); -f2fs_bug_on (sbi, !sbi->total_valid_node_count); +if (unlikely (!sbi->total_valid_block_count || + !sbi->total_valid_node_count)) { +f2fs_warn (sbi,"dec_valid_node_count: inconsistent block counts, total_valid_block:%u, total_valid_node:%u" , + sbi->total_valid_block_count, + sbi->total_valid_node_count); +set_sbi_flag (sbi,SBI_NEED_FSCK ); + }else { + sbi->total_valid_block_count--; + sbi->total_valid_node_count--; + } - sbi->total_valid_node_count--; - sbi->total_valid_block_count--;if (sbi->reserved_blocks && sbi->current_reserved_blocks < sbi->reserved_blocks) sbi->current_reserved_blocks++;
Greg Kroah-Hartman
maintainerPATCH 345/452 f2fs: fix to do sanity check on block address in f2fs_do_zero_range()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 25f8236213a91efdf708b9d77e9e51b6fc3e141c upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215894
I have encountered a bug in F2FS file system in kernel v5.17.
I have uploaded the system call sequence as case.c, and a fuzzed image can be found in google net disk
The kernel should enable CONFIG_KASAN=y and CONFIG_KASAN_INLINE=y. You can reproduce the bug by running the following commands:
kernel BUG at fs/f2fs/segment.c:2291!
Call Trace: f2fs_invalidate_blocks+0x193/0x2d0 f2fs_fallocate+0x2593/0x4a70 vfs_fallocate+0x2a5/0xac0 ksys_fallocate+0x35/0x70 __x64_sys_fallocate+0x8e/0xf0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae
The root cause is, after image was fuzzed, block mapping info in inode will be inconsistent with SIT table, so in f2fs_fallocate(), it will cause panic when updating SIT with invalid blkaddr.
Let's fix the issue by adding sanity check on block address before updating SIT table with it.
--- fs/f2fs/file.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/f2fs/file.c +12 -4
@@ -1413,11 +1413,19 @@ static int f2fs_do_zero_range(struct dno ret = -ENOSPC ;break ; } -if (dn->data_blkaddr !=NEW_ADDR ) { -f2fs_invalidate_blocks (sbi, dn->data_blkaddr); - dn->data_blkaddr =NEW_ADDR ; -f2fs_set_data_blkaddr (dn); + +if (dn->data_blkaddr ==NEW_ADDR ) +continue ; + +if (!f2fs_is_valid_blkaddr (sbi, dn->data_blkaddr, +DATA_GENERIC_ENHANCE )) { + ret = -EFSCORRUPTED ; +break ; } + +f2fs_invalidate_blocks (sbi, dn->data_blkaddr); + dn->data_blkaddr =NEW_ADDR ; +f2fs_set_data_blkaddr (dn); }f2fs_update_extent_cache_range (dn, start,0 , index - start);
Greg Kroah-Hartman
maintainerPATCH 346/452 f2fs: fix to clear dirty inode in f2fs_evict_inode()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit f2db71053dc0409fae785096ad19cce4c8a95af7 upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215904
The kernel message is shown below:
kernel BUG at fs/f2fs/inode.c:825!
Call Trace: evict+0x282/0x4e0 __dentry_kill+0x2b2/0x4d0 shrink_dentry_list+0x17c/0x4f0 shrink_dcache_parent+0x143/0x1e0 do_one_tree+0x9/0x30 shrink_dcache_for_umount+0x51/0x120 generic_shutdown_super+0x5c/0x3a0 kill_block_super+0x90/0xd0 kill_f2fs_super+0x225/0x310 deactivate_locked_super+0x78/0xc0 cleanup_mnt+0x2b7/0x480 task_work_run+0xc8/0x150 exit_to_user_mode_prepare+0x14a/0x150 syscall_exit_to_user_mode+0x1d/0x40 do_syscall_64+0x48/0x90
The root cause is: inode node and dnode node share the same nid, so during f2fs_evict_inode(), dnode node truncation will invalidate its NAT entry, so when truncating inode node, it fails due to invalid NAT entry, result in inode is still marked as dirty, fix this issue by clearing dirty for inode and setting SBI_NEED_FSCK flag in filesystem.
output from dump.f2fs:
[print_node_info: 354] Node ID [0xf:15] is inode
i_nid[0] [0x f : 15]
--- fs/f2fs/inode.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
fs/f2fs/inode.c +15 -1
@@ -757,8 +757,22 @@ retry:f2fs_lock_op (sbi); err =f2fs_remove_inode_page (inode);f2fs_unlock_op (sbi); -if (err == -ENOENT ) +if (err == -ENOENT ) { err =0 ; + +/* +* in fuzzed image, another node may has the same +* block address as inode's, if it was truncated +* previously, truncation of inode node will fail. +*/ +if (is_inode_flag_set (inode,FI_DIRTY_INODE )) { +f2fs_warn (F2FS_I_SB (inode), +"f2fs_evict_inode: inconsistent node id, ino:%lu" , + inode->i_ino); +f2fs_inode_synced (inode); +set_sbi_flag (sbi,SBI_NEED_FSCK ); + } + } }/* give more chances, if ENOMEM case */
Greg Kroah-Hartman
maintainerPATCH 347/452 f2fs: fix deadloop in foreground GC
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit cfd66bb715fd11fde3338d0660cffa1396adc27d upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215914
The root cause is: in a very small sized image, it's very easy to exceed threshold of foreground GC, if we calculate free space and dirty data based on section granularity, in corner case, has_not_enough_free_secs() will always return true, result in deadloop in f2fs_gc().
So this patch refactors has_not_enough_free_secs() as below to fix this issue:
1. calculate needed space based on block granularity, and separate all blocks to two parts, section part, and block part, comparing section part to free section, and comparing block part to free space in openned log.
2. account F2FS_DIRTY_NODES, F2FS_DIRTY_IMETA and F2FS_DIRTY_DENTS as node block consumer;
3. account F2FS_DIRTY_DENTS as data block consumer;
--- fs/f2fs/segment.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
fs/f2fs/segment.h +20 -12
@@ -573,11 +573,10 @@ static inline int reserved_sections(strureturn GET_SEC_FROM_SEG (sbi,reserved_segments (sbi)); } -static inline bool has_curseg_enough_space (struct f2fs_sb_info *sbi) +static inline bool has_curseg_enough_space (struct f2fs_sb_info *sbi, +unsigned int node_blocks,unsigned int dent_blocks) { -unsigned int node_blocks =get_pages (sbi,F2FS_DIRTY_NODES ) + -get_pages (sbi,F2FS_DIRTY_DENTS ); -unsigned int dent_blocks =get_pages (sbi,F2FS_DIRTY_DENTS ); +unsigned int segno, left_blocks;int i;
@@ -603,19 +602,28 @@ static inline bool has_curseg_enough_spastatic inline bool has_not_enough_free_secs (struct f2fs_sb_info *sbi,int freed,int needed) { -int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES ); -int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); -int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA ); +unsigned int total_node_blocks =get_pages (sbi,F2FS_DIRTY_NODES ) + +get_pages (sbi,F2FS_DIRTY_DENTS ) + +get_pages (sbi,F2FS_DIRTY_IMETA ); +unsigned int total_dent_blocks =get_pages (sbi,F2FS_DIRTY_DENTS ); +unsigned int node_secs = total_node_blocks /BLKS_PER_SEC (sbi); +unsigned int dent_secs = total_dent_blocks /BLKS_PER_SEC (sbi); +unsigned int node_blocks = total_node_blocks %BLKS_PER_SEC (sbi); +unsigned int dent_blocks = total_dent_blocks %BLKS_PER_SEC (sbi); +unsigned int free, need_lower, need_upper;if (unlikely (is_sbi_flag_set (sbi,SBI_POR_DOING )))return false; -if (free_sections (sbi) + freed ==reserved_sections (sbi) + needed && -has_curseg_enough_space (sbi)) + free =free_sections (sbi) + freed; + need_lower = node_secs + dent_secs +reserved_sections (sbi) + needed; + need_upper = need_lower + (node_blocks ?1 :0 ) + (dent_blocks ?1 :0 ); + +if (free > need_upper)return false; -return (free_sections (sbi) + freed) <= - (node_secs +2 * dent_secs + imeta_secs + -reserved_sections (sbi) + needed); +else if (free <= need_lower) +return true; +return !has_curseg_enough_space (sbi, node_blocks, dent_blocks); }static inline bool f2fs_is_checkpoint_ready (struct f2fs_sb_info *sbi)
Greg Kroah-Hartman
maintainerPATCH 348/452 f2fs: dont need inode lock for system hidden quota
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit 6213f5d4d23c50d393a31dc8e351e63a1fd10dbe upstream.
Let's avoid false-alarmed lockdep warning.
[ 58.914674] [T1501146] -> #2 (&sb->s_type->i_mutex_key#20){+.+.}-{3:3}:
[ 58.915975] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.916738] [T1501146] system_server: f2fs_quota_sync+0x60/0x1a8
[ 58.917563] [T1501146] system_server: block_operations+0x16c/0x43c
[ 58.918410] [T1501146] system_server: f2fs_write_checkpoint+0x114/0x318
[ 58.919312] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
[ 58.920214] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.920999] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
[ 58.921862] [T1501146] system_server: f2fs_sync_file+0x30/0x48
[ 58.922667] [T1501146] system_server: __arm64_sys_fsync+0x84/0xf8
[ 58.923506] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
[ 58.924604] [T1501146] system_server: do_el0_svc+0x28/0xa0
[ 58.925366] [T1501146] system_server: el0_svc+0x24/0x38
[ 58.926094] [T1501146] system_server: el0_sync_handler+0x88/0xec
[ 58.926920] [T1501146] system_server: el0_sync+0x1b4/0x1c0[ 58.927681] [T1501146] -> #1 (&sbi->cp_global_sem){+.+.}-{3:3}:
[ 58.928889] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.929650] [T1501146] system_server: f2fs_write_checkpoint+0xbc/0x318
[ 58.930541] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
[ 58.931443] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.932226] [T1501146] system_server: sync_filesystem+0xac/0x130
[ 58.933053] [T1501146] system_server: generic_shutdown_super+0x38/0x150
[ 58.933958] [T1501146] system_server: kill_block_super+0x24/0x58
[ 58.934791] [T1501146] system_server: kill_f2fs_super+0xcc/0x124
[ 58.935618] [T1501146] system_server: deactivate_locked_super+0x90/0x120
[ 58.936529] [T1501146] system_server: deactivate_super+0x74/0xac
[ 58.937356] [T1501146] system_server: cleanup_mnt+0x128/0x168
[ 58.938150] [T1501146] system_server: __cleanup_mnt+0x18/0x28
[ 58.938944] [T1501146] system_server: task_work_run+0xb8/0x14c
[ 58.939749] [T1501146] system_server: do_notify_resume+0x114/0x1e8
[ 58.940595] [T1501146] system_server: work_pending+0xc/0x5f0[ 58.941375] [T1501146] -> #0 (&sbi->gc_lock){+.+.}-{3:3}:
[ 58.942519] [T1501146] system_server: __lock_acquire+0x1270/0x2868
[ 58.943366] [T1501146] system_server: lock_acquire+0x114/0x294
[ 58.944169] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.944930] [T1501146] system_server: f2fs_issue_checkpoint+0x13c/0x21c
[ 58.945831] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.946614] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
[ 58.947472] [T1501146] system_server: f2fs_ioc_commit_atomic_write+0xc8/0x14c
[ 58.948439] [T1501146] system_server: __f2fs_ioctl+0x674/0x154c
[ 58.949253] [T1501146] system_server: f2fs_ioctl+0x54/0x88
[ 58.950018] [T1501146] system_server: __arm64_sys_ioctl+0xa8/0x110
[ 58.950865] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
[ 58.951965] [T1501146] system_server: do_el0_svc+0x28/0xa0
[ 58.952727] [T1501146] system_server: el0_svc+0x24/0x38
[ 58.953454] [T1501146] system_server: el0_sync_handler+0x88/0xec
[ 58.954279] [T1501146] system_server: el0_sync+0x1b4/0x1c0--- fs/f2fs/super.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/f2fs/super.c +4 -2
@@ -2292,7 +2292,8 @@ int f2fs_quota_sync(struct super_block *if (!sb_has_quota_active (sb, cnt))continue ; -inode_lock (dqopt->files[cnt]); +if (!f2fs_sb_has_quota_ino (sbi)) +inode_lock (dqopt->files[cnt]);/* * do_quotactl
@@ -2311,7 +2312,8 @@ int f2fs_quota_sync(struct super_block *up_read (&sbi->quota_sem);f2fs_unlock_op (sbi); -inode_unlock (dqopt->files[cnt]); +if (!f2fs_sb_has_quota_ino (sbi)) +inode_unlock (dqopt->files[cnt]);if (ret)break ;
Greg Kroah-Hartman
maintainerPATCH 349/452 f2fs: fix to do sanity check on total_data_blocks
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 6b8beca0edd32075a769bfe4178ca00c0dcd22a9 upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215916
The kernel message is shown below:
kernel BUG at fs/f2fs/segment.c:2560!
Call Trace: allocate_segment_by_default+0x228/0x440 f2fs_allocate_data_block+0x13d1/0x31f0 do_write_page+0x18d/0x710 f2fs_outplace_write_data+0x151/0x250 f2fs_do_write_data_page+0xef9/0x1980 move_data_page+0x6af/0xbc0 do_garbage_collect+0x312f/0x46f0 f2fs_gc+0x6b0/0x3bc0 f2fs_balance_fs+0x921/0x2260 f2fs_write_single_data_page+0x16be/0x2370 f2fs_write_cache_pages+0x428/0xd00 f2fs_write_data_pages+0x96e/0xd50 do_writepages+0x168/0x550 __writeback_single_inode+0x9f/0x870 writeback_sb_inodes+0x47d/0xb20 __writeback_inodes_wb+0xb2/0x200 wb_writeback+0x4bd/0x660 wb_workfn+0x5f3/0xab0 process_one_work+0x79f/0x13e0 worker_thread+0x89/0xf60 kthread+0x26a/0x300 ret_from_fork+0x22/0x30 RIP: 0010:new_curseg+0xe8d/0x15f0
The root cause is: ckpt.valid_block_count is inconsistent with SIT table, stat info indicates filesystem has free blocks, but SIT table indicates filesystem has no free segment.
So that during garbage colloection, it triggers panic when LFS allocator fails to find free segment.
This patch tries to fix this issue by checking consistency in between ckpt.valid_block_count and block accounted from SIT.
--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/segment.c | 33 ++++++++++++++++++++++----------- fs/f2fs/segment.h | 1 + 3 files changed, 25 insertions(+), 13 deletions(-)
fs/f2fs/f2fs.h +2 -2
@@ -1021,8 +1021,8 @@ enum count_type {*/ #define PAGE_TYPE_OF_BIO (type) ((type) > META ? META : (type))enum page_type { -DATA , -NODE , +DATA =0 , +NODE =1 ,/* should not change this */ META ,NR_PAGE_TYPE ,META_FLUSH ,
fs/f2fs/segment.c +22 -11
@@ -4423,7 +4423,7 @@ static int build_sit_entries(struct f2fsunsigned int i, start, end;unsigned int readed, start_blk =0 ;int err =0 ; -block_t total_node_blocks =0 ; +block_t sit_valid_blocks[2 ] = {0 ,0 }; do { readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
@@ -4448,8 +4448,8 @@ static int build_sit_entries(struct f2fsif (err)return err;seg_info_from_raw_sit (se, &sit); -if (IS_NODESEG (se->type)) - total_node_blocks += se->valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] += se->valid_blocks;/* build discard map only one time */ if (is_set_ckpt_flags (sbi,CP_TRIMMED_FLAG )) {
@@ -4487,15 +4487,15 @@ static int build_sit_entries(struct f2fs sit =sit_in_journal (journal, i); old_valid_blocks = se->valid_blocks; -if (IS_NODESEG (se->type)) - total_node_blocks -= old_valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] -= old_valid_blocks; err =check_block_count (sbi, start, &sit);if (err)break ;seg_info_from_raw_sit (se, &sit); -if (IS_NODESEG (se->type)) - total_node_blocks += se->valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] += se->valid_blocks;if (is_set_ckpt_flags (sbi,CP_TRIMMED_FLAG )) {memset (se->discard_map,0xff ,SIT_VBLOCK_MAP_SIZE );
@@ -4515,13 +4515,24 @@ static int build_sit_entries(struct f2fs }up_read (&curseg->journal_rwsem); -if (!err && total_node_blocks !=valid_node_count (sbi)) { +if (err) +return err; + +if (sit_valid_blocks[NODE ] !=valid_node_count (sbi)) {f2fs_err (sbi,"SIT is corrupted node# %u vs %u" , - total_node_blocks,valid_node_count (sbi)); - err = -EFSCORRUPTED ; + sit_valid_blocks[NODE ],valid_node_count (sbi)); +return -EFSCORRUPTED ; + } + +if (sit_valid_blocks[DATA ] + sit_valid_blocks[NODE ] > +valid_user_blocks (sbi)) { +f2fs_err (sbi,"SIT is corrupted data# %u %u vs %u" , + sit_valid_blocks[DATA ], sit_valid_blocks[NODE ], +valid_user_blocks (sbi)); +return -EFSCORRUPTED ; } -return err; +return 0 ; }static void init_free_segmap (struct f2fs_sb_info *sbi)
fs/f2fs/segment.h +1 -0
@@ -24,6 +24,7 @@#define IS_DATASEG (t) ((t) <= CURSEG_COLD_DATA)#define IS_NODESEG (t) ((t) >= CURSEG_HOT_NODE && (t) <= CURSEG_COLD_NODE) +#define SE_PAGETYPE (se) ((IS_NODESEG((se)->type) ? NODE : DATA))static inline void sanity_check_seg_type (struct f2fs_sb_info *sbi,unsigned short seg_type)
Greg Kroah-Hartman
maintainerPATCH 350/452 f2fs: fix fallocate to use file_modified to update permissions consistently
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 958ed92922028ec67f504dcdc72bfdfd0f43936a upstream.
This patch tries to fix permission consistency issue as all other mainline filesystems.
Since the initial introduction of (posix) fallocate back at the turn of the century, it has been possible to use this syscall to change the user-visible contents of files. This can happen by extending the file size during a preallocation, or through any of the newer modes (punch, zero, collapse, insert range). Because the call can be used to change file contents, we should treat it like we do any other modification to a file -- update the mtime, and drop set[ug]id privileges/capabilities.
The VFS function file_modified() does all this for us if pass it a locked inode, so let's make fallocate drop permissions correctly.
--- fs/f2fs/file.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/f2fs/file.c +4 -0
@@ -1744,6 +1744,10 @@ static long f2fs_fallocate(struct file *inode_lock (inode); + ret =file_modified (file); +if (ret) + goto out; +if (mode &FALLOC_FL_PUNCH_HOLE ) {if (offset >= inode->i_size) goto out;
Greg Kroah-Hartman
maintainerPATCH 351/452 f2fs: fix to do sanity check for inline inode
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 677a82b44ebf263d4f9a0cfbd576a6ade797a07b upstream.
Yanming reported a kernel bug in Bugzilla kernel [1], which can be reproduced. The bug message is:
The kernel message is shown below:
kernel BUG at fs/inode.c:611!
Call Trace: evict+0x282/0x4e0 __dentry_kill+0x2b2/0x4d0 dput+0x2dd/0x720 do_renameat2+0x596/0x970 __x64_sys_rename+0x78/0x90 do_syscall_64+0x3b/0x90
[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895
The bug is due to fuzzed inode has both inline_data and encrypted flags. During f2fs_evict_inode(), as the inode was deleted by rename(), it will cause inline data conversion due to conflicting flags. The page cache will be polluted and the panic will be triggered in clear_inode().
Try fixing the bug by doing more sanity checks for inline data inode in sanity_check_inode().
--- fs/f2fs/f2fs.h | 1 + fs/f2fs/inline.c | 29 ++++++++++++++++++++++++----- fs/f2fs/inode.c | 3 +-- 3 files changed, 26 insertions(+), 7 deletions(-)
fs/f2fs/f2fs.h +1 -0
@@ -3735,6 +3735,7 @@ extern struct kmem_cache *f2fs_inode_ent* inline.c */ bool f2fs_may_inline_data (struct inode *inode); +bool f2fs_sanity_check_inline_data (struct inode *inode);bool f2fs_may_inline_dentry (struct inode *inode);void f2fs_do_read_inline_data (struct page *page,struct page *ipage); void f2fs_truncate_inline_inode(struct inode *inode,
fs/f2fs/inline.c +24 -5
@@ -14,21 +14,40 @@#include "node.h" #include <trace/events/f2fs.h> -bool f2fs_may_inline_data (struct inode *inode) +static bool support_inline_data (struct inode *inode) {if (f2fs_is_atomic_file (inode))return false; -if (!S_ISREG (inode->i_mode) && !S_ISLNK (inode->i_mode))return false; -if (i_size_read (inode) >MAX_INLINE_DATA (inode))return false; +return true; +} + +bool f2fs_may_inline_data (struct inode *inode) +{ +if (!support_inline_data (inode)) +return false; + +return !f2fs_post_read_required (inode); +} -if (f2fs_post_read_required (inode)) +bool f2fs_sanity_check_inline_data (struct inode *inode) +{ +if (!f2fs_has_inline_data (inode))return false; -return true; +if (!support_inline_data (inode)) +return true; + +/* +* used by sanity_check_inode(), when disk layout fields has not +* been synchronized to inmem fields. +*/ +return (S_ISREG (inode->i_mode) && + (file_is_encrypt (inode) ||file_is_verity (inode) || + (F2FS_I (inode)->i_flags &F2FS_COMPR_FL ))); }bool f2fs_may_inline_dentry (struct inode *inode)
fs/f2fs/inode.c +1 -2
@@ -272,8 +272,7 @@ static bool sanity_check_inode(struct in } } -if (f2fs_has_inline_data (inode) && - (!S_ISREG (inode->i_mode) && !S_ISLNK (inode->i_mode))) { +if (f2fs_sanity_check_inline_data (inode)) {set_sbi_flag (sbi,SBI_NEED_FSCK );f2fs_warn (sbi,"%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix" , __func__, inode->i_ino, inode->i_mode);
Greg Kroah-Hartman
maintainerPATCH 352/452 wifi: mac80211: fix use-after-free in chanctx code
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 2965c4cdf7ad9ce0796fac5e57debb9519ea721e upstream.
In ieee80211_vif_use_reserved_context(), when we have an old context and the new context's replace_state is set to IEEE80211_CHANCTX_REPLACE_NONE, we free the old context in ieee80211_vif_use_reserved_reassign(). Therefore, we cannot check the old_ctx anymore, so we should set it to NULL after this point.
However, since the new_ctx replace state is clearly not IEEE80211_CHANCTX_REPLACES_OTHER, we're not going to do anything else in this function and can just return to avoid accessing the freed old_ctx.
--- net/mac80211/chan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
net/mac80211/chan.c +2 -5
@@ -1652,12 +1652,9 @@ int ieee80211_vif_use_reserved_context(sif (new_ctx->replace_state ==IEEE80211_CHANCTX_REPLACE_NONE ) {if (old_ctx) - err =ieee80211_vif_use_reserved_reassign (sdata); -else - err =ieee80211_vif_use_reserved_assign (sdata); +return ieee80211_vif_use_reserved_reassign (sdata); -if (err) -return err; +return ieee80211_vif_use_reserved_assign (sdata); }/*
Greg Kroah-Hartman
maintainerPATCH 353/452 iwlwifi: mvm: fix assert 1F04 upon reconfig
In reply to Greg Kroah-HartmanFrom: Emmanuel Grumbach <[email protected]>
commit 9d096e3d3061dbf4ee10e2b59fc2c06e05bdb997 upstream.
When we reconfig we must not send the MAC_POWER command that relates to a MAC that was not yet added to the firmware.
Ignore those in the iterator.
--- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/power.c +3 -0
@@ -621,6 +621,9 @@ static void iwl_mvm_power_get_vifs_iterastruct iwl_power_vifs *power_iterator = _data;bool active = mvmvif->phy_ctxt && mvmvif->phy_ctxt->id <NUM_PHY_CTX ; +if (!mvmvif->uploaded) +return ; +switch (ieee80211_vif_type_p2p (vif)) {case NL80211_IFTYPE_P2P_DEVICE :break ;
Greg Kroah-Hartman
maintainerPATCH 354/452 fs-writeback: writeback_sb_inodes:Recalculate wrote according skipped pages
In reply to Greg Kroah-HartmanFrom: Zhihao Cheng <[email protected]>
commit 68f4c6eba70df70a720188bce95c85570ddfcc87 upstream.
Commit 505a666ee3fc ("writeback: plug writeback in wb_writeback() and writeback_inodes_wb()") has us holding a plug during wb_writeback, which may cause a potential ABBA dead lock:
wb_writeback fat_file_fsyncblk_start_plug(&plug)
for (;;) {
iter i-1: some reqs have been added into plug->mq_list // LOCK A iter i:
progress = __writeback_inodes_wb(wb, work)
. writeback_sb_inodes // fat's bdev
. __writeback_single_inode
. . generic_writepages
. . __block_write_full_page
. . . . __generic_file_fsync
. . . . sync_inode_metadata
. . . . writeback_single_inode
. . . . __writeback_single_inode
. . . . fat_write_inode
. . . . __fat_write_inode
. . . . sync_dirty_buffer // fat's bdev
. . . . lock_buffer(bh) // LOCK B
. . . . submit_bh
. . . . blk_mq_get_tag // LOCK A
. . . trylock_buffer(bh) // LOCK B
. . . redirty_page_for_writepage
. . . wbc->pages_skipped++
. . --wbc->nr_to_write
. wrote += write_chunk - wbc.nr_to_write // wrote > 0
. requeue_inode
. redirty_tail_locked
if (progress) // progress > 0
continue;
iter i+1:
queue_io
// similar process with iter i, infinite for-loop !
}blk_finish_plug(&plug) // flush plug won't be called
Above process triggers a hungtask like:
[ 399.044861] INFO: task bb:2607 blocked for more than 30 seconds. [ 399.046824] Not tainted 5.18.0-rc1-00005-gefae4d9eb6a2-dirty [ 399.051539] task:bb state:D stack: 0 pid: 2607 ppid: 2426 flags:0x00004000 [ 399.051556] Call Trace: [ 399.051570] __schedule+0x480/0x1050 [ 399.051592] schedule+0x92/0x1a0 [ 399.051602] io_schedule+0x22/0x50 [ 399.051613] blk_mq_get_tag+0x1d3/0x3c0 [ 399.051640] __blk_mq_alloc_requests+0x21d/0x3f0 [ 399.051657] blk_mq_submit_bio+0x68d/0xca0 [ 399.051674] __submit_bio+0x1b5/0x2d0 [ 399.051708] submit_bio_noacct+0x34e/0x720 [ 399.051718] submit_bio+0x3b/0x150 [ 399.051725] submit_bh_wbc+0x161/0x230 [ 399.051734] __sync_dirty_buffer+0xd1/0x420 [ 399.051744] sync_dirty_buffer+0x17/0x20 [ 399.051750] __fat_write_inode+0x289/0x310 [ 399.051766] fat_write_inode+0x2a/0xa0 [ 399.051783] __writeback_single_inode+0x53c/0x6f0 [ 399.051795] writeback_single_inode+0x145/0x200 [ 399.051803] sync_inode_metadata+0x45/0x70 [ 399.051856] __generic_file_fsync+0xa3/0x150 [ 399.051880] fat_file_fsync+0x1d/0x80 [ 399.051895] vfs_fsync_range+0x40/0xb0 [ 399.051929] __x64_sys_fsync+0x18/0x30
In my test, 'need_resched()' (which is imported by 590dca3a71 "fs-writeback:
unplug before cond_resched in writeback_sb_inodes") in function 'writeback_sb_inodes()' seldom comes true, unless cond_resched() is deleted from write_cache_pages().
Fix it by correcting wrote number according number of skipped pages in writeback_sb_inodes().
Goto Link to find a reproducer.
--- fs/fs-writeback.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
fs/fs-writeback.c +8 -5
@@ -1650,11 +1650,12 @@ static long writeback_sb_inodes(struct s };unsigned long start_time = jiffies;long write_chunk; -long wrote =0 ;/* count both pages and inodes */ +long total_wrote =0 ;/* count both pages and inodes */ while (!list_empty (&wb->b_io)) {struct inode *inode =wb_inode (wb->b_io.prev);struct bdi_writeback *tmp_wb; +long wrote;if (inode->i_sb != sb) {if (work->sb) {
@@ -1730,7 +1731,9 @@ static long writeback_sb_inodes(struct swbc_detach_inode (&wbc); work->nr_pages -= write_chunk - wbc.nr_to_write; - wrote += write_chunk - wbc.nr_to_write; + wrote = write_chunk - wbc.nr_to_write - wbc.pages_skipped; + wrote = wrote <0 ?0 : wrote; + total_wrote += wrote;if (need_resched ()) {/*
@@ -1752,7 +1755,7 @@ static long writeback_sb_inodes(struct s tmp_wb =inode_to_wb_and_lock_list (inode);spin_lock (&inode->i_lock);if (!(inode->i_state &I_DIRTY_ALL )) - wrote++; + total_wrote++;requeue_inode (inode, tmp_wb, &wbc);inode_sync_complete (inode);spin_unlock (&inode->i_lock);
@@ -1766,14 +1769,14 @@ static long writeback_sb_inodes(struct s* bail out to wb_writeback() often enough to check * background threshold and other termination conditions. */ -if (wrote) { +if (total_wrote) {if (time_is_before_jiffies (start_time +HZ /10UL ))break ;if (work->nr_pages <=0 )break ; } } -return wrote; +return total_wrote; } static long __writeback_inodes_wb(struct bdi_writeback *wb,
Greg Kroah-Hartman
maintainerPATCH 355/452 efi: Do not import certificates from UEFI Secure Boot for T2 Macs
In reply to Greg Kroah-HartmanFrom: Aditya Garg <[email protected]>
commit 155ca952c7ca19aa32ecfb7373a32bbc2e1ec6eb upstream.
On Apple T2 Macs, when Linux attempts to read the db and dbx efi variables at early boot to load UEFI Secure Boot certificates, a page fault occurs in Apple firmware code and EFI runtime services are disabled with the following logs:
[Firmware Bug]: Page fault caused by firmware at PA: 0xffffb1edc0068000
WARNING: CPU: 3 PID: 104 at arch/x86/platform/efi/quirks.c:735 efi_crash_gracefully_on_page_fault+0x50/0xf0 (Removed some logs from here) Call Trace: <TASK> page_fault_oops+0x4f/0x2c0 ? search_bpf_extables+0x6b/0x80 ? search_module_extables+0x50/0x80 ? search_exception_tables+0x5b/0x60 kernelmode_fixup_or_oops+0x9e/0x110 __bad_area_nosemaphore+0x155/0x190 bad_area_nosemaphore+0x16/0x20 do_kern_addr_fault+0x8c/0xa0 exc_page_fault+0xd8/0x180 asm_exc_page_fault+0x1e/0x30 (Removed some logs from here) ? __efi_call+0x28/0x30 ? switch_mm+0x20/0x30 ? efi_call_rts+0x19a/0x8e0 ? process_one_work+0x222/0x3f0 ? worker_thread+0x4a/0x3d0 ? kthread+0x17a/0x1a0 ? process_one_work+0x3f0/0x3f0 ? set_kthread_struct+0x40/0x40 ? ret_from_fork+0x22/0x30 </TASK> ---[ end trace 1f82023595a5927f ]---
efi: Froze efi_rts_wq and disabled EFI Runtime Services
integrity: Couldn't get size: 0x8000000000000015
integrity: MODSIGN: Couldn't get UEFI db list
efi: EFI Runtime Services are disabled!
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get UEFI dbx list
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get mokx list
integrity: Couldn't get size: 0x80000000
So we avoid reading these UEFI variables and thus prevent the crash.
--- security/integrity/platform_certs/keyring_handler.h | 8 ++++ security/integrity/platform_certs/load_uefi.c | 33 ++++++++++++++++++++ 2 files changed, 41 insertions(+)
security/integrity/platform_certs/keyring_handler.h +8 -0
@@ -30,3 +30,11 @@ efi_element_handler_t get_handler_for_dbefi_element_handler_t get_handler_for_dbx (const efi_guid_t *sig_type);#endif + +#ifndef UEFI_QUIRK_SKIP_CERT +#define UEFI_QUIRK_SKIP_CERT (vendor, product) \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_MATCH(DMI_PRODUCT_NAME, product), \ + }, +#endif
security/integrity/platform_certs/load_uefi.c +33 -0
@@ -3,6 +3,7 @@#include <linux/kernel.h> #include <linux/sched.h> #include <linux/cred.h> +#include <linux/dmi.h> #include <linux/err.h> #include <linux/efi.h> #include <linux/slab.h>
@@ -12,6 +13,31 @@#include "keyring_handler.h" /* +* On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot +* certificates causes occurrence of a page fault in Apple's firmware and +* a crash disabling EFI runtime services. The following quirk skips reading +* these variables. +*/ +static const struct dmi_system_id uefi_skip_cert[] = { + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,3" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,4" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,3" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,4" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir8,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir8,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir9,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacMini8,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacPro7,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"iMac20,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"iMac20,2" ) }, + { } +}; + +/* * Look to see if a UEFI variable called MokIgnoreDB exists and return true if * it does. *
@@ -137,6 +163,13 @@ static int __init load_uefi_certs(void)unsigned long dbsize =0 , dbxsize =0 , mokxsize =0 ;efi_status_t status;int rc =0 ; +const struct dmi_system_id *dmi_id; + + dmi_id =dmi_first_match (uefi_skip_cert); +if (dmi_id) { +pr_err ("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n" ); +return false; + }if (!efi_rt_services_supported (EFI_RT_SUPPORTED_GET_VARIABLE ))return false;
Greg Kroah-Hartman
maintainerPATCH 356/452 bfq: Split shared queues on move between cgroups
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 3bc5e683c67d94bd839a1da2e796c15847b51b69 upstream.
When bfqq is shared by multiple processes it can happen that one of the processes gets moved to a different cgroup (or just starts submitting IO for different cgroup). In case that happens we need to split the merged bfqq as otherwise we will have IO for multiple cgroups in one bfqq and we will just account IO time to wrong entities etc.
Similarly if the bfqq is scheduled to merge with another bfqq but the merge didn't happen yet, cancel the merge as it need not be valid anymore.
--- block/bfq-cgroup.c | 36 +++++++++++++++++++++++++++++++++--- block/bfq-iosched.c | 2 +- block/bfq-iosched.h | 1 + 3 files changed, 35 insertions(+), 4 deletions(-)
block/bfq-cgroup.c +33 -3
@@ -725,9 +725,39 @@ static struct bfq_group *__bfq_bic_chang }if (sync_bfqq) { - entity = &sync_bfqq->entity; -if (entity->sched_data != &bfqg->sched_data) -bfq_bfqq_move (bfqd, sync_bfqq, bfqg); +if (!sync_bfqq->new_bfqq && !bfq_bfqq_coop (sync_bfqq)) { +/* We are the only user of this bfqq, just move it */ +if (sync_bfqq->entity.sched_data != &bfqg->sched_data) +bfq_bfqq_move (bfqd, sync_bfqq, bfqg); + }else { +struct bfq_queue *bfqq; + +/* +* The queue was merged to a different queue. Check +* that the merge chain still belongs to the same +* cgroup. +*/ +for (bfqq = sync_bfqq; bfqq; bfqq = bfqq->new_bfqq) +if (bfqq->entity.sched_data != + &bfqg->sched_data) +break ; +if (bfqq) { +/* +* Some queue changed cgroup so the merge is +* not valid anymore. We cannot easily just +* cancel the merge (by clearing new_bfqq) as +* there may be other processes using this +* queue and holding refs to all queues below +* sync_bfqq->new_bfqq. Similarly if the merge +* already happened, we need to detach from +* bfqq now so that we cannot merge bio to a +* request from the old cgroup. +*/ +bfq_put_cooperator (sync_bfqq); +bfq_release_process_ref (bfqd, sync_bfqq); +bic_set_bfqq (bic,NULL ,1 ); + } + } }return bfqg;
block/bfq-iosched.c +1 -1
@@ -4917,7 +4917,7 @@ void bfq_put_queue(struct bfq_queue *bfqbfqg_and_blkg_put (bfqg); } -static void bfq_put_cooperator (struct bfq_queue *bfqq) +void bfq_put_cooperator (struct bfq_queue *bfqq) {struct bfq_queue *__bfqq, *next;
block/bfq-iosched.h +1 -0
@@ -954,6 +954,7 @@ void bfq_weights_tree_remove(struct bfq_void bfq_bfqq_expire (struct bfq_data *bfqd,struct bfq_queue *bfqq,bool compensate,enum bfqq_expiration reason);void bfq_put_queue (struct bfq_queue *bfqq); +void bfq_put_cooperator (struct bfq_queue *bfqq);void bfq_end_wr_async_queues (struct bfq_data *bfqd,struct bfq_group *bfqg);void bfq_release_process_ref (struct bfq_data *bfqd,struct bfq_queue *bfqq);void bfq_schedule_dispatch (struct bfq_data *bfqd);
Greg Kroah-Hartman
maintainerPATCH 357/452 bfq: Update cgroup information before merging bio
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit ea591cd4eb270393810e7be01feb8fde6a34fbbe upstream.
When the process is migrated to a different cgroup (or in case of writeback just starts submitting bios associated with a different cgroup) bfq_merge_bio() can operate with stale cgroup information in bic. Thus the bio can be merged to a request from a different cgroup or it can result in merging of bfqqs for different cgroups or bfqqs of already dead cgroups and causing possible use-after-free issues. Fix the problem by updating cgroup information in bfq_merge_bio().
--- block/bfq-iosched.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
block/bfq-iosched.c +9 -2
@@ -2227,10 +2227,17 @@ static bool bfq_bio_merge(struct requestspin_lock_irq (&bfqd->lock); -if (bic) +if (bic) { +/* +* Make sure cgroup info is uptodate for current process before +* considering the merge. +*/ +bfq_bic_update_cgroup (bic, bio); + bfqd->bio_bfqq =bic_to_bfqq (bic,op_is_sync (bio->bi_opf)); -else + }else { bfqd->bio_bfqq =NULL ; + } bfqd->bio_bic = bic; ret =blk_mq_sched_try_merge (q, bio, nr_segs, &free);
Greg Kroah-Hartman
maintainerPATCH 358/452 bfq: Track whether bfq_group is still online
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 09f871868080c33992cd6a9b72a5ca49582578fa upstream.
Track whether bfq_group is still online. We cannot rely on blkcg_gq->online because that gets cleared only after all policies are offlined and we need something that gets updated already under bfqd->lock when we are cleaning up our bfq_group to be able to guarantee that when we see online bfq_group, it will stay online while we are holding bfqd->lock lock.
--- block/bfq-cgroup.c | 3 ++- block/bfq-iosched.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
block/bfq-cgroup.c +2 -1
@@ -553,6 +553,7 @@ static void bfq_pd_init(struct blkg_poli*/ bfqg->bfqd = bfqd; bfqg->active_entities =0 ; + bfqg->online = true; bfqg->rq_pos_tree =RB_ROOT ; }
@@ -599,7 +600,6 @@ struct bfq_group *bfq_find_set_group(strstruct bfq_entity *entity; bfqg =bfq_lookup_bfqg (bfqd, blkcg); -if (unlikely (!bfqg))return NULL ;
@@ -961,6 +961,7 @@ static void bfq_pd_offline(struct blkg_p put_async_queues:bfq_put_async_queues (bfqd, bfqg); + bfqg->online = false;spin_unlock_irqrestore (&bfqd->lock, flags);/*
block/bfq-iosched.h +2 -0
@@ -901,6 +901,8 @@ struct bfq_group {/* reference counter (see comments in bfq_bic_update_cgroup) */ int ref; +/* Is bfq_group still online? */ +bool online;struct bfq_entity entity;struct bfq_sched_data sched_data;
Greg Kroah-Hartman
maintainerPATCH 359/452 ext4: fix use-after-free in ext4_rename_dir_prepare
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 0be698ecbe4471fcad80e81ec6a05001421041b3 upstream.
We got issue as follows:
EXT4-fs (loop0): mounted filesystem without journal. Opts: ,errors=continueext4_get_first_dir_block: bh->b_data=0xffff88810bee6000 len=34478ext4_get_first_dir_block: *parent_de=0xffff88810beee6ae bh->b_data=0xffff88810bee6000ext4_rename_dir_prepare: [1] parent_de=0xffff88810beee6ae
==================================================================
BUG: KASAN: use-after-free in ext4_rename_dir_prepare+0x152/0x220
Read of size 4 at addr ffff88810beee6ae by task rep/1895
CPU: 13 PID: 1895 Comm: rep Not tainted 5.10.0+ #241
Call Trace:
dump_stack+0xbe/0xf9
print_address_description.constprop.0+0x1e/0x220
kasan_report.cold+0x37/0x7f
ext4_rename_dir_prepare+0x152/0x220
ext4_rename+0xf44/0x1ad0
ext4_rename2+0x11c/0x170
vfs_rename+0xa84/0x1440
do_renameat2+0x683/0x8f0
__x64_sys_renameat+0x53/0x60
do_syscall_64+0x33/0x40
entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x7f45a6fc41c9
RSP: 002b:00007ffc5a470218 EFLAGS: 00000246 ORIG_RAX: 0000000000000108
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f45a6fc41c9
RDX: 0000000000000005 RSI: 0000000020000180 RDI: 0000000000000005
RBP: 00007ffc5a470240 R08: 00007ffc5a470160 R09: 0000000020000080
R10: 00000000200001c0 R11: 0000000000000246 R12: 0000000000400bb0
R13: 00007ffc5a470320 R14: 0000000000000000 R15: 0000000000000000
The buggy address belongs to the page:
page:00000000440015ce refcount:0 mapcount:0 mapping:0000000000000000 index:0x1 pfn:0x10beee
flags: 0x200000000000000()
raw: 0200000000000000 ffffea00043ff4c8 ffffea0004325608 0000000000000000
raw: 0000000000000001 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88810beee580: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff88810beee600: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff88810beee680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff88810beee700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff88810beee780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================Disabling lock debugging due to kernel taintext4_rename_dir_prepare: [2] parent_de->inode=3537895424ext4_rename_dir_prepare: [3] dir=0xffff888124170140ext4_rename_dir_prepare: [4] ino=2ext4_rename_dir_prepare: ent->dir->i_ino=2 parent=-757071872
Reason is first directory entry which 'rec_len' is 34478, then will get illegal parent entry. Now, we do not check directory entry after read directory block in 'ext4_get_first_dir_block'.
To solve this issue, check directory entry in 'ext4_get_first_dir_block'.
[ Trigger an ext4_error() instead of just warning if the directory is
missing a '.' or '..' entry. Also make sure we return an error code
if the file system is corrupted. -TYT ]
--- fs/ext4/namei.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-)
fs/ext4/namei.c +27 -3
@@ -3500,6 +3500,9 @@ static struct buffer_head *ext4_get_firsstruct buffer_head *bh;if (!ext4_has_inline_data (inode)) { +struct ext4_dir_entry_2 *de; +unsigned int offset; +/* The first directory block must not be a hole, so * treat it as DIRENT_HTREE */
@@ -3508,9 +3511,30 @@ static struct buffer_head *ext4_get_firs *retval =PTR_ERR (bh);return NULL ; } - *parent_de =ext4_next_entry ( - (struct ext4_dir_entry_2 *)bh->b_data, - inode->i_sb->s_blocksize); + + de = (struct ext4_dir_entry_2 *) bh->b_data; +if (ext4_check_dir_entry (inode,NULL , de, bh, bh->b_data, + bh->b_size,0 ) || +le32_to_cpu (de->inode) != inode->i_ino || +strcmp ("." , de->name)) { +EXT4_ERROR_INODE (inode,"directory missing '.'" ); +brelse (bh); + *retval = -EFSCORRUPTED ; +return NULL ; + } + offset =ext4_rec_len_from_disk (de->rec_len, + inode->i_sb->s_blocksize); + de =ext4_next_entry (de, inode->i_sb->s_blocksize); +if (ext4_check_dir_entry (inode,NULL , de, bh, bh->b_data, + bh->b_size, offset) || +le32_to_cpu (de->inode) ==0 ||strcmp (".." , de->name)) { +EXT4_ERROR_INODE (inode,"directory missing '..'" ); +brelse (bh); + *retval = -EFSCORRUPTED ; +return NULL ; + } + *parent_de = de; +return bh; }
Greg Kroah-Hartman
maintainerPATCH 360/452 ext4: fix warning in ext4_handle_inode_extension
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit f4534c9fc94d22383f187b9409abb3f9df2e3db3 upstream.
We got issue as follows:
EXT4-fs error (device loop0) in ext4_reserve_inode_write:5741: Out of memory
EXT4-fs error (device loop0): ext4_setattr:5462: inode #13: comm syz-executor.0: mark_inode_dirty error
EXT4-fs error (device loop0) in ext4_setattr:5519: Out of memory
EXT4-fs error (device loop0): ext4_ind_map_blocks:595: inode #13: comm syz-executor.0: Can't allocate blocks for non-extent mapped inodes with bigalloc
------------[ cut here ]------------ WARNING: CPU: 1 PID: 4361 at fs/ext4/file.c:301 ext4_file_write_iter+0x11c9/0x1220 Modules linked in: CPU: 1 PID: 4361 Comm: syz-executor.0 Not tainted 5.10.0+ #1 RIP: 0010:ext4_file_write_iter+0x11c9/0x1220 RSP: 0018:ffff924d80b27c00 EFLAGS: 00010282 RAX: ffffffff815a3379 RBX: 0000000000000000 RCX: 000000003b000000 RDX: ffff924d81601000 RSI: 00000000000009cc RDI: 00000000000009cd RBP: 000000000000000d R08: ffffffffbc5a2c6b R09: 0000902e0e52a96f R10: ffff902e2b7c1b40 R11: ffff902e2b7c1b40 R12: 000000000000000a R13: 0000000000000001 R14: ffff902e0e52aa10 R15: ffffffffffffff8b FS: 00007f81a7f65700(0000) GS:ffff902e3bc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffff600400 CR3: 000000012db88001 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: do_iter_readv_writev+0x2e5/0x360 do_iter_write+0x112/0x4c0 do_pwritev+0x1e5/0x390 __x64_sys_pwritev2+0x7e/0xa0 do_syscall_64+0x37/0x50 entry_SYSCALL_64_after_hwframe+0x44/0xa9
Above issue may happen as follows:
Assume
inode.i_size=4096
EXT4_I(inode)->i_disksize=4096
step 1: set inode->i_isize = 8192ext4_setattr
if (attr->ia_size != inode->i_size)
EXT4_I(inode)->i_disksize = attr->ia_size;
rc = ext4_mark_inode_dirty
ext4_reserve_inode_write
ext4_get_inode_loc
__ext4_get_inode_loc
sb_getblk --> return -ENOMEM
...
if (!error) ->will not update i_size
i_size_write(inode, attr->ia_size);Now:
inode.i_size=4096
EXT4_I(inode)->i_disksize=8192
step 2: Direct write 4096 bytesext4_file_write_iter
ext4_dio_write_iter
iomap_dio_rw ->return error
if (extend)
ext4_handle_inode_extension
WARN_ON_ONCE(i_size_read(inode) < EXT4_I(inode)->i_disksize);
->Then trigger warning.
To solve above issue, if mark inode dirty failed in ext4_setattr just set 'EXT4_I(inode)->i_disksize' with old value.
--- fs/ext4/inode.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/ext4/inode.c +4 -0
@@ -5444,6 +5444,7 @@ int ext4_setattr(struct dentry *dentry,if (attr->ia_valid &ATTR_SIZE ) {handle_t *handle;loff_t oldsize = inode->i_size; +loff_t old_disksize;int shrink = (attr->ia_size < inode->i_size);if (!(ext4_test_inode_flag (inode,EXT4_INODE_EXTENTS ))) {
@@ -5517,6 +5518,7 @@ int ext4_setattr(struct dentry *dentry, inode->i_sb->s_blocksize_bits);down_write (&EXT4_I (inode)->i_data_sem); + old_disksize =EXT4_I (inode)->i_disksize;EXT4_I (inode)->i_disksize = attr->ia_size; rc =ext4_mark_inode_dirty (handle, inode);if (!error)
@@ -5528,6 +5530,8 @@ int ext4_setattr(struct dentry *dentry,*/ if (!error)i_size_write (inode, attr->ia_size); +else +EXT4_I (inode)->i_disksize = old_disksize;up_write (&EXT4_I (inode)->i_data_sem);ext4_journal_stop (handle);if (error)
Greg Kroah-Hartman
maintainerPATCH 361/452 ext4: fix bug_on in ext4_writepages
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit ef09ed5d37b84d18562b30cf7253e57062d0db05 upstream.
we got issue as follows:
EXT4-fs error (device loop0): ext4_mb_generate_buddy:1141: group 0, block bitmap and bg descriptor inconsistent: 25 vs 31513 free cls
------------[ cut here ]------------ kernel BUG at fs/ext4/inode.c:2708! invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 2 PID: 2147 Comm: rep Not tainted 5.18.0-rc2-next-20220413+ #155 RIP: 0010:ext4_writepages+0x1977/0x1c10 RSP: 0018:ffff88811d3e7880 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffff88811c098000 RDX: 0000000000000000 RSI: ffff88811c098000 RDI: 0000000000000002 RBP: ffff888128140f50 R08: ffffffffb1ff6387 R09: 0000000000000000 R10: 0000000000000007 R11: ffffed10250281ea R12: 0000000000000001 R13: 00000000000000a4 R14: ffff88811d3e7bb8 R15: ffff888128141028 FS: 00007f443aed9740(0000) GS:ffff8883aef00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000020007200 CR3: 000000011c2a4000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> do_writepages+0x130/0x3a0 filemap_fdatawrite_wbc+0x83/0xa0 filemap_flush+0xab/0xe0 ext4_alloc_da_blocks+0x51/0x120 __ext4_ioctl+0x1534/0x3210 __x64_sys_ioctl+0x12c/0x170 do_syscall_64+0x3b/0x90
It may happen as follows:
1. write inline_data inodevfs_write
new_sync_write
ext4_file_write_iter
ext4_buffered_write_iter
generic_perform_write
ext4_da_write_begin
ext4_da_write_inline_data_begin -> If inline data size too
small will allocate block to write, then mapping will has
dirty page
ext4_da_convert_inline_data_to_extent ->clear EXT4_STATE_MAY_INLINE_DATA
2. fallocate
do_vfs_ioctl
ioctl_preallocate
vfs_fallocate
ext4_fallocate
ext4_convert_inline_data
ext4_convert_inline_data_nolock
ext4_map_blocks -> fail will goto restore data
ext4_restore_inline_data
ext4_create_inline_data
ext4_write_inline_data
ext4_set_inode_state -> set inode EXT4_STATE_MAY_INLINE_DATA3. writepages__ext4_ioctl
ext4_alloc_da_blocks
filemap_flush
filemap_fdatawrite_wbc
do_writepages
ext4_writepages
if (ext4_has_inline_data(inode))
BUG_ON(ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
The root cause of this issue is we destory inline data until call ext4_writepages under delay allocation mode. But there maybe already convert from inline to extent. To solve this issue, we call filemap_flush first..
--- fs/ext4/inline.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/ext4/inline.c +12 -0
@@ -1974,6 +1974,18 @@ int ext4_convert_inline_data(struct inodif (!ext4_has_inline_data (inode)) {ext4_clear_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA );return 0 ; + }else if (!ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA )) { +/* +* Inode has inline data but EXT4_STATE_MAY_INLINE_DATA is +* cleared. This means we are in the middle of moving of +* inline data to delay allocated block. Just force writeout +* here to finish conversion. +*/ + error =filemap_flush (inode->i_mapping); +if (error) +return error; +if (!ext4_has_inline_data (inode)) +return 0 ; } needed_blocks =ext4_writepage_trans_blocks (inode);
Greg Kroah-Hartman
maintainerPATCH 362/452 ext4: filter out EXT4_FC_REPLAY from on-disk superblock field s_state
In reply to Greg Kroah-HartmanFrom: Theodore Ts'o <[email protected]>
commit c878bea3c9d724ddfa05a813f30de3d25a0ba83f upstream.
The EXT4_FC_REPLAY bit in sbi->s_mount_state is used to indicate that we are in the middle of replay the fast commit journal. This was actually a mistake, since the sbi->s_mount_info is initialized from es->s_state. Arguably s_mount_state is misleadingly named, but the name is historical --- s_mount_state and s_state dates back to ext2.
What should have been used is the ext4_{set,clear,test}_mount_flag() inline functions, which sets EXT4_MF_* bits in sbi->s_mount_flags.
The problem with using EXT4_FC_REPLAY is that a maliciously corrupted superblock could result in EXT4_FC_REPLAY getting set in s_mount_state. This bypasses some sanity checks, and this can trigger a BUG() in ext4_es_cache_extent(). As a easy-to-backport-fix, filter out the EXT4_FC_REPLAY bit for now. We should eventually transition away from EXT4_FC_REPLAY to something like EXT4_MF_REPLAY.
--- fs/ext4/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/ext4/super.c +3 -2
@@ -4538,7 +4538,7 @@ static int ext4_fill_super(struct super_ sbi->s_inodes_per_block; sbi->s_desc_per_block = blocksize /EXT4_DESC_SIZE (sb); sbi->s_sbh = bh; - sbi->s_mount_state =le16_to_cpu (es->s_state); + sbi->s_mount_state =le16_to_cpu (es->s_state) & ~EXT4_FC_REPLAY ; sbi->s_addr_per_block_bits =ilog2 (EXT4_ADDR_PER_BLOCK (sb)); sbi->s_desc_per_block_bits =ilog2 (EXT4_DESC_PER_BLOCK (sb));
@@ -5998,7 +5998,8 @@ static int ext4_remount(struct super_bloif (err) goto restore_opts; } - sbi->s_mount_state =le16_to_cpu (es->s_state); + sbi->s_mount_state = (le16_to_cpu (es->s_state) & + ~EXT4_FC_REPLAY ); err =ext4_setup_super (sb, es,0 );if (err)
Greg Kroah-Hartman
maintainerPATCH 363/452 ext4: fix bug_on in __es_tree_search
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit d36f6ed761b53933b0b4126486c10d3da7751e7f upstream.
Hulk Robot reported a BUG_ON:
==================================================================
kernel BUG at fs/ext4/extents_status.c:199!
[...]
RIP: 0010:ext4_es_end fs/ext4/extents_status.c:199 [inline] RIP: 0010:__es_tree_search+0x1e0/0x260 fs/ext4/extents_status.c:217 [...] Call Trace: ext4_es_cache_extent+0x109/0x340 fs/ext4/extents_status.c:766 ext4_cache_extents+0x239/0x2e0 fs/ext4/extents.c:561 ext4_find_extent+0x6b7/0xa20 fs/ext4/extents.c:964 ext4_ext_map_blocks+0x16b/0x4b70 fs/ext4/extents.c:4384 ext4_map_blocks+0xe26/0x19f0 fs/ext4/inode.c:567 ext4_getblk+0x320/0x4c0 fs/ext4/inode.c:980 ext4_bread+0x2d/0x170 fs/ext4/inode.c:1031 ext4_quota_read+0x248/0x320 fs/ext4/super.c:6257 v2_read_header+0x78/0x110 fs/quota/quota_v2.c:63 v2_check_quota_file+0x76/0x230 fs/quota/quota_v2.c:82 vfs_load_quota_inode+0x5d1/0x1530 fs/quota/dquot.c:2368 dquot_enable+0x28a/0x330 fs/quota/dquot.c:2490 ext4_quota_enable fs/ext4/super.c:6137 [inline] ext4_enable_quotas+0x5d7/0x960 fs/ext4/super.c:6163 ext4_fill_super+0xa7c9/0xdc00 fs/ext4/super.c:4754 mount_bdev+0x2e9/0x3b0 fs/super.c:1158 mount_fs+0x4b/0x1e4 fs/super.c:1261
[...]
==================================================================
Above issue may happen as follows:
-------------------------------------ext4_fill_super
ext4_enable_quotas
ext4_quota_enable
ext4_iget
__ext4_iget
ext4_ext_check_inode
ext4_ext_check
__ext4_ext_check
ext4_valid_extent_entries
Check for overlapping extents does't take effect
dquot_enable
vfs_load_quota_inode
v2_check_quota_file
v2_read_header
ext4_quota_read
ext4_bread
ext4_getblk
ext4_map_blocks
ext4_ext_map_blocks
ext4_find_extent
ext4_cache_extents
ext4_es_cache_extent
ext4_es_cache_extent
__es_tree_search
ext4_es_end
BUG_ON(es->es_lblk + es->es_len < es->es_lblk)The error ext4 extents is as follows:
0af3 0300 0400 0000 00000000 extent_header 00000000 0100 0000 12000000 extent1 00000000 0100 0000 18000000 extent2 02000000 0400 0000 14000000 extent3
In the ext4_valid_extent_entries function,
if prev is 0, no error is returned even if lblock<=prev. This was intended to skip the check on the first extent, but in the error image above, prev=0+1-1=0 when checking the second extent, so even though lblock<=prev, the function does not return an error. As a result, bug_ON occurs in __es_tree_search and the system panics.
To solve this problem, we only need to check that:
1. The lblock of the first extent is not less than 0.
2. The lblock of the next extent is not less than the next block of the previous extent.
The same applies to extent_idx.
--- fs/ext4/extents.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/ext4/extents.c +5 -5
@@ -371,7 +371,7 @@ static int ext4_valid_extent_entries(str {unsigned short entries;ext4_lblk_t lblock =0 ; -ext4_lblk_t prev =0 ; +ext4_lblk_t cur =0 ;if (eh->eh_entries ==0 )return 1 ;
@@ -395,11 +395,11 @@ static int ext4_valid_extent_entries(str/* Check for overlapping extents */ lblock =le32_to_cpu (ext->ee_block); -if ((lblock <= prev) && prev) { +if (lblock < cur) { *pblk =ext4_ext_pblock (ext);return 0 ; } - prev = lblock +ext4_ext_get_actual_len (ext) -1 ; + cur = lblock +ext4_ext_get_actual_len (ext); ext++; entries--; }
@@ -419,13 +419,13 @@ static int ext4_valid_extent_entries(str/* Check for overlapping index extents */ lblock =le32_to_cpu (ext_idx->ei_block); -if ((lblock <= prev) && prev) { +if (lblock < cur) { *pblk =ext4_idx_pblock (ext_idx);return 0 ; } ext_idx++; entries--; - prev = lblock; + cur = lblock +1 ; } }return 1 ;
Greg Kroah-Hartman
maintainerPATCH 364/452 ext4: verify dir block before splitting it
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 46c116b920ebec58031f0a78c5ea9599b0d2a371 upstream.
Before splitting a directory block verify its directory entries are sane so that the splitting code does not access memory it should not.
--- fs/ext4/namei.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-)
fs/ext4/namei.c +21 -11
@@ -280,9 +280,9 @@ static struct dx_frame *dx_probe(structstruct dx_hash_info *hinfo, struct dx_frame *frame);static void dx_release (struct dx_frame *frames); -static int dx_make_map (struct inode *dir,struct ext4_dir_entry_2 *de, -unsigned blocksize,struct dx_hash_info *hinfo, -struct dx_map_entry map[]); +static int dx_make_map (struct inode *dir,struct buffer_head *bh, +struct dx_hash_info *hinfo, +struct dx_map_entry *map_tail);static void dx_sort_map (struct dx_map_entry *map,unsigned count);static struct ext4_dir_entry_2 *dx_move_dirents (char *from,char *to,struct dx_map_entry *offsets,int count,unsigned blocksize);
@@ -1208,15 +1208,23 @@ static inline int search_dirblock(struct* Create map of hash values, offsets, and sizes, stored at end of block. * Returns number of entries mapped. */ -static int dx_make_map (struct inode *dir,struct ext4_dir_entry_2 *de, -unsigned blocksize,struct dx_hash_info *hinfo, +static int dx_make_map (struct inode *dir,struct buffer_head *bh, +struct dx_hash_info *hinfo,struct dx_map_entry *map_tail) {int count =0 ; -char *base = (char *) de; +struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)bh->b_data; +unsigned int buflen = bh->b_size; +char *base = bh->b_data;struct dx_hash_info h = *hinfo; -while ((char *) de < base + blocksize) { +if (ext4_has_metadata_csum (dir->i_sb)) + buflen -=sizeof (struct ext4_dir_entry_tail ); + +while ((char *) de < base + buflen) { +if (ext4_check_dir_entry (dir,NULL , de, bh, base, buflen, + ((char *)de) - base)) +return -EFSCORRUPTED ;if (de->name_len && de->inode) {ext4fs_dirhash (dir, de->name, de->name_len, &h); map_tail--;
@@ -1226,8 +1234,7 @@ static int dx_make_map(struct inode *dir count++;cond_resched (); } -/* XXX: do we need to check rec_len == 0 case? -Chris */ - de =ext4_next_entry (de, blocksize); + de =ext4_next_entry (de, dir->i_sb->s_blocksize); }return count; }
@@ -1853,8 +1860,11 @@ static struct ext4_dir_entry_2 *do_split/* create map in the end of data2 block */ map = (struct dx_map_entry *) (data2 + blocksize); - count =dx_make_map (dir, (struct ext4_dir_entry_2 *) data1, - blocksize, hinfo, map); + count =dx_make_map (dir, *bh, hinfo, map); +if (count <0 ) { + err = count; + goto journal_error; + } map -= count;dx_sort_map (map, count);/* Ensure that neither split block is over half full */
Greg Kroah-Hartman
maintainerPATCH 365/452 ext4: avoid cycles in directory h-tree
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 3ba733f879c2a88910744647e41edeefbc0d92b2 upstream.
A maliciously corrupted filesystem can contain cycles in the h-tree stored inside a directory. That can easily lead to the kernel corrupting tree nodes that were already verified under its hands while doing a node split and consequently accessing unallocated memory. Fix the problem by verifying traversed block numbers are unique.
--- fs/ext4/namei.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
fs/ext4/namei.c +19 -3
@@ -756,12 +756,14 @@ static struct dx_frame * dx_probe(struct ext4_filename *fname, struct inode *dir, struct dx_hash_info *hinfo, struct dx_frame *frame_in) { - unsigned count, indirect; + unsigned count, indirect, level, i;struct dx_entry *at, *entries, *p, *q, *m;struct dx_root *root;struct dx_frame *frame = frame_in;struct dx_frame *ret_err =ERR_PTR (ERR_BAD_DX_DIR );u32 hash; +ext4_lblk_t block; +ext4_lblk_t blocks[EXT4_HTREE_LEVEL ];memset (frame_in,0 ,EXT4_HTREE_LEVEL *sizeof (frame_in[0 ])); frame->bh =ext4_read_dirblock (dir,0 ,INDEX );
@@ -817,6 +819,8 @@ dx_probe(struct ext4_filename *fname, st }dxtrace (printk ("Look up %x" , hash)); + level =0 ; + blocks[0 ] =0 ;while (1 ) { count =dx_get_count (entries);if (!count || count >dx_get_limit (entries)) {
@@ -858,15 +862,27 @@ dx_probe(struct ext4_filename *fname, st dx_get_block(at))); frame->entries = entries; frame->at = at; -if (!indirect--) + + block =dx_get_block (at); +for (i =0 ; i <= level; i++) { +if (blocks[i] == block) { +ext4_warning_inode (dir, +"dx entry: tree cycle block %u points back to block %u" , + blocks[level], block); + goto fail; + } + } +if (++level > indirect)return frame; + blocks[level] = block; frame++; - frame->bh =ext4_read_dirblock (dir,dx_get_block (at),INDEX ); + frame->bh =ext4_read_dirblock (dir, block,INDEX );if (IS_ERR (frame->bh)) { ret_err = (struct dx_frame *) frame->bh; frame->bh =NULL ; goto fail; } + entries = ((struct dx_node *) frame->bh->b_data)->entries;if (dx_get_limit (entries) !=dx_node_limit (dir)) {
Greg Kroah-Hartman
maintainerPATCH 366/452 ACPI: property: Release subnode properties with data nodes
In reply to Greg Kroah-HartmanFrom: Sakari Ailus <[email protected]>
commit 3bd561e1572ee02a50cd1a5be339abf1a5b78d56 upstream.
struct acpi_device_properties describes one source of properties present on either struct acpi_device or struct acpi_data_node. When properties are parsed, both are populated but when released, only those properties that are associated with the device node are freed.
Fix this by also releasing memory of the data node properties.
--- drivers/acpi/property.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/acpi/property.c +12 -6
@@ -433,6 +433,16 @@ void acpi_init_properties(struct acpi_deacpi_extract_apple_properties (adev); } +static void acpi_free_device_properties (struct list_head *list) +{ +struct acpi_device_properties *props, *tmp; + +list_for_each_entry_safe (props, tmp, list, list) { +list_del (&props->list); +kfree (props); + } +} +static void acpi_destroy_nondev_subnodes (struct list_head *list) {struct acpi_data_node *dn, *next;
@@ -445,22 +455,18 @@ static void acpi_destroy_nondev_subnodeswait_for_completion (&dn->kobj_done);list_del (&dn->sibling);ACPI_FREE ((void *)dn->data.pointer); +acpi_free_device_properties (&dn->data.properties);kfree (dn); } }void acpi_free_properties (struct acpi_device *adev) { -struct acpi_device_properties *props, *tmp; -acpi_destroy_nondev_subnodes (&adev->data.subnodes);ACPI_FREE ((void *)adev->data.pointer); adev->data.of_compatible =NULL ; adev->data.pointer =NULL ; -list_for_each_entry_safe (props, tmp, &adev->data.properties, list) { -list_del (&props->list); -kfree (props); - } +acpi_free_device_properties (&adev->data.properties); }/**
Greg Kroah-Hartman
maintainerPATCH 367/452 tracing: Fix potential double free in create_var_ref()
In reply to Greg Kroah-HartmanFrom: Keita Suzuki <[email protected]>
commit 99696a2592bca641eb88cc9a80c90e591afebd0f upstream.
In create_var_ref(), init_var_ref() is called to initialize the fields of variable ref_field, which is allocated in the previous function call to create_hist_field(). Function init_var_ref() allocates the corresponding fields such as ref_field->system, but frees these fields when the function encounters an error. The caller later calls destroy_hist_field() to conduct error handling, which frees the fields and the variable itself. This results in double free of the fields which are already freed in the previous function.
Fix this by storing NULL to the corresponding fields when they are freed in init_var_ref().
--- kernel/trace/trace_events_hist.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_events_hist.c +3 -0
@@ -1789,8 +1789,11 @@ static int init_var_ref(struct hist_fielreturn err; free:kfree (ref_field->system); + ref_field->system =NULL ;kfree (ref_field->event_name); + ref_field->event_name =NULL ;kfree (ref_field->name); + ref_field->name =NULL ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 368/452 PCI/PM: Fix bridge_d3_blacklist[] Elo i2 overwrite of Gigabyte X299
In reply to Greg Kroah-HartmanFrom: Bjorn Helgaas <[email protected]>
commit 12068bb346db5776d0ec9bb4cd073f8427a1ac92 upstream.
92597f97a40b ("PCI/PM: Avoid putting Elo i2 PCIe Ports in D3cold") omitted braces around the new Elo i2 entry, so it overwrote the existing Gigabyte X299 entry. Add the appropriate braces.
Found by:
$ make W=1 drivers/pci/pci.o
CC drivers/pci/pci.o
drivers/pci/pci.c:2974:12: error: initialized field overwritten [-Werror=override-init]
2974 | .ident = "Elo i2",
| ^~~~~~~~--- drivers/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/pci/pci.c +2 -0
@@ -2829,6 +2829,8 @@ static const struct dmi_system_id bridgeDMI_MATCH (DMI_BOARD_VENDOR ,"Gigabyte Technology Co., Ltd." ), DMI_MATCH(DMI_BOARD_NAME, "X299 DESIGNARE EX-CF"), }, + }, + {/* * Downstream device is not accessible after putting a root port * into D3cold and back into D0 on Elo i2.
Greg Kroah-Hartman
maintainerPATCH 369/452 PCI: qcom: Fix runtime PM imbalance on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 87d83b96c8d6c6c2d2096bd0bdba73bcf42b8ef0 upstream.
Drop the leftover pm_runtime_disable() calls from the late probe error paths that would, for example, prevent runtime PM from being reenabled after a probe deferral.
--- drivers/pci/controller/dwc/pcie-qcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/pci/controller/dwc/pcie-qcom.c +1 -4
@@ -1443,17 +1443,14 @@ static int qcom_pcie_probe(struct platfo } ret =phy_init (pcie->phy); -if (ret) { -pm_runtime_disable (&pdev->dev); +if (ret) goto err_pm_runtime_put; - }platform_set_drvdata (pdev, pcie); ret =dw_pcie_host_init (pp);if (ret) {dev_err (dev,"cannot initialize host\n" ); -pm_runtime_disable (&pdev->dev); goto err_pm_runtime_put; }
Greg Kroah-Hartman
maintainerPATCH 370/452 PCI: qcom: Fix unbalanced PHY init on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 83013631f0f9961416abd812e228c8efbc2f6069 upstream.
Undo the PHY initialisation (e.g. balance runtime PM) if host initialisation fails during probe.
--- drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/pci/controller/dwc/pcie-qcom.c +3 -1
@@ -1451,11 +1451,13 @@ static int qcom_pcie_probe(struct platfo ret =dw_pcie_host_init (pp);if (ret) {dev_err (dev,"cannot initialize host\n" ); - goto err_pm_runtime_put; + goto err_phy_exit; }return 0 ; +err_phy_exit: +phy_exit (pcie->phy); err_pm_runtime_put:pm_runtime_put (dev);pm_runtime_disable (dev);
Greg Kroah-Hartman
maintainerPATCH 371/452 mm, compaction: fast_find_migrateblock() should return pfn in the target zone
In reply to Greg Kroah-HartmanFrom: Rei Yamamoto <[email protected]>
commit bbe832b9db2e1ad21522f8f0bf02775fff8a0e0e upstream.
At present, pages not in the target zone are added to cc->migratepages list in isolate_migratepages_block(). As a result, pages may migrate between nodes unintentionally.
This would be a serious problem for older kernels without commit a984226f457f849e ("mm: memcontrol: remove the pgdata parameter of mem_cgroup_page_lruvec"), because it can corrupt the lru list by handling pages in list without holding proper lru_lock.
Avoid returning a pfn outside the target zone in the case that it is not aligned with a pageblock boundary. Otherwise isolate_migratepages_block() will handle pages not in the target zone.
--- mm/compaction.c | 2 ++ 1 file changed, 2 insertions(+)
mm/compaction.c +2 -0
@@ -1747,6 +1747,8 @@ static unsigned long fast_find_migrateblupdate_fast_start_pfn (cc, free_pfn); pfn =pageblock_start_pfn (free_pfn); +if (pfn < cc->zone->zone_start_pfn) + pfn = cc->zone->zone_start_pfn; cc->fast_search_fail =0 ; found_block = true;set_pageblock_skip (freepage);
Greg Kroah-Hartman
maintainerPATCH 372/452 s390/perf: obtain sie_block from the right address
In reply to Greg Kroah-HartmanFrom: Nico Boehr <[email protected]>
commit c9bfb460c3e4da2462e16b0f0b200990b36b1dd2 upstream.
Since commit 1179f170b6f0 ("s390: fix fpu restore in entry.S"), the sie_block pointer is located at empty1[1], but in sie_block() it was taken from empty1[0].
This leads to a random pointer being dereferenced, possibly causing system crash.
This problem can be observed when running a simple guest with an endless loop and recording the cpu-clock event:
sudo perf kvm --guestvmlinux=<guestkernel> --guest top -e cpu-clock
With this fix, the correct guest address is shown.
--- arch/s390/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/perf_event.c +1 -1
@@ -51,7 +51,7 @@ static struct kvm_s390_sie_block *sie_blif (!stack)return NULL ; -return (struct kvm_s390_sie_block *) stack->empty1[0 ]; +return (struct kvm_s390_sie_block *)stack->empty1[1 ]; }static bool is_in_guest (struct pt_regs *regs)
Greg Kroah-Hartman
maintainerPATCH 373/452 dlm: fix plock invalid read
In reply to Greg Kroah-HartmanFrom: Alexander Aring <[email protected]>
commit 42252d0d2aa9b94d168241710a761588b3959019 upstream.
This patch fixes an invalid read showed by KASAN. A unlock will allocate a "struct plock_op" and a followed send_op() will append it to a global send_list data structure. In some cases a followed dev_read() moves it to recv_list and dev_write() will cast it to "struct plock_xop" and access fields which are only available in those structures. At this point an invalid read happens by accessing those fields.
To fix this issue the "callback" field is moved to "struct plock_op" to indicate that a cast to "plock_xop" is allowed and does the additional "plock_xop" handling if set.
Example of the KASAN output which showed the invalid read:
[ 2064.296453] ================================================================== [ 2064.304852] BUG: KASAN: slab-out-of-bounds in dev_write+0x52b/0x5a0 [dlm] [ 2064.306491] Read of size 8 at addr ffff88800ef227d8 by task dlm_controld/7484 [ 2064.308168] [ 2064.308575] CPU: 0 PID: 7484 Comm: dlm_controld Kdump: loaded Not tainted 5.14.0+ #9 [ 2064.310292] Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 [ 2064.311618] Call Trace: [ 2064.312218] dump_stack_lvl+0x56/0x7b [ 2064.313150] print_address_description.constprop.8+0x21/0x150 [ 2064.314578] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.315610] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.316595] kasan_report.cold.14+0x7f/0x11b [ 2064.317674] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.318687] dev_write+0x52b/0x5a0 [dlm] [ 2064.319629] ? dev_read+0x4a0/0x4a0 [dlm] [ 2064.320713] ? bpf_lsm_kernfs_init_security+0x10/0x10 [ 2064.321926] vfs_write+0x17e/0x930 [ 2064.322769] ? __fget_light+0x1aa/0x220 [ 2064.323753] ksys_write+0xf1/0x1c0 [ 2064.324548] ? __ia32_sys_read+0xb0/0xb0 [ 2064.325464] do_syscall_64+0x3a/0x80 [ 2064.326387] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2064.327606] RIP: 0033:0x7f807e4ba96f [ 2064.328470] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 39 87 f8 ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 7c 87 f8 ff 48 [ 2064.332902] RSP: 002b:00007ffd50cfe6e0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 [ 2064.334658] RAX: ffffffffffffffda RBX: 000055cc3886eb30 RCX: 00007f807e4ba96f [ 2064.336275] RDX: 0000000000000040 RSI: 00007ffd50cfe7e0 RDI: 0000000000000010 [ 2064.337980] RBP: 00007ffd50cfe7e0 R08: 0000000000000000 R09: 0000000000000001 [ 2064.339560] R10: 000055cc3886eb30 R11: 0000000000000293 R12: 000055cc3886eb80 [ 2064.341237] R13: 000055cc3886eb00 R14: 000055cc3886f590 R15: 0000000000000001 [ 2064.342857] [ 2064.343226] Allocated by task 12438: [ 2064.344057] kasan_save_stack+0x1c/0x40 [ 2064.345079] __kasan_kmalloc+0x84/0xa0 [ 2064.345933] kmem_cache_alloc_trace+0x13b/0x220 [ 2064.346953] dlm_posix_unlock+0xec/0x720 [dlm] [ 2064.348811] do_lock_file_wait.part.32+0xca/0x1d0 [ 2064.351070] fcntl_setlk+0x281/0xbc0 [ 2064.352879] do_fcntl+0x5e4/0xfe0 [ 2064.354657] __x64_sys_fcntl+0x11f/0x170 [ 2064.356550] do_syscall_64+0x3a/0x80 [ 2064.358259] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2064.360745] [ 2064.361511] Last potentially related work creation: [ 2064.363957] kasan_save_stack+0x1c/0x40 [ 2064.365811] __kasan_record_aux_stack+0xaf/0xc0 [ 2064.368100] call_rcu+0x11b/0xf70 [ 2064.369785] dlm_process_incoming_buffer+0x47d/0xfd0 [dlm] [ 2064.372404] receive_from_sock+0x290/0x770 [dlm] [ 2064.374607] process_recv_sockets+0x32/0x40 [dlm] [ 2064.377290] process_one_work+0x9a8/0x16e0 [ 2064.379357] worker_thread+0x87/0xbf0 [ 2064.381188] kthread+0x3ac/0x490 [ 2064.383460] ret_from_fork+0x22/0x30 [ 2064.385588] [ 2064.386518] Second to last potentially related work creation: [ 2064.389219] kasan_save_stack+0x1c/0x40 [ 2064.391043] __kasan_record_aux_stack+0xaf/0xc0 [ 2064.393303] call_rcu+0x11b/0xf70 [ 2064.394885] dlm_process_incoming_buffer+0x47d/0xfd0 [dlm] [ 2064.397694] receive_from_sock+0x290/0x770 [dlm] [ 2064.399932] process_recv_sockets+0x32/0x40 [dlm] [ 2064.402180] process_one_work+0x9a8/0x16e0 [ 2064.404388] worker_thread+0x87/0xbf0 [ 2064.406124] kthread+0x3ac/0x490 [ 2064.408021] ret_from_fork+0x22/0x30 [ 2064.409834] [ 2064.410599] The buggy address belongs to the object at ffff88800ef22780 [ 2064.410599] which belongs to the cache kmalloc-96 of size 96 [ 2064.416495] The buggy address is located 88 bytes inside of [ 2064.416495] 96-byte region [ffff88800ef22780, ffff88800ef227e0) [ 2064.422045] The buggy address belongs to the page: [ 2064.424635] page:00000000b6bef8bc refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xef22 [ 2064.428970] flags: 0xfffffc0000200(slab|node=0|zone=1|lastcpupid=0x1fffff) [ 2064.432515] raw: 000fffffc0000200 ffffea0000d68b80 0000001400000014 ffff888001041780 [ 2064.436110] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 2064.439813] page dumped because: kasan: bad access detected [ 2064.442548] [ 2064.443310] Memory state around the buggy address: [ 2064.445988] ffff88800ef22680: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.449444] ffff88800ef22700: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.452941] >ffff88800ef22780: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc [ 2064.456383] ^ [ 2064.459386] ffff88800ef22800: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc [ 2064.462788] ffff88800ef22880: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.466239] ==================================================================
reproducer in python:
import argparse
import struct
import fcntl
import os
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file',
help='file to use fcntl, must be on dlm lock filesystem e.g. gfs2')
args = parser.parse_args()
f = open(args.file, 'wb+')
lockdata = struct.pack('hhllhh', fcntl.F_WRLCK,0,0,0,0,0) fcntl.fcntl(f, fcntl.F_SETLK, lockdata)
lockdata = struct.pack('hhllhh', fcntl.F_UNLCK,0,0,0,0,0) fcntl.fcntl(f, fcntl.F_SETLK, lockdata)
--- fs/dlm/plock.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
fs/dlm/plock.c +5 -7
@@ -23,11 +23,11 @@ struct plock_op {struct list_head list;int done;struct dlm_plock_info info; +int (*callback)(struct file_lock *fl,int result); };struct plock_xop {struct plock_op xop; -int (*callback)(struct file_lock *fl,int result);void *fl;void *file;struct file_lock flc;
@@ -129,19 +129,18 @@ int dlm_posix_lock(dlm_lockspace_t *lock/* fl_owner is lockd which doesn't distinguish processes on the nfs client */ op->info.owner = (__u64 ) fl->fl_pid; - xop->callback = fl->fl_lmops->lm_grant; + op->callback = fl->fl_lmops->lm_grant;locks_init_lock (&xop->flc);locks_copy_lock (&xop->flc, fl); xop->fl = fl; xop->file = file; }else { op->info.owner = (__u64 )(long ) fl->fl_owner; - xop->callback =NULL ; }send_op (op); -if (xop->callback ==NULL ) { +if (!op->callback) { rv =wait_event_interruptible (recv_wq, (op->done !=0 ));if (rv == -ERESTARTSYS ) { log_debug(ls, "dlm_posix_lock: wait killed %llx",
@@ -203,7 +202,7 @@ static int dlm_plock_callback(struct plo file = xop->file; flc = &xop->flc; fl = xop->fl; - notify = xop->callback; + notify = op->callback;if (op->info.rv) {notify (fl, op->info.rv);
@@ -436,10 +435,9 @@ static ssize_t dev_write(struct file *fiif (op->info.fsid == info.fsid && op->info.number == info.number && op->info.owner == info.owner) { -struct plock_xop *xop = (struct plock_xop *)op;list_del_init (&op->list);memcpy (&op->info, &info,sizeof (info)); -if (xop->callback) +if (op->callback) do_callback =1 ;else op->done =1 ;
Greg Kroah-Hartman
maintainerPATCH 374/452 dlm: fix missing lkb refcount handling
In reply to Greg Kroah-HartmanFrom: Alexander Aring <[email protected]>
commit 1689c169134f4b5a39156122d799b7dca76d8ddb upstream.
We always call hold_lkb(lkb) if we increment lkb->lkb_wait_count. So, we always need to call unhold_lkb(lkb) if we decrement lkb->lkb_wait_count. This patch will add missing unhold_lkb(lkb) if we decrement lkb->lkb_wait_count. In case of setting lkb->lkb_wait_count to zero we need to countdown until reaching zero and call unhold_lkb(lkb). The waiters list unhold_lkb(lkb) can be removed because it's done for the last lkb_wait_count decrement iteration as it's done in _remove_from_waiters().
This issue was discovered by a dlm gfs2 test case which use excessively dlm_unlock(LKF_CANCEL) feature. Probably the lkb->lkb_wait_count value never reached above 1 if this feature isn't used and so it was not discovered before.
The testcase ended in a rsb on the rsb keep data structure with a refcount of 1 but no lkb was associated with it, which is itself an invalid behaviour. A side effect of that was a condition in which the dlm was sending remove messages in a looping behaviour. With this patch that has not been reproduced.
--- fs/dlm/lock.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
fs/dlm/lock.c +9 -2
@@ -1551,6 +1551,7 @@ static int _remove_from_waiters(struct d lkb->lkb_wait_type =0 ; lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL ; lkb->lkb_wait_count--; +unhold_lkb (lkb); goto out_del; }
@@ -1577,6 +1578,7 @@ static int _remove_from_waiters(struct dlog_error (ls,"remwait error %x reply %d wait_type %d overlap" , lkb->lkb_id, mstype, lkb->lkb_wait_type); lkb->lkb_wait_count--; +unhold_lkb (lkb); lkb->lkb_wait_type =0 ; }
@@ -5312,11 +5314,16 @@ int dlm_recover_waiters_post(struct dlm_ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK ; lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL ; lkb->lkb_wait_type =0 ; - lkb->lkb_wait_count =0 ; +/* drop all wait_count references we still +* hold a reference for this iteration. +*/ +while (lkb->lkb_wait_count) { + lkb->lkb_wait_count--; +unhold_lkb (lkb); + }mutex_lock (&ls->ls_waiters_mutex);list_del_init (&lkb->lkb_wait_reply);mutex_unlock (&ls->ls_waiters_mutex); -unhold_lkb (lkb);/* for waiters list */ if (oc || ou) {/* do an unlock or cancel instead of resending */
Greg Kroah-Hartman
maintainerPATCH 375/452 ocfs2: dlmfs: fix error handling of user_dlm_destroy_lock
In reply to Greg Kroah-HartmanFrom: Junxiao Bi via Ocfs2-devel <[email protected]>
commit 863e0d81b6683c4cbc588ad831f560c90e494bef upstream.
When user_dlm_destroy_lock failed, it didn't clean up the flags it set before exit. For USER_LOCK_IN_TEARDOWN, if this function fails because of lock is still in used, next time when unlink invokes this function, it will return succeed, and then unlink will remove inode and dentry if lock is not in used(file closed), but the dlm lock is still linked in dlm lock resource, then when bast come in, it will trigger a panic due to user-after-free. See the following panic call trace. To fix this, USER_LOCK_IN_TEARDOWN should be reverted if fail. And also error should be returned if USER_LOCK_IN_TEARDOWN is set to let user know that unlink fail.
For the case of ocfs2_dlm_unlock failure, besides USER_LOCK_IN_TEARDOWN, USER_LOCK_BUSY is also required to be cleared. Even though spin lock is released in between, but USER_LOCK_IN_TEARDOWN is still set, for USER_LOCK_BUSY, if before every place that waits on this flag, USER_LOCK_IN_TEARDOWN is checked to bail out, that will make sure no flow waits on the busy flag set by user_dlm_destroy_lock(), then we can simplely revert USER_LOCK_BUSY when ocfs2_dlm_unlock fails. Fix user_dlm_cluster_lock() which is the only function not following this.
[ 941.336392] (python,26174,16):dlmfs_unlink:562 ERROR: unlink 004fb0000060000b5a90b8c847b72e1, error -16 from destroy [ 989.757536] ------------[ cut here ]------------ [ 989.757709] kernel BUG at fs/ocfs2/dlmfs/userdlm.c:173! [ 989.757876] invalid opcode: 0000 [#1] SMP [ 989.758027] Modules linked in: ksplice_2zhuk2jr_ib_ipoib_new(O)
ksplice_2zhuk2jr(O) mptctl mptbase xen_netback xen_blkback xen_gntalloc xen_gntdev xen_evtchn cdc_ether usbnet mii ocfs2 jbd2 rpcsec_gss_krb5 auth_rpcgss nfsv4 nfsv3 nfs_acl nfs fscache lockd grace ocfs2_dlmfs ocfs2_stack_o2cb ocfs2_dlm ocfs2_nodemanager ocfs2_stackglue configfs bnx2fc fcoe libfcoe libfc scsi_transport_fc sunrpc ipmi_devintf bridge stp llc rds_rdma rds bonding ib_sdp ib_ipoib rdma_ucm ib_ucm ib_uverbs ib_umad rdma_cm ib_cm iw_cm falcon_lsm_serviceable(PE) falcon_nf_netcontain(PE) mlx4_vnic falcon_kal(E) falcon_lsm_pinned_13402(E) mlx4_ib ib_sa ib_mad ib_core ib_addr xenfs xen_privcmd dm_multipath iTCO_wdt iTCO_vendor_support pcspkr sb_edac edac_core i2c_i801 lpc_ich mfd_core ipmi_ssif i2c_core ipmi_si ipmi_msghandler
[ 989.760686] ioatdma sg ext3 jbd mbcache sd_mod ahci libahci ixgbe dca ptp
pps_core vxlan udp_tunnel ip6_udp_tunnel megaraid_sas mlx4_core crc32c_intel be2iscsi bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi ipv6 cxgb3 mdio libiscsi_tcp qla4xxx iscsi_boot_sysfs libiscsi scsi_transport_iscsi wmi dm_mirror dm_region_hash dm_log dm_mod [last unloaded:ksplice_2zhuk2jr_ib_ipoib_old]
[ 989.761987] CPU: 10 PID: 19102 Comm: dlm_thread Tainted: P OE 4.1.12-124.57.1.el6uek.x86_64 #2 [ 989.762290] Hardware name: Oracle Corporation ORACLE SERVER X5-2/ASM,MOTHERBOARD,1U, BIOS 30350100 06/17/2021 [ 989.762599] task: ffff880178af6200 ti: ffff88017f7c8000 task.ti: ffff88017f7c8000 [ 989.762848] RIP: e030:[<ffffffffc07d4316>] [<ffffffffc07d4316>] __user_dlm_queue_lockres.part.4+0x76/0x80 [ocfs2_dlmfs] [ 989.763185] RSP: e02b:ffff88017f7cbcb8 EFLAGS: 00010246 [ 989.763353] RAX: 0000000000000000 RBX: ffff880174d48008 RCX: 0000000000000003 [ 989.763565] RDX: 0000000000120012 RSI: 0000000000000003 RDI: ffff880174d48170 [ 989.763778] RBP: ffff88017f7cbcc8 R08: ffff88021f4293b0 R09: 0000000000000000 [ 989.763991] R10: ffff880179c8c000 R11: 0000000000000003 R12: ffff880174d48008 [ 989.764204] R13: 0000000000000003 R14: ffff880179c8c000 R15: ffff88021db7a000 [ 989.764422] FS: 0000000000000000(0000) GS:ffff880247480000(0000) knlGS:ffff880247480000 [ 989.764685] CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 989.764865] CR2: ffff8000007f6800 CR3: 0000000001ae0000 CR4: 0000000000042660 [ 989.765081] Stack: [ 989.765167] 0000000000000003 ffff880174d48040 ffff88017f7cbd18 ffffffffc07d455f [ 989.765442] ffff88017f7cbd88 ffffffff816fb639 ffff88017f7cbd38 ffff8800361b5600 [ 989.765717] ffff88021db7a000 ffff88021f429380 0000000000000003 ffffffffc0453020 [ 989.765991] Call Trace: [ 989.766093] [<ffffffffc07d455f>] user_bast+0x5f/0xf0 [ocfs2_dlmfs] [ 989.766287] [<ffffffff816fb639>] ? schedule_timeout+0x169/0x2d0 [ 989.766475] [<ffffffffc0453020>] ? o2dlm_lock_ast_wrapper+0x20/0x20 [ocfs2_stack_o2cb] [ 989.766738] [<ffffffffc045303a>] o2dlm_blocking_ast_wrapper+0x1a/0x20 [ocfs2_stack_o2cb] [ 989.767010] [<ffffffffc0864ec6>] dlm_do_local_bast+0x46/0xe0 [ocfs2_dlm] [ 989.767217] [<ffffffffc084f5cc>] ? dlm_lockres_calc_usage+0x4c/0x60 [ocfs2_dlm] [ 989.767466] [<ffffffffc08501f1>] dlm_thread+0xa31/0x1140 [ocfs2_dlm] [ 989.767662] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.767834] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768006] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768178] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768349] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768521] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768693] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768893] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.769067] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.769241] [<ffffffff810ce4d0>] ? wait_woken+0x90/0x90 [ 989.769411] [<ffffffffc084f7c0>] ? dlm_kick_thread+0x80/0x80 [ocfs2_dlm] [ 989.769617] [<ffffffff810a8bbb>] kthread+0xcb/0xf0 [ 989.769774] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.769945] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.770117] [<ffffffff810a8af0>] ? kthread_create_on_node+0x180/0x180 [ 989.770321] [<ffffffff816fdaa1>] ret_from_fork+0x61/0x90 [ 989.770492] [<ffffffff810a8af0>] ? kthread_create_on_node+0x180/0x180 [ 989.770689] Code: d0 00 00 00 f0 45 7d c0 bf 00 20 00 00 48 89 83 c0 00 00 00 48 89 83 c8 00 00 00 e8 55 c1 8c c0 83 4b 04 10 48 83 c4 08 5b 5d c3 <0f> 0b 0f 1f 84 00 00 00 00 00 55 48 89 e5 41 55 41 54 53 48 83 [ 989.771892] RIP [<ffffffffc07d4316>] __user_dlm_queue_lockres.part.4+0x76/0x80 [ocfs2_dlmfs] [ 989.772174] RSP <ffff88017f7cbcb8> [ 989.772704] ---[ end trace ebd1e38cebcc93a8 ]--- [ 989.772907] Kernel panic - not syncing: Fatal exception [ 989.773173] Kernel Offset: disabled
--- fs/ocfs2/dlmfs/userdlm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
fs/ocfs2/dlmfs/userdlm.c +15 -1
@@ -435,6 +435,11 @@ again: }spin_lock (&lockres->l_lock); +if (lockres->l_flags &USER_LOCK_IN_TEARDOWN ) { +spin_unlock (&lockres->l_lock); + status = -EAGAIN ; + goto bail; + }/* We only compare against the currently granted level * here. If the lock is blocked waiting on a downconvert,
@@ -597,7 +602,7 @@ int user_dlm_destroy_lock(struct user_lospin_lock (&lockres->l_lock);if (lockres->l_flags &USER_LOCK_IN_TEARDOWN ) {spin_unlock (&lockres->l_lock); -return 0 ; + goto bail; } lockres->l_flags |=USER_LOCK_IN_TEARDOWN ;
@@ -611,12 +616,17 @@ int user_dlm_destroy_lock(struct user_lo }if (lockres->l_ro_holders || lockres->l_ex_holders) { + lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN ;spin_unlock (&lockres->l_lock); goto bail; } status =0 ;if (!(lockres->l_flags &USER_LOCK_ATTACHED )) { +/* +* lock is never requested, leave USER_LOCK_IN_TEARDOWN set +* to avoid new lock request coming in. +*/ spin_unlock (&lockres->l_lock); goto bail; }
@@ -627,6 +637,10 @@ int user_dlm_destroy_lock(struct user_lo status =ocfs2_dlm_unlock (conn, &lockres->l_lksb,DLM_LKF_VALBLK );if (status) { +spin_lock (&lockres->l_lock); + lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN ; + lockres->l_flags &= ~USER_LOCK_BUSY ; +spin_unlock (&lockres->l_lock);user_log_dlm_error ("ocfs2_dlm_unlock" , status, lockres); goto bail; }
Greg Kroah-Hartman
maintainerPATCH 376/452 scsi: dc395x: Fix a missing check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 036a45aa587a10fa2abbd50fbd0f6c4cfc44f69f upstream.
The bug is here:
p->target_id, p->target_lun);
The list iterator 'p' will point to a bogus position containing HEAD if the list is empty or no element is found. This case must be checked before any use of the iterator, otherwise it will lead to an invalid memory access.
To fix this bug, add a check. Use a new variable 'iter' as the list iterator, and use the original variable 'p' as a dedicated pointer to point to the found element.
--- drivers/scsi/dc395x.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/scsi/dc395x.c +12 -3
@@ -3631,10 +3631,19 @@ static struct DeviceCtlBlk *device_alloc#endif if (dcb->target_lun !=0 ) {/* Copy settings */ -struct DeviceCtlBlk *p; -list_for_each_entry (p, &acb->dcb_list, list) -if (p->target_id == dcb->target_id) +struct DeviceCtlBlk *p =NULL , *iter; + +list_for_each_entry (iter, &acb->dcb_list, list) +if (iter->target_id == dcb->target_id) { + p = iter;break ; + } + +if (!p) { +kfree (dcb); +return NULL ; + } + dprintkdbg(DBG_1, "device_alloc: <%02i-%i> copy from <%02i-%i>\n", dcb->target_id, dcb->target_lun,
Greg Kroah-Hartman
maintainerPATCH 377/452 scsi: ufs: qcom: Add a readl() to make sure ref_clk gets enabled
In reply to Greg Kroah-HartmanFrom: Manivannan Sadhasivam <[email protected]>
commit 8eecddfca30e1651dc1c74531ed5eef21dcce7e3 upstream.
In ufs_qcom_dev_ref_clk_ctrl(), it was noted that the ref_clk needs to be stable for at least 1us. Even though there is wmb() to make sure the write gets "completed", there is no guarantee that the write actually reached the UFS device. There is a good chance that the write could be stored in a Write Buffer (WB). In that case, even though the CPU waits for 1us, the ref_clk might not be stable for that period.
So lets do a readl() to make sure that the previous write has reached the UFS device before udelay().
Also, the wmb() after writel_relaxed() is not really needed. Both writel() and readl() are ordered on all architectures and the CPU won't speculate instructions after readl() due to the in-built control dependency with read value on weakly ordered architectures. So it can be safely removed.
--- drivers/scsi/ufs/ufs-qcom.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +5 -2
@@ -664,8 +664,11 @@ static void ufs_qcom_dev_ref_clk_ctrl(stwritel_relaxed (temp, host->dev_ref_clk_ctrl_mmio); -/* ensure that ref_clk is enabled/disabled before we return */ -wmb (); +/* +* Make sure the write to ref_clk reaches the destination and +* not stored in a Write Buffer (WB). +*/ +readl (host->dev_ref_clk_ctrl_mmio);/* * If we call hibern8 exit after this, we need to make sure that
Greg Kroah-Hartman
maintainerPATCH 378/452 drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
In reply to Greg Kroah-HartmanFrom: Dave Airlie <[email protected]>
commit 31ab27b14daaa75541a415c6794d6f3567fea44a upstream.
Submitting a cs with 0 chunks, causes an oops later, found trying to execute the wrong userspace driver.
MESA_LOADER_DRIVER_OVERRIDE=v3d glxinfo
[172536.665184] BUG: kernel NULL pointer dereference, address: 00000000000001d8 [172536.665188] #PF: supervisor read access in kernel mode [172536.665189] #PF: error_code(0x0000) - not-present page [172536.665191] PGD 6712a0067 P4D 6712a0067 PUD 5af9ff067 PMD 0 [172536.665195] Oops: 0000 [#1] SMP NOPTI [172536.665197] CPU: 7 PID: 2769838 Comm: glxinfo Tainted: P O 5.10.81 #1-NixOS [172536.665199] Hardware name: To be filled by O.E.M. To be filled by O.E.M./CROSSHAIR V FORMULA-Z, BIOS 2201 03/23/2015 [172536.665272] RIP: 0010:amdgpu_cs_ioctl+0x96/0x1ce0 [amdgpu] [172536.665274] Code: 75 18 00 00 4c 8b b2 88 00 00 00 8b 46 08 48 89 54 24 68 49 89 f7 4c 89 5c 24 60 31 d2 4c 89 74 24 30 85 c0 0f 85 c0 01 00 00 <48> 83 ba d8 01 00 00 00 48 8b b4 24 90 00 00 00 74 16 48 8b 46 10 [172536.665276] RSP: 0018:ffffb47c0e81bbe0 EFLAGS: 00010246 [172536.665277] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [172536.665278] RDX: 0000000000000000 RSI: ffffb47c0e81be28 RDI: ffffb47c0e81bd68 [172536.665279] RBP: ffff936524080010 R08: 0000000000000000 R09: ffffb47c0e81be38 [172536.665281] R10: ffff936524080010 R11: ffff936524080000 R12: ffffb47c0e81bc40 [172536.665282] R13: ffffb47c0e81be28 R14: ffff9367bc410000 R15: ffffb47c0e81be28 [172536.665283] FS: 00007fe35e05d740(0000) GS:ffff936c1edc0000(0000) knlGS:0000000000000000 [172536.665284] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [172536.665286] CR2: 00000000000001d8 CR3: 0000000532e46000 CR4: 00000000000406e0 [172536.665287] Call Trace: [172536.665322] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665332] drm_ioctl_kernel+0xaa/0xf0 [drm] [172536.665338] drm_ioctl+0x201/0x3b0 [drm] [172536.665369] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665372] ? selinux_file_ioctl+0x135/0x230 [172536.665399] amdgpu_drm_ioctl+0x49/0x80 [amdgpu] [172536.665403] __x64_sys_ioctl+0x83/0xb0 [172536.665406] do_syscall_64+0x33/0x40 [172536.665409] entry_SYSCALL_64_after_hwframe+0x44/0xa9
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +1 -1
@@ -116,7 +116,7 @@ static int amdgpu_cs_parser_init(structint ret;if (cs->in.num_chunks ==0 ) -return 0 ; +return -EINVAL ; chunk_array =kmalloc_array (cs->in.num_chunks,sizeof (uint64_t ),GFP_KERNEL );if (!chunk_array)
Greg Kroah-Hartman
maintainerPATCH 379/452 drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
In reply to Greg Kroah-HartmanFrom: Lucas Stach <[email protected]>
commit e168c25526cd0368af098095c2ded4a008007e1b upstream.
When the mapping is already reaped the unmap must be a no-op, as we would otherwise try to remove the mapping twice, corrupting the involved data structures.
--- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/etnaviv/etnaviv_mmu.c +6 -0
@@ -282,6 +282,12 @@ void etnaviv_iommu_unmap_gem(struct etnamutex_lock (&context->lock); +/* Bail if the mapping has been reaped by another thread */ +if (!mapping->context) { +mutex_unlock (&context->lock); +return ; + } +/* If the vram node is on the mm, unmap and remove the node */ if (mapping->vram_node.mm == &context->mm)etnaviv_iommu_remove_mapping (context, mapping);
Greg Kroah-Hartman
maintainerPATCH 380/452 drm/nouveau/clk: Fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 1c3b2a27def609473ed13b1cd668cb10deab49b4 upstream.
The bug is here:
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp)) return cstate;
The list iterator value 'cstate' will *always* be set and non-NULL by list_for_each_entry_from_reverse(), so it is incorrect to assume that the iterator value will be unchanged if the list is empty or no element is found (In fact, it will be a bogus pointer to an invalid structure object containing the HEAD). Also it missed a NULL check at callsite and may lead to invalid memory access after that.
To fix this bug, just return 'encoder' when found, otherwise return NULL. And add the NULL check.
--- drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +4 -2
@@ -135,10 +135,10 @@ nvkm_cstate_find_best(struct nvkm_clk *clist_for_each_entry_from_reverse (cstate, &pstate->list, head) {if (nvkm_cstate_valid (clk, cstate, max_volt, clk->temp)) -break ; +return cstate; } -return cstate; +return NULL ; } static struct nvkm_cstate *
@@ -169,6 +169,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, sif (!list_empty (&pstate->list)) { cstate =nvkm_cstate_get (clk, pstate, cstatei); cstate =nvkm_cstate_find_best (clk, pstate, cstate); +if (!cstate) +return -EINVAL ; }else { cstate = &pstate->base; }
Greg Kroah-Hartman
maintainerPATCH 381/452 drm/nouveau/kms/nv50-: atom: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 6ce4431c7ba7954c4fa6a96ce16ca1b2943e1a83 upstream.
The bug is here:
return encoder;
The list iterator value 'encoder' will *always* be set and non-NULL by drm_for_each_encoder_mask(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass some NULL checks and lead to invalid memory access passing the check.
To fix this bug, just return 'encoder' when found, otherwise return NULL.
--- drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 +++--- drivers/gpu/drm/nouveau/dispnv50/crc.c | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-)
drivers/gpu/drm/nouveau/dispnv50/atom.h +3 -3
@@ -160,14 +160,14 @@ nv50_head_atom_get(struct drm_atomic_stastatic inline struct drm_encoder *nv50_head_atom_get_encoder (struct nv50_head_atom *atom) { -struct drm_encoder *encoder =NULL ; +struct drm_encoder *encoder;/* We only ever have a single encoder */ drm_for_each_encoder_mask (encoder, atom->state.crtc->dev, atom->state.encoder_mask) -break ; +return encoder; -return encoder; +return NULL ; }#define nv50_wndw_atom (p) container_of((p), struct nv50_wndw_atom, state)
drivers/gpu/drm/nouveau/dispnv50/crc.c +22 -5
@@ -411,9 +411,18 @@ void nv50_crc_atomic_check_outp(struct nstruct nv50_head_atom *armh =nv50_head_atom (old_crtc_state);struct nv50_head_atom *asyh =nv50_head_atom (new_crtc_state);struct nv50_outp_atom *outp_atom; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (armh)); -struct drm_encoder *encoder = &outp->base.base; +struct nouveau_encoder *outp; +struct drm_encoder *encoder, *enc; + + enc =nv50_head_atom_get_encoder (armh); +if (!enc) +continue ; + + outp =nv50_real_outp (enc); +if (!outp) +continue ; + + encoder = &outp->base.base;if (!asyh->clr.crc)continue ;
@@ -464,8 +473,16 @@ void nv50_crc_atomic_set(struct nv50_heastruct drm_device *dev = crtc->dev;struct nv50_crc *crc = &head->crc;const struct nv50_crc_func *func =nv50_disp (dev)->core->func->crc; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (asyh)); +struct nouveau_encoder *outp; +struct drm_encoder *encoder; + + encoder =nv50_head_atom_get_encoder (asyh); +if (!encoder) +return ; + + outp =nv50_real_outp (encoder); +if (!outp) +return ; func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src),
Greg Kroah-Hartman
maintainerPATCH 382/452 drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
In reply to Greg Kroah-HartmanFrom: Brian Norris <[email protected]>
commit 8fb6c44fe8468f92ac7b8bbfcca4404a4e88645f upstream.
If the display is not enable()d, then we aren't holding a runtime PM reference here. Thus, it's easy to accidentally cause a hang, if user space is poking around at /dev/drm_dp_aux0 at the "wrong" time.
Let's get a runtime PM reference, and check that we "see" the panel. Don't force any panel power-up, etc., because that can be intrusive, and that's not what other drivers do (see drivers/gpu/drm/bridge/ti-sn65dsi86.c and drivers/gpu/drm/bridge/parade-ps8640.c.)
--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +12 -1
@@ -1639,8 +1639,19 @@ static ssize_t analogix_dpaux_transfer(s struct drm_dp_aux_msg *msg) {struct analogix_dp_device *dp =to_dp (aux); +int ret; -return analogix_dp_transfer (dp, msg); +pm_runtime_get_sync (dp->dev); + + ret =analogix_dp_detect_hpd (dp); +if (ret) + goto out; + + ret =analogix_dp_transfer (dp, msg); +out: +pm_runtime_put (dp->dev); + +return ret; } struct analogix_dp_device *
Greg Kroah-Hartman
maintainerPATCH 383/452 drm/i915/dsi: fix VBT send packet port selection for ICL+
In reply to Greg Kroah-HartmanFrom: Jani Nikula <[email protected]>
commit 0ea917819d12fed41ea4662cc26ffa0060a5c354 upstream.
The VBT send packet port selection was never updated for ICL+ where the 2nd link is on port B instead of port C as in VLV+ DSI.
First, single link DSI needs to use the configured port instead of relying on the VBT sequence block port. Remove the hard-coded port C check here and make it generic. For reference, see commit f915084edc5a ("drm/i915: Changes related to the sequence port no for") for the original VLV specific fix.
Second, the sequence block port number is either 0 or 1, where 1 indicates the 2nd link. Remove the hard-coded port C here for 2nd link. (This could be a "find second set bit" on DSI ports, but just check the two possible options.)
Third, sanity check the result with a warning to avoid a NULL pointer dereference.
--- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/display/intel_dsi_vbt.c +22 -11
@@ -121,9 +121,25 @@ struct i2c_adapter_lookup {#define ICL_GPIO_DDPA_CTRLCLK_2 8#define ICL_GPIO_DDPA_CTRLDATA_2 9 -static enum port intel_dsi_seq_port_to_port (u8 port) +static enum port intel_dsi_seq_port_to_port (struct intel_dsi *intel_dsi, +u8 seq_port) { -return port ?PORT_C :PORT_A ; +/* +* If single link DSI is being used on any port, the VBT sequence block +* send packet apparently always has 0 for the port. Just use the port +* we have configured, and ignore the sequence block port. +*/ +if (hweight8 (intel_dsi->ports) ==1 ) +return ffs (intel_dsi->ports) -1 ; + +if (seq_port) { +if (intel_dsi->ports &PORT_B ) +return PORT_B ; +else if (intel_dsi->ports &PORT_C ) +return PORT_C ; + } + +return PORT_A ; } static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
@@ -145,15 +161,10 @@ static const u8 *mipi_exec_send_packet(s seq_port = (flags >>MIPI_PORT_SHIFT ) &3 ; -/* For DSI single link on Port A & C, the seq_port value which is -* parsed from Sequence Block#53 of VBT has been set to 0 -* Now, read/write of packets for the DSI single link on Port A and -* Port C will based on the DVO port from VBT block 2. -*/ -if (intel_dsi->ports == (1 <<PORT_C )) - port =PORT_C ; -else - port =intel_dsi_seq_port_to_port (seq_port); + port =intel_dsi_seq_port_to_port (intel_dsi, seq_port); + +if (drm_WARN_ON (&dev_priv->drm, !intel_dsi->dsi_hosts[port])) + goto out; dsi_device = intel_dsi->dsi_hosts[port]->device;if (!dsi_device) {
Greg Kroah-Hartman
maintainerPATCH 384/452 md: fix an incorrect NULL check in does_sb_need_changing
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit fc8738343eefc4ea8afb6122826dea48eacde514 upstream.
The bug is here:
if (!rdev)
The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass the NULL check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'rdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/md/md.c +5 -3
@@ -2648,14 +2648,16 @@ static void sync_sbs(struct mddev *mddevstatic bool does_sb_need_changing (struct mddev *mddev) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;struct mdp_superblock_1 *sb;int role;/* Find a good rdev */ -rdev_for_each (rdev, mddev) -if ((rdev->raid_disk >=0 ) && !test_bit (Faulty, &rdev->flags)) +rdev_for_each (iter, mddev) +if ((iter->raid_disk >=0 ) && !test_bit (Faulty, &iter->flags)) { + rdev = iter;break ; + }/* No good device found. */ if (!rdev)
Greg Kroah-Hartman
maintainerPATCH 385/452 md: fix an incorrect NULL check in md_reload_sb
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 64c54d9244a4efe9bc6e9c98e13c4bbb8bb39083 upstream.
The bug is here:
if (!rdev || rdev->desc_nr != nr) {The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each_rcu(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found (In fact, it will be a bogus pointer to an invalid struct object containing the HEAD). Otherwise it will bypass the check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'pdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/md/md.c +6 -4
@@ -9730,16 +9730,18 @@ static int read_rdev(struct mddev *mddevvoid md_reload_sb (struct mddev *mddev,int nr) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;int err;/* Find the rdev */ -rdev_for_each_rcu (rdev, mddev) { -if (rdev->desc_nr == nr) +rdev_for_each_rcu (iter, mddev) { +if (iter->desc_nr == nr) { + rdev = iter;break ; + } } -if (!rdev || rdev->desc_nr != nr) { +if (!rdev) {pr_warn ("%s: %d Could not find rdev with nr %d\n" , __func__, __LINE__, nr);return ; }
Greg Kroah-Hartman
maintainerPATCH 386/452 mtd: cfi_cmdset_0002: Move and rename chip_check/chip_ready/chip_good_for_write
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 083084df578a8bdb18334f69e7b32d690aaa3247 upstream.
This is a preparation patch for the S29GL064N buffer writes fix. There is no functional change.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 95 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 63 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +32 -63
@@ -798,21 +798,25 @@ static struct mtd_info *cfi_amdstd_setup }/* -* Return true if the chip is ready. +* Return true if the chip is ready and has the correct value. * * Ready is one of: read mode, query mode, erase-suspend-read mode (in any * non-suspended sector) and is indicated by no toggle bits toggling. * +* Error are indicated by toggling bits or bits held with the wrong value, +* or with bits toggling. +* * Note that anything more complicated than checking if no bits are toggling * (including checking DQ5 for an error status) is tricky to get working * correctly and is therefore not done (particularly with interleaved chips * as each chip must be checked independently of the others). */ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, -unsigned long addr) +unsigned long addr,map_word *expected) {struct cfi_private *cfi = map->fldrv_priv;map_word d, t; +int ret;if (cfi_use_status_reg (cfi)) {map_word ready =CMD (CFI_SR_DRB );
@@ -822,57 +826,20 @@ static int __xipram chip_ready(struct ma*/ cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type,NULL ); - d =map_read (map, addr); + t =map_read (map, addr); -return map_word_andequal (map, d, ready, ready); +return map_word_andequal (map, t, ready, ready); } d =map_read (map, addr); t =map_read (map, addr); -return map_word_equal (map, d, t); -} - -/* -* Return true if the chip is ready and has the correct value. -* -* Ready is one of: read mode, query mode, erase-suspend-read mode (in any -* non-suspended sector) and it is indicated by no bits toggling. -* -* Error are indicated by toggling bits or bits held with the wrong value, -* or with bits toggling. -* -* Note that anything more complicated than checking if no bits are toggling -* (including checking DQ5 for an error status) is tricky to get working -* correctly and is therefore not done (particularly with interleaved chips -* as each chip must be checked independently of the others). -* -*/ -static int __xipram chip_good(struct map_info *map, struct flchip *chip, -unsigned long addr,map_word expected) -{ -struct cfi_private *cfi = map->fldrv_priv; -map_word oldd, curd; - -if (cfi_use_status_reg (cfi)) { -map_word ready =CMD (CFI_SR_DRB ); - -/* -* For chips that support status register, check device -* ready bit -*/ -cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, - cfi->device_type,NULL ); - curd =map_read (map, addr); - -return map_word_andequal (map, curd, ready, ready); - } + ret =map_word_equal (map, d, t); - oldd =map_read (map, addr); - curd =map_read (map, addr); +if (!ret || !expected) +return ret; -return map_word_equal (map, oldd, curd) && -map_word_equal (map, curd, expected); +return map_word_equal (map, t, *expected); }static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode)
@@ -889,7 +856,7 @@ static int get_chip(struct map_info *mapcase FL_STATUS :for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -927,7 +894,7 @@ static int get_chip(struct map_info *map chip->state =FL_ERASE_SUSPENDING ; chip->erase_suspended =1 ;for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1458,7 +1425,7 @@ static int do_otp_lock(struct map_info */* wait for chip to become ready */ timeo = jiffies +msecs_to_jiffies (2 );for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1690,11 +1657,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1702,7 +1669,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1970,18 +1937,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2190,7 +2157,7 @@ static int cfi_amdstd_panic_wait(struct* If the driver thinks the chip is idle, and no toggle bits * are changing, then the chip is actually idle for sure. */ -if (chip->state ==FL_READY &&chip_ready (map, chip, adr)) +if (chip->state ==FL_READY &&chip_ready (map, chip, adr,NULL ))return 0 ;/*
@@ -2207,7 +2174,7 @@ static int cfi_amdstd_panic_wait(struct/* wait for the chip to become ready */ for (i =0 ; i <jiffies_to_usecs (timeo); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))return 0 ;udelay (1 );
@@ -2271,13 +2238,13 @@ retry:map_write (map, datum, adr);for (i =0 ; i <jiffies_to_usecs (uWriteTimeout); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;udelay (1 ); } -if (!chip_good (map, chip, adr, datum) || +if (!chip_ready (map, chip, adr, &datum) ||cfi_check_err_status (map, chip, adr)) {/* reset on all failures. */ map_write (map,CMD (0xF0 ), chip->start);
@@ -2419,6 +2386,7 @@ static int __xipram do_erase_chip(structDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr = cfi->addr_unlock1;
@@ -2473,7 +2441,7 @@ static int __xipram do_erase_chip(struct chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2518,6 +2486,7 @@ static int __xipram do_erase_oneblock(stDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr += chip->start;
@@ -2572,7 +2541,7 @@ static int __xipram do_erase_oneblock(st chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2766,7 +2735,7 @@ static int __maybe_unused do_ppb_xxlock(*/ timeo = jiffies +msecs_to_jiffies (2000 );/* 2s max (un)locking */ for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
Greg Kroah-Hartman
maintainerPATCH 387/452 mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 0a8e98305f63deaf0a799d5cf5532cc83af035d1 upstream.
Since commit dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") buffered writes fail on S29GL064N. This is because, on S29GL064N, reads return 0xFF at the end of DQ polling for write completion, where as, chip_good() check expects actual data written to the last location to be returned post DQ polling completion. Fix is to revert to using chip_good() for S29GL064N which only checks for DQ lines to settle down to determine write completion.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 42 +++++++++++++++++++++++++++++------- include/linux/mtd/cfi.h | 1 2 files changed, 35 insertions(+), 8 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +34 -8
@@ -59,6 +59,10 @@#define CFI_SR_WBASB BIT(3)#define CFI_SR_SLSB BIT(1) +enum cfi_quirks { +CFI_QUIRK_DQ_TRUE_DATA =BIT (0 ), +}; +static int cfi_amdstd_read (struct mtd_info *,loff_t ,size_t ,size_t *,u_char *);static int cfi_amdstd_write_words (struct mtd_info *,loff_t ,size_t ,size_t *,const u_char *);#if !FORCE_WORD_WRITE
@@ -432,6 +436,15 @@ static void fixup_s29ns512p_sectors(stru mtd->name); } +static void fixup_quirks (struct mtd_info *mtd) +{ +struct map_info *map = mtd->priv; +struct cfi_private *cfi = map->fldrv_priv; + +if (cfi->mfr ==CFI_MFR_AMD && cfi->id ==0x0c01 ) + cfi->quirks |=CFI_QUIRK_DQ_TRUE_DATA ; +} +/* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { {CFI_MFR_SST ,0x234a , fixup_sst39vf },/* SST39VF1602 */
@@ -470,6 +483,7 @@ static struct cfi_fixup cfi_fixup_table[ #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif + { CFI_MFR_ANY, CFI_ID_ANY, fixup_quirks }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = {
@@ -842,6 +856,18 @@ static int __xipram chip_ready(struct mareturn map_word_equal (map, t, *expected); } +static int __xipram chip_good(struct map_info *map, struct flchip *chip, +unsigned long addr,map_word *expected) +{ +struct cfi_private *cfi = map->fldrv_priv; +map_word *datum = expected; + +if (cfi->quirks &CFI_QUIRK_DQ_TRUE_DATA ) + datum =NULL ; + +return chip_ready (map, chip, addr, datum); +} +static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode) {DECLARE_WAITQUEUE (wait, current);
@@ -1657,11 +1683,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1669,7 +1695,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1937,18 +1963,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
include/linux/mtd/cfi.h +1 -0
@@ -286,6 +286,7 @@ struct cfi_private {map_word sector_erase_cmd;unsigned long chipshift;/* Because they're of the same type */ const char *im_name;/* inter_module name for cmdset_setup */ +unsigned long quirks;struct flchip chips[];/* per-chip data structure for each chip */ };
Greg Kroah-Hartman
maintainerPATCH 388/452 media: coda: Fix reported H264 profile
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit 7110c08ea71953a7fc342f0b76046f72442cf26c upstream.
The CODA960 manual states that ASO/FMO features of baseline are not supported, so for this reason this driver should only report constrained baseline support.
This fixes negotiation issue with constrained baseline content on GStreamer 1.17.1.
ASO/FMO features are unsupported for the encoder and untested for the decoder because there is currently no userspace support. Neither GStreamer parsers nor FFMPEG parsers support ASO/FMO.
--- drivers/media/platform/coda/coda-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/platform/coda/coda-common.c +3 -3
@@ -2343,8 +2343,8 @@ static void coda_encode_ctrls(struct cod V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ,0x0 , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ); +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ,0x0 , +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE );if (ctx->dev->devtype->product ==CODA_HX4 || ctx->dev->devtype->product ==CODA_7541 ) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@@ -2425,7 +2425,7 @@ static void coda_decode_ctrls(struct cod ctx->h264_profile_ctrl =v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE ,V4L2_MPEG_VIDEO_H264_PROFILE_HIGH , - ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ) | + ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH )),V4L2_MPEG_VIDEO_H264_PROFILE_HIGH );
Greg Kroah-Hartman
maintainerPATCH 389/452 media: coda: Add more H264 levels for CODA960
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit eb2fd187abc878a2dfad46902becb74963473c7d upstream.
Add H264 level 1.0, 4.1, 4.2 to the list of supported formats. While the hardware does not fully support these levels, it does support most of them. The constraints on frame size and pixel formats already cover the limitation.
This fixes negotiation of level on GStreamer 1.17.1.
--- drivers/media/platform/coda/coda-common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/media/platform/coda/coda-common.c +6 -3
@@ -2358,12 +2358,15 @@ static void coda_encode_ctrls(struct codif (ctx->dev->devtype->product ==CODA_960 ) {v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_LEVEL , -V4L2_MPEG_VIDEO_H264_LEVEL_4_0 , - ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | +V4L2_MPEG_VIDEO_H264_LEVEL_4_2 , + ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_1_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_1 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_2 ) | - (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 )), + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_1 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_2 )),V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ); } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
Greg Kroah-Hartman
maintainerPATCH 390/452 ima: remove the IMA_TEMPLATE Kconfig option
In reply to Greg Kroah-HartmanFrom: GUO Zihua <[email protected]>
commit 891163adf180bc369b2f11c9dfce6d2758d2a5bd upstream.
The original 'ima' measurement list template contains a hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. Other measurement list templates permit both larger hashes and longer pathnames. When the "ima" template is configured as the default, a new measurement list template (ima_template=) must be specified before specifying a larger hash algorithm (ima_hash=) on the boot command line.
To avoid this boot command line ordering issue, remove the legacy "ima" template configuration option, allowing it to still be specified on the boot command line.
The root cause of this issue is that during the processing of ima_hash, we would try to check whether the hash algorithm is compatible with the template. If the template is not set at the moment we do the check, we check the algorithm against the configured default template. If the default template is "ima", then we reject any hash algorithm other than sha1 and md5.
For example, if the compiled default template is "ima", and the default algorithm is sha1 (which is the current default). In the cmdline, we put in "ima_hash=sha256 ima_template=ima-ng". The expected behavior would be that ima starts with ima-ng as the template and sha256 as the hash algorithm. However, during the processing of "ima_hash=", "ima_template=" has not been processed yet, and hash_setup would check the configured hash algorithm against the compiled default: ima, and reject sha256. So at the end, the hash algorithm that is actually used will be sha1.
With template "ima" removed from the configured default, we ensure that the default tempalte would at least be "ima-ng" which allows for basically any hash algorithm.
This change would not break the algorithm compatibility checks for IMA.
--- security/integrity/ima/Kconfig | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
security/integrity/ima/Kconfig +6 -8
@@ -69,10 +69,9 @@ choice hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. The 'ima-ng' measurement list template permits both larger hash digests and longer - pathnames. + pathnames. The configured default template can be replaced + by specifying "ima_template=" on the boot command line. - config IMA_TEMPLATE - bool "ima" config IMA_NG_TEMPLATE bool "ima-ng (default)" config IMA_SIG_TEMPLATE
@@ -82,7 +81,6 @@ endchoice config IMA_DEFAULT_TEMPLATE string depends on IMA - default "ima" if IMA_TEMPLATE default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE
@@ -102,19 +100,19 @@ choice config IMA_DEFAULT_HASH_SHA256 bool "SHA256" - depends on CRYPTO_SHA256=y && !IMA_TEMPLATE + depends on CRYPTO_SHA256=y config IMA_DEFAULT_HASH_SHA512 bool "SHA512" - depends on CRYPTO_SHA512=y && !IMA_TEMPLATE + depends on CRYPTO_SHA512=y config IMA_DEFAULT_HASH_WP512 bool "WP512" - depends on CRYPTO_WP512=y && !IMA_TEMPLATE + depends on CRYPTO_WP512=y config IMA_DEFAULT_HASH_SM3 bool "SM3" - depends on CRYPTO_SM3=y && !IMA_TEMPLATE + depends on CRYPTO_SM3=y endchoice config IMA_DEFAULT_HASH
Greg Kroah-Hartman
maintainerPATCH 391/452 Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 1aa0e8b144b6474c4914439d232d15bfe883636b upstream.
Add a config option to guard (future) usage of asm_volatile_goto() that includes "tied outputs", i.e. "+" constraints that specify both an input and output parameter. clang-13 has a bug[1] that causes compilation of such inline asm to fail, and KVM wants to use a "+m" constraint to implement a uaccess form of CMPXCHG[2]. E.g. the test code fails with
<stdin>:1:29: error: invalid operand in inline asm: '.long (${1:l}) - .'
int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }
^
<stdin>:1:29: error: unknown token in expression
<inline asm>:1:9: note: instantiated into assembly here
.long () - .
^2 errors generated.
on clang-13, but passes on gcc (with appropriate asm goto support). The bug is fixed in clang-14, but won't be backported to clang-13 as the changes are too invasive/risky.
gcc also had a similar bug[3], fixed in gcc-11, where gcc failed to account for its behavior of assigning two numbers to tied outputs (one for input, one for output) when evaluating symbolic references.
[1] https://github.com/ClangBuiltLinux/linux/issues/1512
[2] https://lore.kernel.org/all/YfMruK8%[email protected]
[3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98096
Message-Id: <[email protected]>
--- init/Kconfig | 5 +++++ 1 file changed, 5 insertions(+)
init/Kconfig +5 -0
@@ -68,6 +68,11 @@ config CC_HAS_ASM_GOTO_OUTPUT depends on CC_HAS_ASM_GOTO def_bool $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null) +config CC_HAS_ASM_GOTO_TIED_OUTPUT + depends on CC_HAS_ASM_GOTO_OUTPUT + # Detect buggy gcc and clang, fixed in gcc-11 clang-14. + def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null) + config TOOLS_SUPPORT_RELR def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
Greg Kroah-Hartman
maintainerPATCH 392/452 RDMA/hfi1: Fix potential integer multiplication overflow errors
In reply to Greg Kroah-HartmanFrom: Dennis Dalessandro <[email protected]>
commit f93e91a0372c922c20d5bee260b0f43b4b8a1bee upstream.
When multiplying of different types, an overflow is possible even when storing the result in a larger type. This is because the conversion is done after the multiplication. So arithmetic overflow and thus in incorrect value is possible.
Correct an instance of this in the inter packet delay calculation. Fix by ensuring one of the operands is u64 which will promote the other to u64 as well ensuring no overflow.
--- drivers/infiniband/hw/hfi1/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/hfi1/init.c +1 -1
@@ -530,7 +530,7 @@ void set_link_ipg(struct hfi1_pportdatau16 shift, mult;u64 src;u32 current_egress_rate;/* Mbits /sec */ -u32 max_pkt_time; +u64 max_pkt_time;/* * max_pkt_time is the maximum packet egress time in units * of the fabric clock period 1/(805 MHz).
Greg Kroah-Hartman
maintainerPATCH 393/452 csky: patch_text: Fixup last cpu should be master
In reply to Greg Kroah-HartmanFrom: Guo Ren <[email protected]>
commit 8c4d16471e2babe9bdfe41d6ef724526629696cb upstream.
These patch_text implementations are using stop_machine_cpuslocked infrastructure with atomic cpu_count. The original idea: When the master CPU patch_text, the others should wait for it. But current implementation is using the first CPU as master, which couldn't guarantee the remaining CPUs are waiting. This patch changes the last CPU as the master to solve the potential risk.
--- arch/csky/kernel/probes/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/csky/kernel/probes/kprobes.c +1 -1
@@ -28,7 +28,7 @@ static int __kprobes patch_text_cb(voidstruct csky_insn_patch *param = priv;unsigned int addr = (unsigned int )param->addr; -if (atomic_inc_return (¶m->cpu_count) ==1 ) { +if (atomic_inc_return (¶m->cpu_count) ==num_online_cpus ()) { *(u16 *) addr =cpu_to_le16 (param->opcode);dcache_wb_range (addr, addr +2 );atomic_inc (¶m->cpu_count);
Greg Kroah-Hartman
maintainerPATCH 394/452 irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375, A38x, A39x
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
commit a3d66a76348daf559873f19afc912a2a7c2ccdaf upstream.
Register ARMADA_370_XP_INT_FABRIC_MASK_OFFS is Armada 370 and XP specific and on new Armada platforms it has different meaning. It does not configure Performance Counter Overflow interrupt masking. So do not touch this register on non-A370/XP platforms (A375, A38x and A39x).
--- drivers/irqchip/irq-armada-370-xp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +10 -1
@@ -308,7 +308,16 @@ static inline int armada_370_xp_msi_initstatic void armada_xp_mpic_perf_init (void ) { -unsigned long cpuid =cpu_logical_map (smp_processor_id ()); +unsigned long cpuid; + +/* +* This Performance Counter Overflow interrupt is specific for +* Armada 370 and XP. It is not available on Armada 375, 38x and 39x. +*/ +if (!of_machine_is_compatible ("marvell,armada-370-xp" )) +return ; + + cpuid =cpu_logical_map (smp_processor_id ());/* Enable Performance Counter Overflow interrupts */ writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
Greg Kroah-Hartman
maintainerPATCH 395/452 irqchip: irq-xtensa-mx: fix initial IRQ affinity
In reply to Greg Kroah-HartmanFrom: Max Filippov <[email protected]>
commit a255ee29252066d621df5d6b420bf534c6ba5bc0 upstream.
When irq-xtensa-mx chip is used in non-SMP configuration its irq_set_affinity callback is not called leaving IRQ affinity set empty. As a result IRQ delivery does not work in that configuration. Initialize IRQ affinity of the xtensa MX interrupt distributor to CPU 0 for all external IRQ lines.
--- drivers/irqchip/irq-xtensa-mx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/irqchip/irq-xtensa-mx.c +14 -4
@@ -151,14 +151,25 @@ static struct irq_chip xtensa_mx_irq_chi .irq_set_affinity = xtensa_mx_irq_set_affinity, }; +static void __init xtensa_mx_init_common (struct irq_domain *root_domain) +{ +unsigned int i; + +irq_set_default_host (root_domain); +secondary_init_irq (); + +/* Initialize default IRQ routing to CPU 0 */ +for (i =0 ; i <XCHAL_NUM_EXTINTERRUPTS ; ++i) +set_er (1 ,MIROUT (i)); +} +int __init xtensa_mx_init_legacy (struct device_node *interrupt_parent) {struct irq_domain *root_domain =irq_domain_add_legacy (NULL ,NR_IRQS -1 ,1 ,0 , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }
@@ -168,8 +179,7 @@ static int __init xtensa_mx_init(structstruct irq_domain *root_domain =irq_domain_add_linear (np,NR_IRQS , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }IRQCHIP_DECLARE (xtensa_mx_irq_chip,"cdns,xtensa-mx" , xtensa_mx_init);
Greg Kroah-Hartman
maintainerPATCH 396/452 cfg80211: declare MODULE_FIRMWARE for regulatory.db
In reply to Greg Kroah-HartmanFrom: Dimitri John Ledkov <[email protected]>
commit 7bc7981eeebe1b8e603ad2ffc5e84f4df76920dd upstream.
Add MODULE_FIRMWARE declarations for regulatory.db and regulatory.db.p7s such that userspace tooling can discover and include these files.
--- net/wireless/reg.c | 4 ++++ 1 file changed, 4 insertions(+)
net/wireless/reg.c +4 -0
@@ -787,6 +787,8 @@ static int __init load_builtin_regdb_keyreturn 0 ; } +MODULE_FIRMWARE ("regulatory.db.p7s" ); +static bool regdb_has_valid_signature (const u8 *data,unsigned int size) {const struct firmware *sig;
@@ -1058,6 +1060,8 @@ static void regdb_fw_cb(const struct firrelease_firmware (fw); } +MODULE_FIRMWARE ("regulatory.db" ); +static int query_regdb_file (const char *alpha2) {ASSERT_RTNL ();
Greg Kroah-Hartman
maintainerPATCH 397/452 mac80211: upgrade passive scan to active scan on DFS channels after beacon rx
In reply to Greg Kroah-HartmanFrom: Felix Fietkau <[email protected]>
commit b041b7b9de6e1d4362de855ab90f9d03ef323edd upstream.
In client mode, we can't connect to hidden SSID APs or SSIDs not advertised in beacons on DFS channels, since we're forced to passive scan. Fix this by sending out a probe request immediately after the first beacon, if active scan was requested by the user.
--- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/scan.c | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+)
net/mac80211/ieee80211_i.h +5 -0
@@ -1103,6 +1103,9 @@ struct tpt_led_trigger {* a scan complete for an aborted scan. * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being * cancelled. +* @SCAN_BEACON_WAIT: Set whenever we're passive scanning because of radar/no-IR +* and could send a probe request after receiving a beacon. +* @SCAN_BEACON_DONE: Beacon received, we can now send a probe request */ enum {SCAN_SW_SCANNING ,
@@ -1111,6 +1114,8 @@ enum {SCAN_COMPLETED ,SCAN_ABORTED ,SCAN_HW_CANCELLED , +SCAN_BEACON_WAIT , + SCAN_BEACON_DONE, };/**
net/mac80211/scan.c +20 -0
@@ -277,6 +277,16 @@ void ieee80211_scan_rx(struct ieee80211_if (likely (!sdata1 && !sdata2))return ; +if (test_and_clear_bit (SCAN_BEACON_WAIT , &local->scanning)) { +/* +* we were passive scanning because of radar/no-IR, but +* the beacon/proberesp rx gives us an opportunity to upgrade +* to active scan +*/ +set_bit (SCAN_BEACON_DONE , &local->scanning); +ieee80211_queue_delayed_work (&local->hw, &local->scan_work,0 ); + } +if (ieee80211_is_probe_resp (mgmt->frame_control)) {struct cfg80211_scan_request *scan_req;struct cfg80211_sched_scan_request *sched_scan_req;
@@ -783,6 +793,8 @@ static int __ieee80211_start_scan(struct IEEE80211_CHAN_RADAR)) || !req->n_ssids) { next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + if (req->n_ssids) + set_bit(SCAN_BEACON_WAIT, &local->scanning); } else {ieee80211_scan_state_send_probe (local, &next_delay); next_delay =IEEE80211_CHANNEL_TIME ;
@@ -994,6 +1006,8 @@ set_channel: !scan_req->n_ssids) { *next_delay =IEEE80211_PASSIVE_CHANNEL_TIME ; local->next_scan_state =SCAN_DECISION ; +if (scan_req->n_ssids) +set_bit (SCAN_BEACON_WAIT , &local->scanning);return ; }
@@ -1086,6 +1100,8 @@ void ieee80211_scan_work(struct work_str goto out; } +clear_bit (SCAN_BEACON_WAIT , &local->scanning); +/* * as long as no delay is required advance immediately * without scheduling a new work
@@ -1096,6 +1112,10 @@ void ieee80211_scan_work(struct work_str goto out_complete; } +if (test_and_clear_bit (SCAN_BEACON_DONE , &local->scanning) && + local->next_scan_state ==SCAN_DECISION ) + local->next_scan_state =SCAN_SEND_PROBE ; +switch (local->next_scan_state) {case SCAN_DECISION :/* if no more bands/channels left, complete scan */
Greg Kroah-Hartman
maintainerPATCH 398/452 um: chan_user: Fix winch_tramp() return value
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 57ae0b67b747031bc41fb44643aa5344ab58607e upstream.
The previous fix here was only partially correct, it did result in returning a proper error value in case of error, but it also clobbered the pid that we need to return from this function (not just zero for success).
As a result, it returned 0 here, but later this is treated as a pid and used to kill the process, but since it's now 0 we kill(0, SIGKILL), which makes UML kill itself rather than just the helper thread.
Fix that and make it more obvious by using a separate variable for the pid.
--- arch/um/drivers/chan_user.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/um/drivers/chan_user.c +5 -4
@@ -220,7 +220,7 @@ static int winch_tramp(int fd, struct tt unsigned long *stack_out) {struct winch_data data; -int fds[2 ], n, err; +int fds[2 ], n, err, pid;char c; err =os_pipe (fds,1 ,1 );
@@ -238,8 +238,9 @@ static int winch_tramp(int fd, struct tt* problem with /dev/net/tun, which if held open by this * thread, prevents the TUN/TAP device from being reused. */ - err =run_helper_thread (winch_thread, &data,CLONE_FILES , stack_out); -if (err <0 ) { + pid =run_helper_thread (winch_thread, &data,CLONE_FILES , stack_out); +if (pid <0 ) { + err = pid;printk (UM_KERN_ERR "fork of winch_thread failed - errno = %d\n" , -err); goto out_close;
@@ -263,7 +264,7 @@ static int winch_tramp(int fd, struct tt goto out_close; } -return err; +return pid; out_close:close (fds[1 ]);
Greg Kroah-Hartman
maintainerPATCH 399/452 um: Fix out-of-bounds read in LDT setup
In reply to Greg Kroah-HartmanFrom: Vincent Whitchurch <[email protected]>
commit 2a4a62a14be1947fa945c5c11ebf67326381a568 upstream.
syscall_stub_data() expects the data_count parameter to be the number of longs, not bytes.
==================================================================
BUG: KASAN: stack-out-of-bounds in syscall_stub_data+0x70/0xe0 Read of size 128 at addr 000000006411f6f0 by task swapper/1 CPU: 0 PID: 1 Comm: swapper Not tainted 5.18.0+ #18 Call Trace: show_stack.cold+0x166/0x2a7 __dump_stack+0x3a/0x43 dump_stack_lvl+0x1f/0x27 print_report.cold+0xdb/0xf81 kasan_report+0x119/0x1f0 kasan_check_range+0x3a3/0x440 memcpy+0x52/0x140 syscall_stub_data+0x70/0xe0 write_ldt_entry+0xac/0x190 init_new_ldt+0x515/0x960 init_new_context+0x2c4/0x4d0 mm_init.constprop.0+0x5ed/0x760 mm_alloc+0x118/0x170 0x60033f48 do_one_initcall+0x1d7/0x860 0x60003e7b kernel_init+0x6e/0x3d4 new_thread_handler+0x1e7/0x2c0 The buggy address belongs to stack of task swapper/1 and is located at offset 64 in frame: init_new_ldt+0x0/0x960
This frame has 2 objects:
[32, 40) 'addr'
[64, 80) 'desc'
==================================================================
--- arch/x86/um/ldt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/um/ldt.c +4 -2
@@ -23,9 +23,11 @@ static long write_ldt_entry(struct mm_id {long res;void *stub_addr; + +BUILD_BUG_ON (sizeof (*desc) %sizeof (long )); + res =syscall_stub_data (mm_idp, (unsigned long *)desc, - (sizeof (*desc) +sizeof (long ) -1 ) & - ~(sizeof (long ) -1 ), +sizeof (*desc) /sizeof (long ), addr, &stub_addr);if (!res) { unsigned long args[] = { func,
Greg Kroah-Hartman
maintainerPATCH 400/452 kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add]
In reply to Greg Kroah-HartmanFrom: Naveen N. Rao <[email protected]>
commit 3e35142ef99fe6b4fe5d834ad43ee13cca10a2dc upstream.
Since commit d1bcae833b32f1 ("ELF: Don't generate unused section symbols") [1], binutils (v2.36+) started dropping section symbols that it thought were unused. This isn't an issue in general, but with kexec_file.c, gcc is placing kexec_arch_apply_relocations[_add] into a separate .text.unlikely section and the section symbol ".text.unlikely" is being dropped. Due to this, recordmcount is unable to find a non-weak symbol in .text.unlikely to generate a relocation record against.
Address this by dropping the weak attribute from these functions. Instead, follow the existing pattern of having architectures #define the name of the function they want to override in their headers.
[1] https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=d1bcae833b32f1
--- arch/s390/include/asm/kexec.h | 10 +++++++++ arch/x86/include/asm/kexec.h | 8 +++++++ include/linux/kexec.h | 46 ++++++++++++++++++++++++++++++++++-------- kernel/kexec_file.c | 34 ------------------------------- 4 files changed, 56 insertions(+), 42 deletions(-)
arch/s390/include/asm/kexec.h +10 -0
@@ -9,6 +9,8 @@#ifndef _S390_KEXEC_H#define _S390_KEXEC_H +#include <linux/module.h> +#include <asm/processor.h> #include <asm/page.h> #include <asm/setup.h>
@@ -83,4 +85,12 @@ struct kimage_arch {extern const struct kexec_file_ops s390_kexec_image_ops;extern const struct kexec_file_ops s390_kexec_elf_ops; +#ifdef CONFIG_KEXEC_FILE +struct purgatory_info ; +int arch_kexec_apply_relocations_add (struct purgatory_info *pi, +Elf_Shdr *section, +const Elf_Shdr *relsec, +const Elf_Shdr *symtab); +#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add +#endif #endif /*_S390_KEXEC_H */
arch/x86/include/asm/kexec.h +8 -0
@@ -191,6 +191,14 @@ extern int arch_kexec_post_alloc_pages(vextern void arch_kexec_pre_free_pages (void *vaddr,unsigned int pages);#define arch_kexec_pre_free_pages arch_kexec_pre_free_pages +#ifdef CONFIG_KEXEC_FILE +struct purgatory_info ; +int arch_kexec_apply_relocations_add (struct purgatory_info *pi, +Elf_Shdr *section, +const Elf_Shdr *relsec, +const Elf_Shdr *symtab); +#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add +#endif #endif typedef void crash_vmclear_fn (void );
include/linux/kexec.h +38 -8
58 lines not on this page · raw message
kernel/kexec_file.c +0 -34
@@ -109,40 +109,6 @@ int __weak arch_kexec_kernel_verify_sig(#endif /* -* arch_kexec_apply_relocations_add - apply relocations of type RELA -* @pi: Purgatory to be relocated. -* @section: Section relocations applying to. -* @relsec: Section containing RELAs. -* @symtab: Corresponding symtab. -* -* Return: 0 on success, negative errno on error. -*/ -int __weak -arch_kexec_apply_relocations_add (struct purgatory_info *pi,Elf_Shdr *section, -const Elf_Shdr *relsec,const Elf_Shdr *symtab) -{ -pr_err ("RELA relocation unsupported.\n" ); -return -ENOEXEC ; -} - -/* -* arch_kexec_apply_relocations - apply relocations of type REL -* @pi: Purgatory to be relocated. -* @section: Section relocations applying to. -* @relsec: Section containing RELs. -* @symtab: Corresponding symtab. -* -* Return: 0 on success, negative errno on error. -*/ -int __weak -arch_kexec_apply_relocations (struct purgatory_info *pi,Elf_Shdr *section, -const Elf_Shdr *relsec,const Elf_Shdr *symtab) -{ -pr_err ("REL relocation unsupported.\n" ); -return -ENOEXEC ; -} - -/* * Free up memory used by kernel, initrd, and command line. This is temporary * memory allocation which is not needed any more after these buffers have * been loaded into separate segments and have been copied elsewhere.
Greg Kroah-Hartman
maintainerPATCH 401/452 ftrace: Clean up hash direct_functions on register failures
In reply to Greg Kroah-HartmanFrom: Song Liu <[email protected]>
commit 7d54c15cb89a29a5f59e5ffc9ee62e6591769ef1 upstream.
We see the following GPF when register_ftrace_direct fails:
[ ] general protection fault, probably for non-canonical address \
0x200000000000010: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI
[...]
[ ] RIP: 0010:ftrace_find_rec_direct+0x53/0x70
[ ] Code: 48 c1 e0 03 48 03 42 08 48 8b 10 31 c0 48 85 d2 74 [...] [ ] RSP: 0018:ffffc9000138bc10 EFLAGS: 00010206
[ ] RAX: 0000000000000000 RBX: ffffffff813e0df0 RCX: 000000000000003b [ ] RDX: 0200000000000000 RSI: 000000000000000c RDI: ffffffff813e0df0 [ ] RBP: ffffffffa00a3000 R08: ffffffff81180ce0 R09: 0000000000000001 [ ] R10: ffffc9000138bc18 R11: 0000000000000001 R12: ffffffff813e0df0 [ ] R13: ffffffff813e0df0 R14: ffff888171b56400 R15: 0000000000000000 [ ] FS: 00007fa9420c7780(0000) GS:ffff888ff6a00000(0000) knlGS:000000000 [ ] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ ] CR2: 000000000770d000 CR3: 0000000107d50003 CR4: 0000000000370ee0 [ ] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ ] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ ] Call Trace:
[ ] <TASK> [ ] register_ftrace_direct+0x54/0x290 [ ] ? render_sigset_t+0xa0/0xa0 [ ] bpf_trampoline_update+0x3f5/0x4a0 [ ] ? 0xffffffffa00a3000 [ ] bpf_trampoline_link_prog+0xa9/0x140 [ ] bpf_tracing_prog_attach+0x1dc/0x450 [ ] bpf_raw_tracepoint_open+0x9a/0x1e0 [ ] ? find_held_lock+0x2d/0x90 [ ] ? lock_release+0x150/0x430 [ ] __sys_bpf+0xbd6/0x2700 [ ] ? lock_is_held_type+0xd8/0x130 [ ] __x64_sys_bpf+0x1c/0x20 [ ] do_syscall_64+0x3a/0x80 [ ] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ ] RIP: 0033:0x7fa9421defa9
[ ] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 9 f8 [...] [ ] RSP: 002b:00007ffed743bd78 EFLAGS: 00000246 ORIG_RAX: 0000000000000141 [ ] RAX: ffffffffffffffda RBX: 00000000069d2480 RCX: 00007fa9421defa9 [ ] RDX: 0000000000000078 RSI: 00007ffed743bd80 RDI: 0000000000000011 [ ] RBP: 00007ffed743be00 R08: 0000000000bb7270 R09: 0000000000000000 [ ] R10: 00000000069da210 R11: 0000000000000246 R12: 0000000000000001 [ ] R13: 00007ffed743c4b0 R14: 00000000069d2480 R15: 0000000000000001 [ ] </TASK>
[ ] Modules linked in: klp_vm(OK)
[ ] ---[ end trace 0000000000000000 ]---
One way to trigger this is:
1. load a livepatch that patches kernel function xxx;
2. run bpftrace -e 'kfunc:xxx {}', this will fail (expected for now);
3. repeat #2 => gpf.
This is because the entry is added to direct_functions, but not removed. Fix this by remove the entry from direct_functions when register_ftrace_direct fails.
Also remove the last trailing space from ftrace.c, so we don't have to worry about it anymore.
--- kernel/trace/ftrace.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/trace/ftrace.c +2 -3
@@ -4427,7 +4427,7 @@ int ftrace_func_mapper_add_ip(struct ftr* @ip: The instruction pointer address to remove the data from * * Returns the data if it is found, otherwise NULL. -* Note, if the data pointer is used as the data itself, (see +* Note, if the data pointer is used as the data itself, (see * ftrace_func_mapper_find_ip(), then the return value may be meaningless, * if the data pointer was set to zero. */
@@ -5153,8 +5153,6 @@ int register_ftrace_direct(unsigned long__add_hash_entry (direct_functions, entry); ret =ftrace_set_filter_ip (&direct_ops, ip,0 ,0 ); -if (ret) -remove_hash_entry (direct_functions, entry);if (!ret && !(direct_ops.flags &FTRACE_OPS_FL_ENABLED )) { ret =register_ftrace_function (&direct_ops);
@@ -5163,6 +5161,7 @@ int register_ftrace_direct(unsigned long }if (ret) { +remove_hash_entry (direct_functions, entry);kfree (entry);if (!direct->count) {list_del_rcu (&direct->next);
Greg Kroah-Hartman
maintainerPATCH 402/452 iommu/msm: Fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 8b9ad480bd1dd25f4ff4854af5685fa334a2f57a upstream.
The bug is here:
if (!iommu || iommu->dev->of_node != spec->np) {The list iterator value 'iommu' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found (in fact, it will point to a invalid structure object containing HEAD).
To fix the bug, use a new value 'iter' as the list iterator, while use the old value 'iommu' as a dedicated variable to point to the found one, and remove the unneeded check for 'iommu->dev->of_node != spec->np' outside the loop.
--- drivers/iommu/msm_iommu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/iommu/msm_iommu.c +7 -4
@@ -616,16 +616,19 @@ static void insert_iommu_master(struct dstatic int qcom_iommu_of_xlate (struct device *dev,struct of_phandle_args *spec) { -struct msm_iommu_dev *iommu; +struct msm_iommu_dev *iommu =NULL , *iter;unsigned long flags;int ret =0 ;spin_lock_irqsave (&msm_iommu_lock, flags); -list_for_each_entry (iommu, &qcom_iommu_devices, dev_node) -if (iommu->dev->of_node == spec->np) +list_for_each_entry (iter, &qcom_iommu_devices, dev_node) { +if (iter->dev->of_node == spec->np) { + iommu = iter;break ; + } + } -if (!iommu || iommu->dev->of_node != spec->np) { +if (!iommu) { ret = -ENODEV ; goto fail; }
Greg Kroah-Hartman
maintainerPATCH 403/452 nodemask.h: fix compilation error with GCC12
In reply to Greg Kroah-HartmanFrom: Christophe de Dinechin <[email protected]>
commit 37462a920392cb86541650a6f4121155f11f1199 upstream.
With gcc version 12.0.1 20220401 (Red Hat 12.0.1-0), building with defconfig results in the following compilation error:
| CC mm/swapfile.o | mm/swapfile.c: In function `setup_swap_info': | mm/swapfile.c:2291:47: error: array subscript -1 is below array bounds | of `struct plist_node[]' [-Werror=array-bounds] | 2291 | p->avail_lists[i].prio = 1; | | ~~~~~~~~~~~~~~^~~ | In file included from mm/swapfile.c:16: | ./include/linux/swap.h:292:27: note: while referencing `avail_lists' | 292 | struct plist_node avail_lists[]; /* | | ^~~~~~~~~~~
This is due to the compiler detecting that the mask in node_states[__state] could theoretically be zero, which would lead to first_node() returning -1 through find_first_bit.
I believe that the warning/error is legitimate. I first tried adding a test to check that the node mask is not emtpy, since a similar test exists in the case where MAX_NUMNODES == 1.
However, adding the if statement causes other warnings to appear in for_each_cpu_node_but, because it introduces a dangling else ambiguity. And unfortunately, GCC is not smart enough to detect that the added test makes the case where (node) == -1 impossible, so it still complains with the same message.
This is why I settled on replacing that with a harmless, but relatively useless (node) >= 0 test. Based on the warning for the dangling else, I also decided to fix the case where MAX_NUMNODES == 1 by moving the condition inside the for loop. It will still only be tested once. This ensures that the meaning of an else following for_each_node_mask or derivatives would not silently have a different meaning depending on the configuration.
--- include/linux/nodemask.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
include/linux/nodemask.h +6 -7
@@ -375,14 +375,13 @@ static inline void __nodes_fold(nodemask }#if MAX_NUMNODES >1 -#define for_each_node_mask (node, mask) \ - for ((node) = first_node(mask); \ - (node) < MAX_NUMNODES; \ - (node) = next_node((node), (mask))) +#define for_each_node_mask (node, mask) \ + for ((node) = first_node(mask); \ + (node >= 0) && (node) < MAX_NUMNODES; \ + (node) = next_node((node), (mask)))#else /* MAX_NUMNODES == 1 */ -#define for_each_node_mask (node, mask) \ - if (!nodes_empty(mask)) \ - for ((node) = 0; (node) < 1; (node)++) +#define for_each_node_mask (node, mask) \ + for ((node) = 0; (node) < 1 && !nodes_empty(mask); (node)++)#endif /* MAX_NUMNODES */ /*
Greg Kroah-Hartman
maintainerPATCH 404/452 hugetlb: fix huge_pmd_unshare address update
In reply to Greg Kroah-HartmanFrom: Mike Kravetz <[email protected]>
commit 48381273f8734d28ef56a5bdf1966dd8530111bc upstream.
The routine huge_pmd_unshare() is passed a pointer to an address associated with an area which may be unshared. If unshare is successful this address is updated to 'optimize' callers iterating over huge page addresses. For the optimization to work correctly, address should be updated to the last huge page in the unmapped/unshared area. However, in the common case where the passed address is PUD_SIZE aligned, the address is incorrectly updated to the address of the preceding huge page. That wastes CPU cycles as the unmapped/unshared range is scanned twice.
--- mm/hugetlb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
mm/hugetlb.c +8 -1
@@ -5465,7 +5465,14 @@ int huge_pmd_unshare(struct mm_struct *mpud_clear (pud);put_page (virt_to_page (ptep));mm_dec_nr_pmds (mm); - *addr =ALIGN (*addr,HPAGE_SIZE *PTRS_PER_PTE ) -HPAGE_SIZE ; +/* +* This update of passed address optimizes loops sequentially +* processing addresses in increments of huge page size (PMD_SIZE +* in this case). By clearing the pud, a PUD_SIZE area is unmapped. +* Update address to the 'last page' in the cleared area so that +* calling loop can move to first page past this area. +*/ + *addr |=PUD_SIZE -PMD_SIZE ;return 1 ; }#define want_pmd_share () (1)
Greg Kroah-Hartman
maintainerPATCH 405/452 xtensa/simdisk: fix proc_read_simdisk()
In reply to Greg Kroah-HartmanFrom: Yi Yang <[email protected]>
commit b011946d039d66bbc7102137e98cc67e1356aa87 upstream.
The commit a69755b18774 ("xtensa simdisk: switch to proc_create_data()") split read operation into two parts, first retrieving the path when it's non-null and second retrieving the trailing '\n'. However when the path is non-null the first simple_read_from_buffer updates ppos, and the second simple_read_from_buffer returns 0 if ppos is greater than 1 (i.e. almost always). As a result reading from that proc file is almost always empty.
Fix it by making a temporary copy of the path with the trailing '\n' and using simple_read_from_buffer on that copy.
--- arch/xtensa/platforms/iss/simdisk.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
arch/xtensa/platforms/iss/simdisk.c +12 -6
@@ -213,12 +213,18 @@ static ssize_t proc_read_simdisk(structstruct simdisk *dev =PDE_DATA (file_inode (file));const char *s = dev->filename;if (s) { -ssize_t n =simple_read_from_buffer (buf, size, ppos, - s,strlen (s)); -if (n <0 ) -return n; - buf += n; - size -= n; +ssize_t len =strlen (s); +char *temp =kmalloc (len +2 ,GFP_KERNEL ); + +if (!temp) +return -ENOMEM ; + + len =scnprintf (temp, len +2 ,"%s\n" , s); + len =simple_read_from_buffer (buf, size, ppos, + temp, len); + +kfree (temp); +return len; }return simple_read_from_buffer (buf, size, ppos,"\n" ,1 ); }
Greg Kroah-Hartman
maintainerPATCH 406/452 rtl818x: Prevent using not initialized queues
In reply to Greg Kroah-HartmanFrom: Alexander Wetzel <[email protected]>
commit 746285cf81dc19502ab238249d75f5990bd2d231 upstream.
Using not existing queues can panic the kernel with rtl8180/rtl8185 cards. Ignore the skb priority for those cards, they only have one tx queue. Pierre Asselin ([email protected]) reported the kernel crash in the Gentoo forum:
https://forums.gentoo.org/viewtopic-t-1147832-postdays-0-postorder-asc-start-25.html
He also confirmed that this patch fixes the issue. In summary this happened:
After updating wpa_supplicant from 2.9 to 2.10 the kernel crashed with a "divide error: 0000" when connecting to an AP. Control port tx now tries to use IEEE80211_AC_VO for the priority, which wpa_supplicants starts to use in 2.10.
Since only the rtl8187se part of the driver supports QoS, the priority of the skb is set to IEEE80211_AC_BE (2) by mac80211 for rtl8180/rtl8185 cards.
rtl8180 is then unconditionally reading out the priority and finally crashes on drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c line 544 without this patch:
idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries
"ring->entries" is zero for rtl8180/rtl8185 cards, tx_ring[2] never got initialized.
--- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +6 -2
@@ -460,8 +460,10 @@ static void rtl8180_tx(struct ieee80211_struct rtl8180_priv *priv = dev->priv;struct rtl8180_tx_ring *ring;struct rtl8180_tx_desc *entry; +unsigned int prio =0 ;unsigned long flags; -unsigned int idx, prio, hw_prio; +unsigned int idx, hw_prio; +dma_addr_t mapping;u32 tx_flags;u8 rc_flags;
@@ -470,7 +472,9 @@ static void rtl8180_tx(struct ieee80211_/* do arithmetic and then convert to le16 */ u16 frame_duration =0 ; - prio =skb_get_queue_mapping (skb); +/* rtl8180/rtl8185 only has one useable tx queue */ +if (dev->queues >IEEE80211_AC_BK ) + prio =skb_get_queue_mapping (skb); ring = &priv->tx_ring[prio]; mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len,
Greg Kroah-Hartman
maintainerPATCH 407/452 ASoC: rt5514: Fix event generation for "DSP Voice Wake Up" control
In reply to Greg Kroah-HartmanFrom: Mark Brown <[email protected]>
commit 4213ff556740bb45e2d9ff0f50d056c4e7dd0921 upstream.
The driver has a custom put function for "DSP Voice Wake Up" which does not generate event notifications on change, instead returning 0. Since we already exit early in the case that there is no change this can be fixed by unconditionally returning 1 at the end of the function.
--- sound/soc/codecs/rt5514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/rt5514.c +1 -1
@@ -419,7 +419,7 @@ static int rt5514_dsp_voice_wake_up_put( } } -return 0 ; +return 1 ; }static const struct snd_kcontrol_new rt5514_snd_controls[] = {
Greg Kroah-Hartman
maintainerPATCH 408/452 carl9170: tx: fix an incorrect use of list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 54a6f29522da3c914da30e50721dedf51046449a upstream.
If the previous list_for_each_entry_continue_rcu() don't exit early (no goto hit inside the loop), the iterator 'cvif' after the loop will be a bogus pointer to an invalid structure object containing the HEAD (&ar->vif_list). As a result, the use of 'cvif' after that will lead to a invalid memory access (i.e., 'cvif->id': the invalid pointer dereference when return back to/after the callsite in the carl9170_update_beacon()).
The original intention should have been to return the valid 'cvif' when found in list, NULL otherwise. So just return NULL when no entry found, to fix this bug.
--- drivers/net/wireless/ath/carl9170/tx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/carl9170/tx.c +3 -0
@@ -1557,6 +1557,9 @@ static struct carl9170_vif_info *carl917 goto out; } }while (ar->beacon_enabled && i--); + +/* no entry found in list */ +return NULL ; } out:
Greg Kroah-Hartman
maintainerPATCH 409/452 stm: ltdc: fix two incorrect NULL checks on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 2e6c86be0e57079d1fb6c7c7e5423db096d0548a upstream.
The two bugs are here:
if (encoder) {
if (bridge && bridge->timings)The list iterator value 'encoder/bridge' will *always* be set and non-NULL by drm_for_each_encoder()/list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, use a new variable '*_iter' as the list iterator, while use the old variable 'encoder/bridge' as a dedicated pointer to point to the found element.
--- drivers/gpu/drm/stm/ltdc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/gpu/drm/stm/ltdc.c +10 -6
@@ -527,8 +527,8 @@ static void ltdc_crtc_mode_set_nofb(strustruct drm_device *ddev = crtc->dev;struct drm_connector_list_iter iter;struct drm_connector *connector =NULL ; -struct drm_encoder *encoder =NULL ; -struct drm_bridge *bridge =NULL ; +struct drm_encoder *encoder =NULL , *en_iter; +struct drm_bridge *bridge =NULL , *br_iter;struct drm_display_mode *mode = &crtc->state->adjusted_mode;struct videomode vm;u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h;
@@ -538,15 +538,19 @@ static void ltdc_crtc_mode_set_nofb(struint ret;/* get encoder from crtc */ -drm_for_each_encoder (encoder, ddev) -if (encoder->crtc == crtc) +drm_for_each_encoder (en_iter, ddev) +if (en_iter->crtc == crtc) { + encoder = en_iter;break ; + }if (encoder) {/* get bridge from encoder */ -list_for_each_entry (bridge, &encoder->bridge_chain, chain_node) -if (bridge->encoder == encoder) +list_for_each_entry (br_iter, &encoder->bridge_chain, chain_node) +if (br_iter->encoder == encoder) { + bridge = br_iter;break ; + }/* Get the connector from encoder */ drm_connector_list_iter_begin (ddev, &iter);
Greg Kroah-Hartman
maintainerPATCH 410/452 bcache: improve multithreaded bch_btree_check()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 622536443b6731ec82c563aae7807165adbe9178 upstream.
Commit 8e7102273f59 ("bcache: make bch_btree_check() to be multithreaded") makes bch_btree_check() to be much faster when checking all btree nodes during cache device registration. But it isn't in ideal shap yet, still can be improved.
This patch does the following thing to improve current parallel btree nodes check by multiple threads in bch_btree_check(),
- Add read lock to root node while checking all the btree nodes with multiple threads. Although currently it is not mandatory but it is good to have a read lock in code logic.
- Remove local variable 'char name[32]', and generate kernel thread name string directly when calling kthread_run().
- Allocate local variable "struct btree_check_state check_state" on the stack and avoid unnecessary dynamic memory allocation for it.
- Reduce BCH_BTR_CHKTHREAD_MAX from 64 to 12 which is enough indeed.
- Increase check_state->started to count created kernel thread after it succeeds to create.
- When wait for all checking kernel threads to finish, use wait_event() to replace wait_event_interruptible().
With this change, the code is more clear, and some potential error conditions are avoided.
--- drivers/md/bcache/btree.c | 58 ++++++++++++++++++++-------------------------- drivers/md/bcache/btree.h | 2 - 2 files changed, 27 insertions(+), 33 deletions(-)
drivers/md/bcache/btree.c +26 -32
@@ -2006,8 +2006,7 @@ int bch_btree_check(struct cache_set *c)int i;struct bkey *k =NULL ;struct btree_iter iter; -struct btree_check_state *check_state; -char name[32 ]; +struct btree_check_state check_state;/* check and mark root node keys */ for_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)
@@ -2018,63 +2017,58 @@ int bch_btree_check(struct cache_set *c)if (c->root->level ==0 )return 0 ; - check_state =kzalloc (sizeof (struct btree_check_state ),GFP_KERNEL ); -if (!check_state) -return -ENOMEM ; - - check_state->c = c; - check_state->total_threads =bch_btree_chkthread_nr (); - check_state->key_idx =0 ; -spin_lock_init (&check_state->idx_lock); -atomic_set (&check_state->started,0 ); -atomic_set (&check_state->enough,0 ); -init_waitqueue_head (&check_state->wait); + check_state.c = c; + check_state.total_threads =bch_btree_chkthread_nr (); + check_state.key_idx =0 ; +spin_lock_init (&check_state.idx_lock); +atomic_set (&check_state.started,0 ); +atomic_set (&check_state.enough,0 ); +init_waitqueue_head (&check_state.wait); +rw_lock (0 , c->root, c->root->level);/* * Run multiple threads to check btree nodes in parallel, -* if check_state->enough is non-zero, it means current +* if check_state.enough is non-zero, it means current * running check threads are enough, unncessary to create * more. */ -for (i =0 ; i < check_state->total_threads; i++) { -/* fetch latest check_state->enough earlier */ +for (i =0 ; i < check_state.total_threads; i++) { +/* fetch latest check_state.enough earlier */ smp_mb__before_atomic (); -if (atomic_read (&check_state->enough)) +if (atomic_read (&check_state.enough))break ; - check_state->infos[i].result =0 ; - check_state->infos[i].state = check_state; -snprintf (name,sizeof (name),"bch_btrchk[%u]" , i); -atomic_inc (&check_state->started); + check_state.infos[i].result =0 ; + check_state.infos[i].state = &check_state; - check_state->infos[i].thread = + check_state.infos[i].thread =kthread_run (bch_btree_check_thread, - &check_state->infos[i], - name); -if (IS_ERR (check_state->infos[i].thread)) { + &check_state.infos[i], +"bch_btrchk[%d]" , i); +if (IS_ERR (check_state.infos[i].thread)) {pr_err ("fails to run thread bch_btrchk[%d]\n" , i);for (--i; i >=0 ; i--) -kthread_stop (check_state->infos[i].thread); +kthread_stop (check_state.infos[i].thread); ret = -ENOMEM ; goto out; } +atomic_inc (&check_state.started); }/* * Must wait for all threads to stop. */ -wait_event_interruptible (check_state->wait, -atomic_read (&check_state->started) ==0 ); +wait_event (check_state.wait,atomic_read (&check_state.started) ==0 ); -for (i =0 ; i < check_state->total_threads; i++) { -if (check_state->infos[i].result) { - ret = check_state->infos[i].result; +for (i =0 ; i < check_state.total_threads; i++) { +if (check_state.infos[i].result) { + ret = check_state.infos[i].result; goto out; } } out: -kfree (check_state); +rw_unlock (0 , c->root);return ret; }
drivers/md/bcache/btree.h +1 -1
@@ -226,7 +226,7 @@ struct btree_check_info {int result; }; -#define BCH_BTR_CHKTHREAD_MAX 64 +#define BCH_BTR_CHKTHREAD_MAX 12struct btree_check_state {struct cache_set *c;int total_threads;
Greg Kroah-Hartman
maintainerPATCH 411/452 bcache: improve multithreaded bch_sectors_dirty_init()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 4dc34ae1b45fe26e772a44379f936c72623dd407 upstream.
Commit b144e45fc576 ("bcache: make bch_sectors_dirty_init() to be multithreaded") makes bch_sectors_dirty_init() to be much faster when counting dirty sectors by iterating all dirty keys in the btree. But it isn't in ideal shape yet, still can be improved.
This patch does the following changes to improve current parallel dirty keys iteration on the btree,
- Add read lock to root node when multiple threads iterating the btree, to prevent the root node gets split by I/Os from other registered bcache devices.
- Remove local variable "char name[32]" and generate kernel thread name string directly when calling kthread_run().
- Allocate "struct bch_dirty_init_state state" directly on stack and avoid the unnecessary dynamic memory allocation for it.
- Decrease BCH_DIRTY_INIT_THRD_MAX from 64 to 12 which is enough indeed.
- Increase &state->started to count created kernel thread after it succeeds to create.
- When wait for all dirty key counting threads to finish, use wait_event() to replace wait_event_interruptible().
With the above changes, the code is more clear, and some potential error conditions are avoided.
--- drivers/md/bcache/writeback.c | 60 ++++++++++++++++-------------------------- drivers/md/bcache/writeback.h | 2 - 2 files changed, 25 insertions(+), 37 deletions(-)
drivers/md/bcache/writeback.c +24 -36
@@ -899,10 +899,10 @@ void bch_sectors_dirty_init(struct bcachstruct btree_iter iter;struct sectors_dirty_init op;struct cache_set *c = d->c; -struct bch_dirty_init_state *state; -char name[32 ]; +struct bch_dirty_init_state state;/* Just count root keys if no leaf node */ +rw_lock (0 , c->root, c->root->level);if (c->root->level ==0 ) {bch_btree_op_init (&op.op,-1 ); op.inode = d->id;
@@ -912,54 +912,42 @@ void bch_sectors_dirty_init(struct bcachfor_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)sectors_dirty_init_fn (&op.op, c->root, k); +rw_unlock (0 , c->root);return ; } - state =kzalloc (sizeof (struct bch_dirty_init_state ),GFP_KERNEL ); -if (!state) { -pr_warn ("sectors dirty init failed: cannot allocate memory\n" ); -return ; - } + state.c = c; + state.d = d; + state.total_threads =bch_btre_dirty_init_thread_nr (); + state.key_idx =0 ; +spin_lock_init (&state.idx_lock); +atomic_set (&state.started,0 ); +atomic_set (&state.enough,0 ); +init_waitqueue_head (&state.wait); - state->c = c; - state->d = d; - state->total_threads =bch_btre_dirty_init_thread_nr (); - state->key_idx =0 ; -spin_lock_init (&state->idx_lock); -atomic_set (&state->started,0 ); -atomic_set (&state->enough,0 ); -init_waitqueue_head (&state->wait); - -for (i =0 ; i < state->total_threads; i++) { -/* Fetch latest state->enough earlier */ +for (i =0 ; i < state.total_threads; i++) { +/* Fetch latest state.enough earlier */ smp_mb__before_atomic (); -if (atomic_read (&state->enough)) +if (atomic_read (&state.enough))break ; - state->infos[i].state = state; -atomic_inc (&state->started); -snprintf (name,sizeof (name),"bch_dirty_init[%d]" , i); - - state->infos[i].thread = -kthread_run (bch_dirty_init_thread, - &state->infos[i], - name); -if (IS_ERR (state->infos[i].thread)) { + state.infos[i].state = &state; + state.infos[i].thread = +kthread_run (bch_dirty_init_thread, &state.infos[i], +"bch_dirtcnt[%d]" , i); +if (IS_ERR (state.infos[i].thread)) {pr_err ("fails to run thread bch_dirty_init[%d]\n" , i);for (--i; i >=0 ; i--) -kthread_stop (state->infos[i].thread); +kthread_stop (state.infos[i].thread); goto out; } +atomic_inc (&state.started); } -/* -* Must wait for all threads to stop. -*/ -wait_event_interruptible (state->wait, -atomic_read (&state->started) ==0 ); - out: -kfree (state); +/* Must wait for all threads to stop. */ +wait_event (state.wait,atomic_read (&state.started) ==0 ); +rw_unlock (0 , c->root); }void bch_cached_dev_writeback_init (struct cached_dev *dc)
drivers/md/bcache/writeback.h +1 -1
@@ -16,7 +16,7 @@#define BCH_AUTO_GC_DIRTY_THRESHOLD 50 -#define BCH_DIRTY_INIT_THRD_MAX 64 +#define BCH_DIRTY_INIT_THRD_MAX 12/* * 14 (16384ths) is chosen here as something that each backing device * should be a reasonable fraction of the share, and not to blow up
Greg Kroah-Hartman
maintainerPATCH 412/452 bcache: remove incremental dirty sector counting for bch_sectors_dirty_init()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 80db4e4707e78cb22287da7d058d7274bd4cb370 upstream.
After making bch_sectors_dirty_init() being multithreaded, the existing incremental dirty sector counting in bch_root_node_dirty_init() doesn't release btree occupation after iterating 500000 (INIT_KEYS_EACH_TIME) bkeys. Because a read lock is added on btree root node to prevent the btree to be split during the dirty sectors counting, other I/O requester has no chance to gain the write lock even restart bcache_btree().
That is to say, the incremental dirty sectors counting is incompatible to the multhreaded bch_sectors_dirty_init(). We have to choose one and drop another one.
In my testing, with 512 bytes random writes, I generate 1.2T dirty data and a btree with 400K nodes. With single thread and incremental dirty sectors counting, it takes 30+ minites to register the backing device. And with multithreaded dirty sectors counting, the backing device registration can be accomplished within 2 minutes.
The 30+ minutes V.S. 2- minutes difference makes me decide to keep multithreaded bch_sectors_dirty_init() and drop the incremental dirty sectors counting. This is what this patch does.
But INIT_KEYS_EACH_TIME is kept, in sectors_dirty_init_fn() the CPU will be released by cond_resched() after every INIT_KEYS_EACH_TIME keys iterated. This is to avoid the watchdog reports a bogus soft lockup warning.
--- drivers/md/bcache/writeback.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-)
drivers/md/bcache/writeback.c +12 -27
@@ -756,13 +756,11 @@ static int bch_writeback_thread(void *ar/* Init */ #define INIT_KEYS_EACH_TIME 500000 -#define INIT_KEYS_SLEEP_MS 100struct sectors_dirty_init {struct btree_op op;unsigned int inode;size_t count; -struct bkey start; }; static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b,
@@ -778,11 +776,8 @@ static int sectors_dirty_init_fn(struct KEY_START(k), KEY_SIZE(k)); op->count++; -if (atomic_read (&b->c->search_inflight) && - !(op->count %INIT_KEYS_EACH_TIME )) { -bkey_copy_key (&op->start, k); -return -EAGAIN ; - } +if (!(op->count %INIT_KEYS_EACH_TIME )) +cond_resched ();return MAP_CONTINUE ; }
@@ -797,24 +792,16 @@ static int bch_root_node_dirty_init(strubch_btree_op_init (&op.op,-1 ); op.inode = d->id; op.count =0 ; - op.start =KEY (op.inode,0 ,0 ); -do { - ret =bcache_btree (map_keys_recurse, - k, - c->root, - &op.op, - &op.start, - sectors_dirty_init_fn, -0 ); -if (ret == -EAGAIN ) -schedule_timeout_interruptible ( -msecs_to_jiffies (INIT_KEYS_SLEEP_MS )); -else if (ret <0 ) { -pr_warn ("sectors dirty init failed, ret=%d!\n" , ret); -break ; - } - }while (ret == -EAGAIN ); + ret =bcache_btree (map_keys_recurse, + k, + c->root, + &op.op, + &KEY (op.inode,0 ,0 ), + sectors_dirty_init_fn, +0 ); +if (ret <0 ) +pr_warn ("sectors dirty init failed, ret=%d!\n" , ret);return ret; }
@@ -858,7 +845,6 @@ static int bch_dirty_init_thread(void *a goto out; } skip_nr--; -cond_resched (); }if (p) {
@@ -868,7 +854,6 @@ static int bch_dirty_init_thread(void *a p =NULL ; prev_idx = cur_idx; -cond_resched (); } out:
@@ -907,11 +892,11 @@ void bch_sectors_dirty_init(struct bcachbch_btree_op_init (&op.op,-1 ); op.inode = d->id; op.count =0 ; - op.start =KEY (op.inode,0 ,0 );for_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)sectors_dirty_init_fn (&op.op, c->root, k); +rw_unlock (0 , c->root);return ; }
Greg Kroah-Hartman
maintainerPATCH 413/452 bcache: avoid journal no-space deadlock by reserving 1 journal bucket
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 32feee36c30ea06e38ccb8ae6e5c44c6eec790a6 upstream.
The journal no-space deadlock was reported time to time. Such deadlock can happen in the following situation.
When all journal buckets are fully filled by active jset with heavy write I/O load, the cache set registration (after a reboot) will load all active jsets and inserting them into the btree again (which is called journal replay). If a journaled bkey is inserted into a btree node and results btree node split, new journal request might be triggered. For example, the btree grows one more level after the node split, then the root node record in cache device super block will be upgrade by bch_journal_meta() from bch_btree_set_root(). But there is no space in journal buckets, the journal replay has to wait for new journal bucket to be reclaimed after at least one journal bucket replayed. This is one example that how the journal no-space deadlock happens.
The solution to avoid the deadlock is to reserve 1 journal bucket in run time, and only permit the reserved journal bucket to be used during cache set registration procedure for things like journal replay. Then the journal space will never be fully filled, there is no chance for journal no-space deadlock to happen anymore.
This patch adds a new member "bool do_reserve" in struct journal, it is inititalized to 0 (false) when struct journal is allocated, and set to 1 (true) by bch_journal_space_reserve() when all initialization done in run_cache_set(). In the run time when journal_reclaim() tries to allocate a new journal bucket, free_journal_buckets() is called to check whether there are enough free journal buckets to use. If there is only 1 free journal bucket and journal->do_reserve is 1 (true), the last bucket is reserved and free_journal_buckets() will return 0 to indicate no free journal bucket. Then journal_reclaim() will give up, and try next time to see whetheer there is free journal bucket to allocate. By this method, there is always 1 jouranl bucket reserved in run time.
During the cache set registration, journal->do_reserve is 0 (false), so the reserved journal bucket can be used to avoid the no-space deadlock.
--- drivers/md/bcache/journal.c | 31 ++++++++++++++++++++++++++----- drivers/md/bcache/journal.h | 2 ++ drivers/md/bcache/super.c | 1 + 3 files changed, 29 insertions(+), 5 deletions(-)
drivers/md/bcache/journal.c +26 -5
@@ -407,6 +407,11 @@ err:return ret; } +void bch_journal_space_reserve (struct journal *j) +{ + j->do_reserve = true; +} +/* Journalling */ static void btree_flush_write (struct cache_set *c)
@@ -625,12 +630,30 @@ static void do_journal_discard(struct ca } } +static unsigned int free_journal_buckets (struct cache_set *c) +{ +struct journal *j = &c->journal; +struct cache *ca = c->cache; +struct journal_device *ja = &c->cache->journal; +unsigned int n; + +/* In case njournal_buckets is not power of 2 */ +if (ja->cur_idx >= ja->discard_idx) + n = ca->sb.njournal_buckets + ja->discard_idx - ja->cur_idx; +else + n = ja->discard_idx - ja->cur_idx; + +if (n > (1 + j->do_reserve)) +return n - (1 + j->do_reserve); + +return 0 ; +} +static void journal_reclaim (struct cache_set *c) {struct bkey *k = &c->journal.key;struct cache *ca = c->cache;uint64_t last_seq; -unsigned int next;struct journal_device *ja = &ca->journal;atomic_t p__maybe_unused ;
@@ -653,12 +676,10 @@ static void journal_reclaim(struct cacheif (c->journal.blocks_free) goto out; - next = (ja->cur_idx +1 ) % ca->sb.njournal_buckets; -/* No space available on this device */ -if (next == ja->discard_idx) +if (!free_journal_buckets (c)) goto out; - ja->cur_idx = next; + ja->cur_idx = (ja->cur_idx +1 ) % ca->sb.njournal_buckets; k->ptr[0 ] =MAKE_PTR (0 ,bucket_to_sector (c, ca->sb.d[ja->cur_idx]), ca->sb.nr_this_dev);
drivers/md/bcache/journal.h +2 -0
@@ -105,6 +105,7 @@ struct journal {spinlock_t lock;spinlock_t flush_write_lock;bool btree_flushing; +bool do_reserve;/* used when waiting because the journal was full */ struct closure_waitlist wait;struct closure io;
@@ -182,5 +183,6 @@ int bch_journal_replay(struct cache_setvoid bch_journal_free (struct cache_set *c);int bch_journal_alloc (struct cache_set *c); +void bch_journal_space_reserve (struct journal *j);#endif /* _BCACHE_JOURNAL_H */
drivers/md/bcache/super.c +1 -0
@@ -2150,6 +2150,7 @@ static int run_cache_set(struct cache_seflash_devs_run (c); +bch_journal_space_reserve (&c->journal);set_bit (CACHE_SET_RUNNING , &c->flags);return 0 ; err:
Greg Kroah-Hartman
maintainerPATCH 414/452 serial: pch: dont overwrite xmit->buf[0] by x_char
In reply to Greg Kroah-HartmanFrom: Jiri Slaby <[email protected]>
commit d9f3af4fbb1d955bbaf872d9e76502f6e3e803cb upstream.
When x_char is to be sent, the TX path overwrites whatever is in the circular buffer at offset 0 with x_char and sends it using pch_uart_hal_write(). I don't understand how this was supposed to work if xmit->buf[0] already contained some character. It must have been lost.
Remove this whole pop_tx_x() concept and do the work directly in the callers. (Without printing anything using dev_dbg().)
--- drivers/tty/serial/pch_uart.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-)
drivers/tty/serial/pch_uart.c +7 -20
@@ -628,22 +628,6 @@ static int push_rx(struct eg20t_port *prreturn 0 ; } -static int pop_tx_x (struct eg20t_port *priv,unsigned char *buf) -{ -int ret =0 ; -struct uart_port *port = &priv->port; - -if (port->x_char) { -dev_dbg (priv->port.dev,"%s:X character send %02x (%lu)\n" , - __func__, port->x_char, jiffies); - buf[0 ] = port->x_char; - port->x_char =0 ; - ret =1 ; - } - -return ret; -} -static int dma_push_rx (struct eg20t_port *priv,int size) {int room;
@@ -893,9 +877,10 @@ static unsigned int handle_tx(struct eg2 fifo_size =max (priv->fifo_size,1 ); tx_empty =1 ; -if (pop_tx_x (priv, xmit->buf)) { -pch_uart_hal_write (priv, xmit->buf,1 ); +if (port->x_char) { +pch_uart_hal_write (priv, &port->x_char,1 ); port->icount.tx++; + port->x_char =0 ; tx_empty =0 ; fifo_size--; }
@@ -950,9 +935,11 @@ static unsigned int dma_handle_tx(struct } fifo_size =max (priv->fifo_size,1 ); -if (pop_tx_x (priv, xmit->buf)) { -pch_uart_hal_write (priv, xmit->buf,1 ); + +if (port->x_char) { +pch_uart_hal_write (priv, &port->x_char,1 ); port->icount.tx++; + port->x_char =0 ; fifo_size--; }
Greg Kroah-Hartman
maintainerPATCH 415/452 tilcdc: tilcdc_external: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 8b917cbe38e9b0d002492477a9fc2bfee2412ce4 upstream.
The bug is here:
if (!encoder) {The list iterator value 'encoder' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, use a new variable 'iter' as the list iterator, while use the original variable 'encoder' as a dedicated pointer to point to the found element.
--- drivers/gpu/drm/tilcdc/tilcdc_external.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/gpu/drm/tilcdc/tilcdc_external.c +5 -3
@@ -60,11 +60,13 @@ struct drm_connector *tilcdc_encoder_finint tilcdc_add_component_encoder (struct drm_device *ddev) {struct tilcdc_drm_private *priv = ddev->dev_private; -struct drm_encoder *encoder; +struct drm_encoder *encoder =NULL , *iter; -list_for_each_entry (encoder, &ddev->mode_config.encoder_list, head) -if (encoder->possible_crtcs & (1 << priv->crtc->index)) +list_for_each_entry (iter, &ddev->mode_config.encoder_list, head) +if (iter->possible_crtcs & (1 << priv->crtc->index)) { + encoder = iter;break ; + }if (!encoder) {dev_err (ddev->dev,"%s: No suitable encoder found\n" , __func__);
Greg Kroah-Hartman
maintainerPATCH 416/452 gma500: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit bdef417d84536715145f6dc9cc3275c46f26295a upstream.
The bug is here:
return crtc;
The list iterator value 'crtc' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, return 'crtc' when found, otherwise return NULL.
--- drivers/gpu/drm/gma500/psb_intel_display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/gma500/psb_intel_display.c +4 -3
@@ -536,14 +536,15 @@ void psb_intel_crtc_init(struct drm_devistruct drm_crtc *psb_intel_get_crtc_from_pipe (struct drm_device *dev,int pipe) { -struct drm_crtc *crtc =NULL ; +struct drm_crtc *crtc;list_for_each_entry (crtc, &dev->mode_config.crtc_list, head) {struct gma_crtc *gma_crtc =to_gma_crtc (crtc); +if (gma_crtc->pipe == pipe) -break ; +return crtc; } -return crtc; +return NULL ; }int gma_connector_clones (struct drm_device *dev,int type_mask)
Greg Kroah-Hartman
maintainerPATCH 417/452 arm64: dts: qcom: ipq8074: fix the sleep clock frequency
In reply to Greg Kroah-HartmanFrom: Kathiravan T <[email protected]>
commit f607dd767f5d6800ffbdce5b99ba81763b023781 upstream.
Sleep clock frequency should be 32768Hz. Lets fix it.
--- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/ipq8074.dtsi +1 -1
@@ -13,7 +13,7 @@ clocks { sleep_clk: sleep_clk { compatible = "fixed-clock"; - clock-frequency = <32000>; + clock-frequency = <32768>; #clock-cells = <0>; };
Greg Kroah-Hartman
maintainerPATCH 418/452 phy: qcom-qmp: fix struct clk leak on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit f0a4bc38a12f5a0cc5ad68670d9480e91e6a94df upstream.
Make sure to release the pipe clock reference in case of a late probe error (e.g. probe deferral).
--- drivers/phy/qualcomm/phy-qcom-qmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-qmp.c +1 -1
@@ -3789,7 +3789,7 @@ int qcom_qmp_phy_create(struct device *d* all phys that don't need this. */ snprintf (prop_name,sizeof (prop_name),"pipe%d" , id); - qphy->pipe_clk =of_clk_get_by_name (np, prop_name); + qphy->pipe_clk =devm_get_clk_from_child (dev, np, prop_name);if (IS_ERR (qphy->pipe_clk)) {if (cfg->type ==PHY_TYPE_PCIE || cfg->type ==PHY_TYPE_USB3 ) {
Greg Kroah-Hartman
maintainerPATCH 419/452 ARM: dts: s5pv210: Remove spi-cs-high on panel in Aries
In reply to Greg Kroah-HartmanFrom: Jonathan Bakker <[email protected]>
commit 096f58507374e1293a9e9cff8a1ccd5f37780a20 upstream.
Since commit 766c6b63aa04 ("spi: fix client driver breakages when using GPIO descriptors"), the panel has been blank due to an inverted CS GPIO. In order to correct this, drop the spi-cs-high from the panel SPI device.
--- arch/arm/boot/dts/s5pv210-aries.dtsi | 1 - 1 file changed, 1 deletion(-)
arch/arm/boot/dts/s5pv210-aries.dtsi +0 -1
@@ -564,7 +564,6 @@ panel@0 { reset-gpios = <&mp05 5 GPIO_ACTIVE_LOW>; vdd3-supply = <&ldo7_reg>; vci-supply = <&ldo17_reg>; - spi-cs-high; spi-max-frequency = <1200000>; pinctrl-names = "default";
Signature · 1 line
2.36.1
Greg Kroah-Hartman
maintainerPATCH 420/452 ARM: pxa: maybe fix gpio lookup tables
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
commit 2672a4bff6c03a20d5ae460a091f67ee782c3eff upstream.
Quoted 1 line
From inspection I found a couple of GPIO lookups that are
listed with device "gpio-pxa", but actually have a number from a different gpio controller.
Try to rectify that here, with a guess of what the actual device name is.
--- arch/arm/mach-pxa/cm-x300.c | 8 ++++---- arch/arm/mach-pxa/magician.c | 2 +- arch/arm/mach-pxa/tosa.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/arm/mach-pxa/cm-x300.c +4 -4
@@ -354,13 +354,13 @@ static struct platform_device cm_x300_spstatic struct gpiod_lookup_table cm_x300_spi_gpiod_table = { .dev_id ="spi_gpio" , .table = { -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_SCL , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_SCL -GPIO_LCD_BASE ,"sck" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_DIN , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_DIN -GPIO_LCD_BASE ,"mosi" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_DOUT , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_DOUT -GPIO_LCD_BASE ,"miso" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_CS , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_CS -GPIO_LCD_BASE ,"cs" ,GPIO_ACTIVE_HIGH ), { }, },
arch/arm/mach-pxa/magician.c +1 -1
@@ -681,7 +681,7 @@ static struct platform_device bq24022 =static struct gpiod_lookup_table bq24022_gpiod_table = { .dev_id ="gpio-regulator" , .table = { -GPIO_LOOKUP ("gpio-pxa" ,EGPIO_MAGICIAN_BQ24022_ISET2 , +GPIO_LOOKUP ("htc-egpio-0" ,EGPIO_MAGICIAN_BQ24022_ISET2 -MAGICIAN_EGPIO_BASE ,NULL ,GPIO_ACTIVE_HIGH ),GPIO_LOOKUP ("gpio-pxa" , GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,"enable" ,GPIO_ACTIVE_LOW ),
arch/arm/mach-pxa/tosa.c +2 -2
@@ -296,9 +296,9 @@ static struct gpiod_lookup_table tosa_mc .table = {GPIO_LOOKUP ("gpio-pxa" , TOSA_GPIO_nSD_DETECT,"cd" ,GPIO_ACTIVE_LOW ), -GPIO_LOOKUP ("gpio-pxa" ,TOSA_GPIO_SD_WP , +GPIO_LOOKUP ("sharp-scoop.0" ,TOSA_GPIO_SD_WP -TOSA_SCOOP_GPIO_BASE ,"wp" ,GPIO_ACTIVE_LOW ), -GPIO_LOOKUP ("gpio-pxa" ,TOSA_GPIO_PWR_ON , +GPIO_LOOKUP ("sharp-scoop.0" ,TOSA_GPIO_PWR_ON -TOSA_SCOOP_GPIO_BASE , "power", GPIO_ACTIVE_HIGH), { }, },
Greg Kroah-Hartman
maintainerPATCH 421/452 SMB3: EBADF/EIO errors in rename/open caused by race condition in smb2_compound_op
In reply to Greg Kroah-HartmanFrom: Steve French <[email protected]>
commit 0a55cf74ffb5d004b93647e4389096880ce37d6b upstream.
There is a race condition in smb2_compound_op:
after_close:
num_rqst++;
if (cfile) {
cifsFileInfo_put(cfile); // sends SMB2_CLOSE to the server
cfile = NULL;This is triggered by smb2_query_path_info operation that happens during revalidate_dentry. In smb2_query_path_info, get_readable_path is called to load the cfile, increasing the reference counter. If in the meantime, this reference becomes the very last, this call to cifsFileInfo_put(cfile) will trigger a SMB2_CLOSE request sent to the server just before sending this compound request – and so then the compound request fails either with EBADF/EIO depending on the timing at the server, because the handle is already closed.
In the first scenario, the race seems to be happening between smb2_query_path_info triggered by the rename operation, and between “cleanup” of asynchronous writes – while fsync(fd) likely waits for the asynchronous writes to complete, releasing the writeback structures can happen after the close(fd) call. So the EBADF/EIO errors will pop up if the timing is such that:
1) There are still outstanding references after close(fd) in the writeback structures
2) smb2_query_path_info successfully fetches the cfile, increasing the refcounter by 1
3) All writeback structures release the same cfile, reducing refcounter to 1
4) smb2_compound_op is called with that cfile
In the second scenario, the race seems to be similar – here open triggers the smb2_query_path_info operation, and if all other threads in the meantime decrease the refcounter to 1 similarly to the first scenario, again SMB2_CLOSE will be sent to the server just before issuing the compound request. This case is harder to reproduce.
See https://bugzilla.samba.org/show_bug.cgi?id=15051
--- fs/cifs/smb2inode.c | 2 -- 1 file changed, 2 deletions(-)
fs/cifs/smb2inode.c +0 -2
@@ -371,8 +371,6 @@ smb2_compound_op(const unsigned int xid, num_rqst++;if (cfile) { -cifsFileInfo_put (cfile); - cfile =NULL ; rc = compound_send_recv(xid, ses, server, flags, num_rqst - 2, &rqst[1], &resp_buftype[1],
Greg Kroah-Hartman
maintainerPATCH 422/452 docs/conf.py: Cope with removal of language=None in Sphinx 5.0.0
In reply to Greg Kroah-HartmanFrom: Akira Yokosawa <[email protected]>
commit 627f01eab93d8671d4e4afee9b148f9998d20e7c upstream.
One of the changes in Sphinx 5.0.0 [1] says [sic]:
5.0.0 final
- #10474: language does not accept None as it value. The default value of language becomes to 'en' now.
[1]: https://www.sphinx-doc.org/en/master/changes.html#release-5-0-0-released-may-30-2022
It results in a new warning from Sphinx 5.0.0 [sic]:
WARNING: Invalid configuration value found: 'language = None'. Update your configuration to a valid langauge code. Falling back to 'en' (English).
Silence the warning by using 'en'.
It works with all the Sphinx versions required for building kernel documentation (1.7.9 or later).
--- Documentation/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/conf.py +1 -1
@@ -176,7 +176,7 @@ finally: # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used:
Greg Kroah-Hartman
maintainerPATCH 423/452 dt-bindings: gpio: altera: correct interrupt-cells
In reply to Greg Kroah-HartmanFrom: Dinh Nguyen <[email protected]>
commit 3a21c3ac93aff7b4522b152399df8f6a041df56d upstream.
update documentation to correctly state the interrupt-cells to be 2.
--- Documentation/devicetree/bindings/gpio/gpio-altera.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/gpio/gpio-altera.txt +3 -2
@@ -9,8 +9,9 @@ Required properties: - The second cell is reserved and is currently unused. - gpio-controller : Marks the device node as a GPIO controller. - interrupt-controller: Mark the device node as an interrupt controller -- #interrupt-cells : Should be 1. The interrupt type is fixed in the hardware. +- #interrupt-cells : Should be 2. The interrupt type is fixed in the hardware. - The first cell is the GPIO offset number within the GPIO controller. + - The second cell is the interrupt trigger type and level flags. - interrupts: Specify the interrupt. - altr,interrupt-type: Specifies the interrupt trigger type the GPIO hardware is synthesized. This field is required if the Altera GPIO controller
@@ -38,6 +39,6 @@ gpio_altr: gpio@ff200000 { altr,interrupt-type = <IRQ_TYPE_EDGE_RISING>; #gpio-cells = <2>; gpio-controller; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupt-controller; };
Greg Kroah-Hartman
maintainerPATCH 424/452 vdpasim: allow to enable a vq repeatedly
In reply to Greg Kroah-HartmanFrom: Eugenio Pérez <[email protected]>
commit 242436973831aa97e8ce19533c6c912ea8def31b upstream.
Code must be resilient to enable a queue many times.
At the moment the queue is resetting so it's definitely not the expected behavior.
v2: set vq->ready = 0 at disable.
Message-Id: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim.c +4 -1
@@ -473,11 +473,14 @@ static void vdpasim_set_vq_ready(struct {struct vdpasim *vdpasim =vdpa_to_sim (vdpa);struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; +bool old_ready;spin_lock (&vdpasim->lock); + old_ready = vq->ready; vq->ready = ready; -if (vq->ready) +if (vq->ready && !old_ready) {vdpasim_queue_ready (vdpasim, idx); + }spin_unlock (&vdpasim->lock); }
Greg Kroah-Hartman
maintainerPATCH 425/452 blk-iolatency: Fix inflight count imbalances and IO hangs on offline
In reply to Greg Kroah-HartmanFrom: Tejun Heo <[email protected]>
commit 8a177a36da6c54c98b8685d4f914cb3637d53c0d upstream.
iolatency needs to track the number of inflight IOs per cgroup. As this tracking can be expensive, it is disabled when no cgroup has iolatency configured for the device. To ensure that the inflight counters stay balanced, iolatency_set_limit() freezes the request_queue while manipulating the enabled counter, which ensures that no IO is in flight and thus all counters are zero.
Unfortunately, iolatency_set_limit() isn't the only place where the enabled counter is manipulated. iolatency_pd_offline() can also dec the counter and trigger disabling. As this disabling happens without freezing the q, this can easily happen while some IOs are in flight and thus leak the counts.
This can be easily demonstrated by turning on iolatency on an one empty cgroup while IOs are in flight in other cgroups and then removing the cgroup. Note that iolatency shouldn't have been enabled elsewhere in the system to ensure that removing the cgroup disables iolatency for the whole device.
The following keeps flipping on and off iolatency on sda:
echo +io > /sys/fs/cgroup/cgroup.subtree_control while true; do
mkdir -p /sys/fs/cgroup/test
echo '8:0 target=100000' > /sys/fs/cgroup/test/io.latency sleep 1
rmdir /sys/fs/cgroup/test
sleep 1
done
and there's concurrent fio generating direct rand reads:
fio --name test --filename=/dev/sda --direct=1 --rw=randread \
--runtime=600 --time_based --iodepth=256 --numjobs=4 --bs=4kwhile monitoring with the following drgn script:
while True:
for css in css_for_each_descendant_pre(prog['blkcg_root'].css.address_of_()):
for pos in hlist_for_each(container_of(css, 'struct blkcg', 'css').blkg_list):
blkg = container_of(pos, 'struct blkcg_gq', 'blkcg_node')
pd = blkg.pd[prog['blkcg_policy_iolatency'].plid]
if pd.value_() == 0:
continue
iolat = container_of(pd, 'struct iolatency_grp', 'pd') inflight = iolat.rq_wait.inflight.counter.value_()
if inflight:
print(f'inflight={inflight} {disk_name(blkg.q.disk).decode("utf-8")} '
f'{cgroup_path(css.cgroup).decode("utf-8")}')
time.sleep(1)
The monitoring output looks like the following:
inflight=1 sda /user.slice
inflight=1 sda /user.slice
...
inflight=14 sda /user.slice
inflight=13 sda /user.slice
inflight=17 sda /user.slice
inflight=15 sda /user.slice
inflight=18 sda /user.slice
inflight=17 sda /user.slice
inflight=20 sda /user.slice
inflight=19 sda /user.slice <- fio stopped, inflight stuck at 19 inflight=19 sda /user.slice
inflight=19 sda /user.slice
If a cgroup with stuck inflight ends up getting throttled, the throttled IOs will never get issued as there's no completion event to wake it up leading to an indefinite hang.
This patch fixes the bug by unifying enable handling into a work item which is automatically kicked off from iolatency_set_min_lat_nsec() which is called from both iolatency_set_limit() and iolatency_pd_offline() paths. Punting to a work item is necessary as iolatency_pd_offline() is called under spinlocks while freezing a request_queue requires a sleepable context.
This also simplifies the code reducing LOC sans the comments and avoids the unnecessary freezes which were happening whenever a cgroup's latency target is newly set or cleared.
--- block/blk-iolatency.c | 122 ++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 58 deletions(-)
block/blk-iolatency.c +64 -58
@@ -86,7 +86,17 @@ struct iolatency_grp;struct blk_iolatency {struct rq_qos rqos;struct timer_list timer; -atomic_t enabled; + +/* +* ->enabled is the master enable switch gating the throttling logic and +* inflight tracking. The number of cgroups which have iolat enabled is +* tracked in ->enable_cnt, and ->enable is flipped on/off accordingly +* from ->enable_work with the request_queue frozen. For details, See +* blkiolatency_enable_work_fn(). +*/ +bool enabled; +atomic_t enable_cnt; +struct work_struct enable_work; };static inline struct blk_iolatency *BLKIOLATENCY (struct rq_qos *rqos)
@@ -94,11 +104,6 @@ static inline struct blk_iolatency *BLKI return container_of(rqos, struct blk_iolatency, rqos); } -static inline bool blk_iolatency_enabled (struct blk_iolatency *blkiolat) -{ -return atomic_read (&blkiolat->enabled) >0 ; -} -struct child_latency_info {spinlock_t lock;
@@ -463,7 +468,7 @@ static void blkcg_iolatency_throttle(strstruct blkcg_gq *blkg = bio->bi_blkg;bool issue_as_root =bio_issue_as_root_blkg (bio); -if (!blk_iolatency_enabled (blkiolat)) +if (!blkiolat->enabled)return ;while (blkg && blkg->parent) {
@@ -593,7 +598,6 @@ static void blkcg_iolatency_done_bio(stru64 window_start;u64 now;bool issue_as_root =bio_issue_as_root_blkg (bio); -bool enabled = false;int inflight =0 ; blkg = bio->bi_blkg;
@@ -604,8 +608,7 @@ static void blkcg_iolatency_done_bio(strif (!iolat)return ; - enabled =blk_iolatency_enabled (iolat->blkiolat); -if (!enabled) +if (!iolat->blkiolat->enabled)return ; now =ktime_to_ns (ktime_get ());
@@ -644,6 +647,7 @@ static void blkcg_iolatency_exit(structstruct blk_iolatency *blkiolat =BLKIOLATENCY (rqos);del_timer_sync (&blkiolat->timer); +flush_work (&blkiolat->enable_work);blkcg_deactivate_policy (rqos->q, &blkcg_policy_iolatency);kfree (blkiolat); }
@@ -715,6 +719,44 @@ next:rcu_read_unlock (); } +/** +* blkiolatency_enable_work_fn - Enable or disable iolatency on the device +* @work: enable_work of the blk_iolatency of interest +* +* iolatency needs to keep track of the number of in-flight IOs per cgroup. This +* is relatively expensive as it involves walking up the hierarchy twice for +* every IO. Thus, if iolatency is not enabled in any cgroup for the device, we +* want to disable the in-flight tracking. +* +* We have to make sure that the counting is balanced - we don't want to leak +* the in-flight counts by disabling accounting in the completion path while IOs +* are in flight. This is achieved by ensuring that no IO is in flight by +* freezing the queue while flipping ->enabled. As this requires a sleepable +* context, ->enabled flipping is punted to this work function. +*/ +static void blkiolatency_enable_work_fn (struct work_struct *work) +{ + struct blk_iolatency *blkiolat = container_of(work, struct blk_iolatency, + enable_work); +bool enabled; + +/* +* There can only be one instance of this function running for @blkiolat +* and it's guaranteed to be executed at least once after the latest +* ->enabled_cnt modification. Acting on the latest ->enable_cnt is +* sufficient. +* +* Also, we know @blkiolat is safe to access as ->enable_work is flushed +* in blkcg_iolatency_exit(). +*/ + enabled =atomic_read (&blkiolat->enable_cnt); +if (enabled != blkiolat->enabled) { +blk_mq_freeze_queue (blkiolat->rqos.q); + blkiolat->enabled = enabled; +blk_mq_unfreeze_queue (blkiolat->rqos.q); + } +} +int blk_iolatency_init (struct request_queue *q) {struct blk_iolatency *blkiolat;
@@ -740,17 +782,15 @@ int blk_iolatency_init(struct request_qu }timer_setup (&blkiolat->timer, blkiolatency_timer_fn,0 ); +INIT_WORK (&blkiolat->enable_work, blkiolatency_enable_work_fn);return 0 ; } -/* -* return 1 for enabling iolatency, return -1 for disabling iolatency, otherwise -* return 0. -*/ -static int iolatency_set_min_lat_nsec (struct blkcg_gq *blkg,u64 val) +static void iolatency_set_min_lat_nsec (struct blkcg_gq *blkg,u64 val) {struct iolatency_grp *iolat =blkg_to_lat (blkg); +struct blk_iolatency *blkiolat = iolat->blkiolat;u64 oldval = iolat->min_lat_nsec; iolat->min_lat_nsec = val;
@@ -758,13 +798,15 @@ static int iolatency_set_min_lat_nsec(st iolat->cur_win_nsec =min_t (u64, iolat->cur_win_nsec,BLKIOLATENCY_MAX_WIN_SIZE ); -if (!oldval && val) -return 1 ; +if (!oldval && val) { +if (atomic_inc_return (&blkiolat->enable_cnt) ==1 ) +schedule_work (&blkiolat->enable_work); + }if (oldval && !val) {blkcg_clear_delay (blkg); -return -1 ; +if (atomic_dec_return (&blkiolat->enable_cnt) ==0 ) +schedule_work (&blkiolat->enable_work); } -return 0 ; }static void iolatency_clear_scaling (struct blkcg_gq *blkg)
@@ -796,7 +838,6 @@ static ssize_t iolatency_set_limit(strucu64 lat_val =0 ;u64 oldval;int ret; -int enable =0 ; ret =blkg_conf_prep (blkcg, &blkcg_policy_iolatency, buf, &ctx);if (ret)
@@ -831,41 +872,12 @@ static ssize_t iolatency_set_limit(struc blkg = ctx.blkg; oldval = iolat->min_lat_nsec; - enable =iolatency_set_min_lat_nsec (blkg, lat_val); -if (enable) { -if (!blk_get_queue (blkg->q)) { - ret = -ENODEV ; - goto out; - } - -blkg_get (blkg); - } - -if (oldval != iolat->min_lat_nsec) { +iolatency_set_min_lat_nsec (blkg, lat_val); +if (oldval != iolat->min_lat_nsec)iolatency_clear_scaling (blkg); - } - ret =0 ; out:blkg_conf_finish (&ctx); -if (ret ==0 && enable) { -struct iolatency_grp *tmp =blkg_to_lat (blkg); -struct blk_iolatency *blkiolat = tmp->blkiolat; - -blk_mq_freeze_queue (blkg->q); - -if (enable ==1 ) -atomic_inc (&blkiolat->enabled); -else if (enable ==-1 ) -atomic_dec (&blkiolat->enabled); -else -WARN_ON_ONCE (1 ); - -blk_mq_unfreeze_queue (blkg->q); - -blkg_put (blkg); -blk_put_queue (blkg->q); - }return ret ?: nbytes; }
@@ -1006,14 +1018,8 @@ static void iolatency_pd_offline(struct {struct iolatency_grp *iolat =pd_to_lat (pd);struct blkcg_gq *blkg =lat_to_blkg (iolat); -struct blk_iolatency *blkiolat = iolat->blkiolat; -int ret; - ret =iolatency_set_min_lat_nsec (blkg,0 ); -if (ret ==1 ) -atomic_inc (&blkiolat->enabled); -if (ret ==-1 ) -atomic_dec (&blkiolat->enabled); +iolatency_set_min_lat_nsec (blkg,0 );iolatency_clear_scaling (blkg); }
Greg Kroah-Hartman
maintainerPATCH 426/452 coresight: core: Fix coresight device probe failure issue
In reply to Greg Kroah-HartmanFrom: Mao Jinlong <[email protected]>
commit 8c1d3f79d9ca48e406b78e90e94cf09a8c076bf2 upstream.
It is possibe that probe failure issue happens when the device and its child_device's probe happens at the same time. In coresight_make_links, has_conns_grp is true for parent, but has_conns_grp is false for child device as has_conns_grp is set to true in coresight_create_conns_sysfs_group. The probe of parent device will fail at this condition. Add has_conns_grp check for child device before make the links and make the process from device_register to connection_create be atomic to avoid this probe failure issue.
--- drivers/hwtracing/coresight/coresight-core.c | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-core.c +22 -11
@@ -1337,7 +1337,7 @@ static int coresight_fixup_device_conns(continue ; conn->child_dev =coresight_find_csdev_by_fwnode (conn->child_fwnode); -if (conn->child_dev) { +if (conn->child_dev && conn->child_dev->has_conns_grp) { ret =coresight_make_links (csdev, conn, conn->child_dev);if (ret)
@@ -1486,6 +1486,7 @@ struct coresight_device *coresight_regisint nr_refcnts =1 ;atomic_t *refcnts =NULL ;struct coresight_device *csdev; +bool registered = false; csdev =kzalloc (sizeof (*csdev),GFP_KERNEL );if (!csdev) {
@@ -1506,7 +1507,8 @@ struct coresight_device *coresight_regis refcnts =kcalloc (nr_refcnts,sizeof (*refcnts),GFP_KERNEL );if (!refcnts) { ret = -ENOMEM ; - goto err_free_csdev; +kfree (csdev); + goto err_out; } csdev->refcnt = refcnts;
@@ -1530,6 +1532,13 @@ struct coresight_device *coresight_regis csdev->dev.fwnode =fwnode_handle_get (dev_fwnode (desc->dev));dev_set_name (&csdev->dev,"%s" , desc->name); +/* +* Make sure the device registration and the connection fixup +* are synchronised, so that we don't see uninitialised devices +* on the coresight bus while trying to resolve the connections. +*/ +mutex_lock (&coresight_mutex); + ret =device_register (&csdev->dev);if (ret) {put_device (&csdev->dev);
@@ -1537,7 +1546,7 @@ struct coresight_device *coresight_regis* All resources are free'd explicitly via * coresight_device_release(), triggered from put_device(). */ - goto err_out; + goto out_unlock; } if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
@@ -1552,11 +1561,11 @@ struct coresight_device *coresight_regis* from put_device(), which is in turn called from * function device_unregister(). */ - goto err_out; + goto out_unlock; } } - -mutex_lock (&coresight_mutex); +/* Device is now registered */ + registered = true; ret =coresight_create_conns_sysfs_group (csdev);if (!ret)
@@ -1566,16 +1575,18 @@ struct coresight_device *coresight_regisif (!ret && cti_assoc_ops && cti_assoc_ops->add) cti_assoc_ops->add (csdev); +out_unlock:mutex_unlock (&coresight_mutex); -if (ret) { +/* Success */ +if (!ret) +return csdev; + +/* Unregister the device if needed */ +if (registered) {coresight_unregister (csdev);return ERR_PTR (ret); } -return csdev; - -err_free_csdev: -kfree (csdev); err_out:/* Cleanup the connection information */ coresight_release_platform_data (NULL , desc->pdata);
Greg Kroah-Hartman
maintainerPATCH 427/452 phy: qcom-qmp: fix reset-controller leak on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 4d2900f20edfe541f75756a00deeb2ffe7c66bc1 upstream.
Make sure to release the lane reset controller in case of a late probe error (e.g. probe deferral).
Note that due to the reset controller being defined in devicetree in "lane" child nodes, devm_reset_control_get_exclusive() cannot be used directly.
--- drivers/phy/qualcomm/phy-qcom-qmp.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/phy/qualcomm/phy-qcom-qmp.c +9 -0
@@ -3717,6 +3717,11 @@ static const struct phy_ops qcom_qmp_pci .owner = THIS_MODULE, }; +static void qcom_qmp_reset_control_put (void *data) +{ +reset_control_put (data); +} +static int qcom_qmp_phy_create (struct device *dev,struct device_node *np,int id,void __iomem *serdes,const struct qmp_phy_cfg *cfg)
@@ -3811,6 +3816,10 @@ int qcom_qmp_phy_create(struct device *ddev_err (dev,"failed to get lane%d reset\n" , id);return PTR_ERR (qphy->lane_rst); } + ret =devm_add_action_or_reset (dev, qcom_qmp_reset_control_put, + qphy->lane_rst); +if (ret) +return ret; }if (cfg->type ==PHY_TYPE_UFS || cfg->type ==PHY_TYPE_PCIE )
Greg Kroah-Hartman
maintainerPATCH 428/452 net: ipa: fix page free in ipa_endpoint_trans_release()
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
commit 155c0c90bca918de6e4327275dfc1d97fd604115 upstream.
Currently the (possibly compound) page used for receive buffers are freed using __free_pages(). But according to this comment above the definition of that function, that's wrong:
If you want to use the page's reference count to decide when to free the allocation, you should allocate a compound page, and use put_page() instead of __free_pages().
Convert the call to __free_pages() in ipa_endpoint_trans_release() to use put_page() instead.
--- drivers/net/ipa/ipa_endpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ipa/ipa_endpoint.c +1 -1
@@ -1179,7 +1179,7 @@ void ipa_endpoint_trans_release(struct istruct page *page = trans->data;if (page) -__free_pages (page,get_order (IPA_RX_BUFFER_SIZE )); +put_page (page); } }
Greg Kroah-Hartman
maintainerPATCH 429/452 net: ipa: fix page free in ipa_endpoint_replenish_one()
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
commit 70132763d5d2e94cd185e3aa92ac6a3ba89068fa upstream.
Currently the (possibly compound) pages used for receive buffers are freed using __free_pages(). But according to this comment above the definition of that function, that's wrong:
If you want to use the page's reference count to decide when to free the allocation, you should allocate a compound page, and use put_page() instead of __free_pages().
Convert the call to __free_pages() in ipa_endpoint_replenish_one() to use put_page() instead.
--- drivers/net/ipa/ipa_endpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ipa/ipa_endpoint.c +1 -1
@@ -884,7 +884,7 @@ static int ipa_endpoint_replenish_one(st err_trans_free:gsi_trans_free (trans); err_free_pages: -__free_pages (page,get_order (IPA_RX_BUFFER_SIZE )); +put_page (page);return -ENOMEM ; }
Greg Kroah-Hartman
maintainerPATCH 430/452 xfs: set inode size after creating symlink
In reply to Greg Kroah-HartmanFrom: Jeffrey Mitchell <[email protected]>
commit 8aa921a95335d0a8c8e2be35a44467e7c91ec3e4 upstream.
When XFS creates a new symlink, it writes its size to disk but not to the VFS inode. This causes i_size_read() to return 0 for that symlink until it is re-read from disk, for example when the system is rebooted.
I found this inconsistency while protecting directories with eCryptFS. The command "stat path/to/symlink/in/ecryptfs" will report "Size: 0" if the symlink was created after the last reboot on an XFS root.
Call i_size_write() in xfs_symlink()
--- fs/xfs/xfs_symlink.c | 1 + 1 file changed, 1 insertion(+)
fs/xfs/xfs_symlink.c +1 -0
@@ -300,6 +300,7 @@ xfs_symlink( }ASSERT (pathlen ==0 ); } +i_size_write (VFS_I (ip), ip->i_d.di_size);/* * Create the directory entry for the symlink.
Greg Kroah-Hartman
maintainerPATCH 431/452 xfs: sync lazy sb accounting on quiesce of read-only mounts
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
commit 50d25484bebe94320c49dd1347d3330c7063bbdb upstream.
xfs_log_sbcount() syncs the superblock specifically to accumulate the in-core percpu superblock counters and commit them to disk. This is required to maintain filesystem consistency across quiesce (freeze, read-only mount/remount) or unmount when lazy superblock accounting is enabled because individual transactions do not update the superblock directly.
This mechanism works as expected for writable mounts, but xfs_log_sbcount() skips the update for read-only mounts. Read-only mounts otherwise still allow log recovery and write out an unmount record during log quiesce. If a read-only mount performs log recovery, it can modify the in-core superblock counters and write an unmount record when the filesystem unmounts without ever syncing the in-core counters. This leaves the filesystem with a clean log but in an inconsistent state with regard to lazy sb counters.
Update xfs_log_sbcount() to use the same logic xfs_log_unmount_write() uses to determine when to write an unmount record. This ensures that lazy accounting is always synced before the log is cleaned. Refactor this logic into a new helper to distinguish between a writable filesystem and a writable log. Specifically, the log is writable unless the filesystem is mounted with the norecovery mount option, the underlying log device is read-only, or the filesystem is shutdown. Drop the freeze state check because the update is already allowed during the freezing process and no context calls this function on an already frozen fs. Also, retain the shutdown check in xfs_log_unmount_write() to catch the case where the preceding log force might have triggered a shutdown.
--- fs/xfs/xfs_log.c | 28 ++++++++++++++++++++-------- fs/xfs/xfs_log.h | 1 + fs/xfs/xfs_mount.c | 3 +-- 3 files changed, 22 insertions(+), 10 deletions(-)
fs/xfs/xfs_log.c +20 -8
@@ -347,6 +347,25 @@ xlog_tic_add_region(xlog_ticket_t *tic, tic->t_res_num++; } +bool +xfs_log_writable ( +struct xfs_mount *mp) +{ +/* +* Never write to the log on norecovery mounts, if the block device is +* read-only, or if the filesystem is shutdown. Read-only mounts still +* allow internal writes for log recovery and unmount purposes, so don't +* restrict that case here. +*/ +if (mp->m_flags &XFS_MOUNT_NORECOVERY ) +return false; +if (xfs_readonly_buftarg (mp->m_log->l_targ)) +return false; +if (XFS_FORCED_SHUTDOWN (mp)) +return false; +return true; +} +/* * Replenish the byte reservation required by moving the grant write head. */
@@ -886,15 +905,8 @@ xfs_log_unmount_write( {struct xlog *log = mp->m_log; -/* -* Don't write out unmount record on norecovery mounts or ro devices. -* Or, if we are doing a forced umount (typically because of IO errors). -*/ -if (mp->m_flags &XFS_MOUNT_NORECOVERY || -xfs_readonly_buftarg (log->l_targ)) { -ASSERT (mp->m_flags &XFS_MOUNT_RDONLY ); +if (!xfs_log_writable (mp))return ; - }xfs_log_force (mp,XFS_LOG_SYNC );
fs/xfs/xfs_log.h +1 -0
@@ -127,6 +127,7 @@ int xfs_log_reserve(struct xfs_mount *int xfs_log_regrant (struct xfs_mount *mp,struct xlog_ticket *tic);void xfs_log_unmount (struct xfs_mount *mp);int xfs_log_force_umount (struct xfs_mount *mp,int logerror); +bool xfs_log_writable (struct xfs_mount *mp);struct xlog_ticket *xfs_log_ticket_get (struct xlog_ticket *ticket);void xfs_log_ticket_put (struct xlog_ticket *ticket);
fs/xfs/xfs_mount.c +1 -2
@@ -1176,8 +1176,7 @@ xfs_fs_writable(int xfs_log_sbcount (xfs_mount_t *mp) { -/* allow this to proceed during the freeze sequence... */ -if (!xfs_fs_writable (mp,SB_FREEZE_COMPLETE )) +if (!xfs_log_writable (mp))return 0 ;/*
Greg Kroah-Hartman
maintainerPATCH 432/452 xfs: fix chown leaking delalloc quota blocks when fssetxattr fails
In reply to Greg Kroah-HartmanFrom: "Darrick J. Wong" <[email protected]>
commit 1aecf3734a95f3c167d1495550ca57556d33f7ec upstream.
While refactoring the quota code to create a function to allocate inode change transactions, I noticed that xfs_qm_vop_chown_reserve does more than just make reservations: it also *modifies* the incore counts directly to handle the owner id change for the delalloc blocks.
I then observed that the fssetxattr code continues validating input arguments after making the quota reservation but before dirtying the transaction. If the routine decides to error out, it fails to undo the accounting switch! This leads to incorrect quota reservation and failure down the line.
We can fix this by making the reservation function do only that -- for the new dquot, it reserves ondisk and delalloc blocks to the transaction, and the old dquot hangs on to its incore reservation for now. Once we actually switch the dquots, we can then update the incore reservations because we've dirtied the transaction and it's too late to turn back now.
No fixes tag because this has been broken since the start of git.
--- fs/xfs/xfs_qm.c | 92 +++++++++++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 57 deletions(-)
fs/xfs/xfs_qm.c +35 -57
@@ -1786,6 +1786,29 @@ xfs_qm_vop_chown(xfs_trans_mod_dquot (tp, newdq,XFS_TRANS_DQ_ICOUNT ,1 );/* +* Back when we made quota reservations for the chown, we reserved the +* ondisk blocks + delalloc blocks with the new dquot. Now that we've +* switched the dquots, decrease the new dquot's block reservation +* (having already bumped up the real counter) so that we don't have +* any reservation to give back when we commit. +*/ +xfs_trans_mod_dquot (tp, newdq,XFS_TRANS_DQ_RES_BLKS , + -ip->i_delayed_blks); + +/* +* Give the incore reservation for delalloc blocks back to the old +* dquot. We don't normally handle delalloc quota reservations +* transactionally, so just lock the dquot and subtract from the +* reservation. Dirty the transaction because it's too late to turn +* back now. +*/ + tp->t_flags |=XFS_TRANS_DIRTY ; +xfs_dqlock (prevdq); +ASSERT (prevdq->q_blk.reserved >= ip->i_delayed_blks); + prevdq->q_blk.reserved -= ip->i_delayed_blks; +xfs_dqunlock (prevdq); + +/* * Take an extra reference, because the inode is going to keep * this dquot pointer even after the trans_commit. */
@@ -1807,84 +1830,39 @@ xfs_qm_vop_chown_reserve( uint flags) {struct xfs_mount *mp = ip->i_mount; -uint64_t delblks;unsigned int blkflags; -struct xfs_dquot *udq_unres =NULL ; -struct xfs_dquot *gdq_unres =NULL ; -struct xfs_dquot *pdq_unres =NULL ;struct xfs_dquot *udq_delblks =NULL ;struct xfs_dquot *gdq_delblks =NULL ;struct xfs_dquot *pdq_delblks =NULL ; -int error; -ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL |XFS_ILOCK_SHARED ));ASSERT (XFS_IS_QUOTA_RUNNING (mp)); - delblks = ip->i_delayed_blks; blkflags =XFS_IS_REALTIME_INODE (ip) ?XFS_QMOPT_RES_RTBLKS :XFS_QMOPT_RES_REGBLKS ;if (XFS_IS_UQUOTA_ON (mp) && udqp && -i_uid_read (VFS_I (ip)) != udqp->q_id) { +i_uid_read (VFS_I (ip)) != udqp->q_id) udq_delblks = udqp; -/* -* If there are delayed allocation blocks, then we have to -* unreserve those from the old dquot, and add them to the -* new dquot. -*/ -if (delblks) { -ASSERT (ip->i_udquot); - udq_unres = ip->i_udquot; - } - } +if (XFS_IS_GQUOTA_ON (ip->i_mount) && gdqp && -i_gid_read (VFS_I (ip)) != gdqp->q_id) { +i_gid_read (VFS_I (ip)) != gdqp->q_id) gdq_delblks = gdqp; -if (delblks) { -ASSERT (ip->i_gdquot); - gdq_unres = ip->i_gdquot; - } - }if (XFS_IS_PQUOTA_ON (ip->i_mount) && pdqp && - ip->i_d.di_projid != pdqp->q_id) { + ip->i_d.di_projid != pdqp->q_id) pdq_delblks = pdqp; -if (delblks) { -ASSERT (ip->i_pdquot); - pdq_unres = ip->i_pdquot; - } - } - - error =xfs_trans_reserve_quota_bydquots (tp, ip->i_mount, - udq_delblks, gdq_delblks, pdq_delblks, - ip->i_d.di_nblocks,1 , flags | blkflags); -if (error) -return error;/* -* Do the delayed blks reservations/unreservations now. Since, these -* are done without the help of a transaction, if a reservation fails -* its previous reservations won't be automatically undone by trans -* code. So, we have to do it manually here. +* Reserve enough quota to handle blocks on disk and reserved for a +* delayed allocation. We'll actually transfer the delalloc +* reservation between dquots at chown time, even though that part is +* only semi-transactional. */ -if (delblks) { -/* -* Do the reservations first. Unreservation can't fail. -*/ -ASSERT (udq_delblks || gdq_delblks || pdq_delblks); -ASSERT (udq_unres || gdq_unres || pdq_unres); - error =xfs_trans_reserve_quota_bydquots (NULL , ip->i_mount, - udq_delblks, gdq_delblks, pdq_delblks, - (xfs_qcnt_t )delblks,0 , flags | blkflags); -if (error) -return error; -xfs_trans_reserve_quota_bydquots (NULL , ip->i_mount, - udq_unres, gdq_unres, pdq_unres, - -((xfs_qcnt_t )delblks),0 , blkflags); - } - -return 0 ; +return xfs_trans_reserve_quota_bydquots (tp, ip->i_mount, udq_delblks, + gdq_delblks, pdq_delblks, + ip->i_d.di_nblocks + ip->i_delayed_blks, +1 , blkflags | flags); }int
Greg Kroah-Hartman
maintainerPATCH 433/452 xfs: fix incorrect root dquot corruption error when switching group/project quota types
In reply to Greg Kroah-HartmanFrom: "Darrick J. Wong" <[email protected]>
commit 45068063efb7dd0a8d115c106aa05d9ab0946257 upstream.
While writing up a regression test for broken behavior when a chprojid request fails, I noticed that we were logging corruption notices about the root dquot of the group/project quota file at mount time when testing V4 filesystems.
In commit afeda6000b0c, I was trying to improve ondisk dquot validation by making sure that when we load an ondisk dquot into memory on behalf of an incore dquot, the dquot id and type matches. Unfortunately, I forgot that V4 filesystems only have two quota files, and can switch that file between group and project quota types at mount time. When we perform that switch, we'll try to load the default quota limits from the root dquot prior to running quotacheck and log a corruption error when the types don't match.
This is inconsequential because quotacheck will reset the second quota file as part of doing the switch, but we shouldn't leave scary messages in the kernel log.
--- fs/xfs/xfs_dquot.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
fs/xfs/xfs_dquot.c +37 -2
@@ -500,6 +500,42 @@ xfs_dquot_alloc(return dqp; } +/* Check the ondisk dquot's id and type match what the incore dquot expects. */ +static bool +xfs_dquot_check_type ( +struct xfs_dquot *dqp, +struct xfs_disk_dquot *ddqp) +{ +uint8_t ddqp_type; +uint8_t dqp_type; + + ddqp_type = ddqp->d_type &XFS_DQTYPE_REC_MASK ; + dqp_type =xfs_dquot_type (dqp); + +if (be32_to_cpu (ddqp->d_id) != dqp->q_id) +return false; + +/* +* V5 filesystems always expect an exact type match. V4 filesystems +* expect an exact match for user dquots and for non-root group and +* project dquots. +*/ +if (xfs_sb_version_hascrc (&dqp->q_mount->m_sb) || + dqp_type ==XFS_DQTYPE_USER || dqp->q_id !=0 ) +return ddqp_type == dqp_type; + +/* +* V4 filesystems support either group or project quotas, but not both +* at the same time. The non-user quota file can be switched between +* group and project quota uses depending on the mount options, which +* means that we can encounter the other type when we try to load quota +* defaults. Quotacheck will soon reset the the entire quota file +* (including the root dquot) anyway, but don't log scary corruption +* reports to dmesg. +*/ +return ddqp_type ==XFS_DQTYPE_GROUP || ddqp_type ==XFS_DQTYPE_PROJ ; +} +/* Copy the in-core quota fields in from the on-disk buffer. */ STATIC int xfs_dquot_from_disk(
@@ -512,8 +548,7 @@ xfs_dquot_from_disk(* Ensure that we got the type and ID we were looking for. * Everything else was checked by the dquot buffer verifier. */ -if ((ddqp->d_type &XFS_DQTYPE_REC_MASK ) !=xfs_dquot_type (dqp) || -be32_to_cpu (ddqp->d_id) != dqp->q_id) { +if (!xfs_dquot_check_type (dqp, ddqp)) {xfs_alert_tag (bp->b_mount,XFS_PTAG_VERIFIER_ERROR ,"Metadata corruption detected at %pS, quota %u" , __this_address, dqp->q_id);
Greg Kroah-Hartman
maintainerPATCH 434/452 xfs: restore shutdown check in mapped write fault path
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
commit e4826691cc7e5458bcb659935d0092bcf3f08c20 upstream.
XFS triggers an iomap warning in the write fault path due to a !PageUptodate() page if a write fault happens to occur on a page that recently failed writeback. The iomap writeback error handling code can clear the Uptodate flag if no portion of the page is submitted for I/O. This is reproduced by fstest generic/019, which combines various forms of I/O with simulated disk failures that inevitably lead to filesystem shutdown (which then unconditionally fails page writeback).
This is a regression introduced by commit f150b4234397 ("xfs: split the iomap ops for buffered vs direct writes") due to the removal of a shutdown check and explicit error return in the ->iomap_begin() path used by the write fault path. The explicit error return historically translated to a SIGBUS, but now carries on with iomap processing where it complains about the unexpected state. Restore the shutdown check to xfs_buffered_write_iomap_begin() to restore historical behavior.
--- fs/xfs/xfs_iomap.c | 3 +++ 1 file changed, 3 insertions(+)
fs/xfs/xfs_iomap.c +3 -0
@@ -870,6 +870,9 @@ xfs_buffered_write_iomap_begin(int allocfork =XFS_DATA_FORK ;int error =0 ; +if (XFS_FORCED_SHUTDOWN (mp)) +return -EIO ; +/* we can't use delayed allocations when using extent size hints */ if (xfs_get_extsz_hint (ip)) return xfs_direct_write_iomap_begin(inode, offset, count,
Greg Kroah-Hartman
maintainerPATCH 435/452 xfs: force log and push AIL to clear pinned inodes when aborting mount
In reply to Greg Kroah-HartmanFrom: "Darrick J. Wong" <[email protected]>
commit d336f7ebc65007f5831e2297e6f3383ae8dbf8ed upstream.
If we allocate quota inodes in the process of mounting a filesystem but then decide to abort the mount, it's possible that the quota inodes are sitting around pinned by the log. Now that inode reclaim relies on the AIL to flush inodes, we have to force the log and push the AIL in between releasing the quota inodes and kicking off reclaim to tear down all the incore inodes. Do this by extracting the bits we need from the unmount path and reusing them. As an added bonus, failed writes during a failed mount will not retry forever now.
This was originally found during a fuzz test of metadata directories (xfs/1546), but the actual symptom was that reclaim hung up on the quota inodes.
--- fs/xfs/xfs_mount.c | 90 +++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 46 deletions(-)
fs/xfs/xfs_mount.c +44 -46
@@ -632,6 +632,47 @@ xfs_check_summary_counts( }/* +* Flush and reclaim dirty inodes in preparation for unmount. Inodes and +* internal inode structures can be sitting in the CIL and AIL at this point, +* so we need to unpin them, write them back and/or reclaim them before unmount +* can proceed. +* +* An inode cluster that has been freed can have its buffer still pinned in +* memory because the transaction is still sitting in a iclog. The stale inodes +* on that buffer will be pinned to the buffer until the transaction hits the +* disk and the callbacks run. Pushing the AIL will skip the stale inodes and +* may never see the pinned buffer, so nothing will push out the iclog and +* unpin the buffer. +* +* Hence we need to force the log to unpin everything first. However, log +* forces don't wait for the discards they issue to complete, so we have to +* explicitly wait for them to complete here as well. +* +* Then we can tell the world we are unmounting so that error handling knows +* that the filesystem is going away and we should error out anything that we +* have been retrying in the background. This will prevent never-ending +* retries in AIL pushing from hanging the unmount. +* +* Finally, we can push the AIL to clean all the remaining dirty objects, then +* reclaim the remaining inodes that are still in memory at this point in time. +*/ +static void +xfs_unmount_flush_inodes ( +struct xfs_mount *mp) +{ +xfs_log_force (mp,XFS_LOG_SYNC ); +xfs_extent_busy_wait_all (mp); +flush_workqueue (xfs_discard_wq); + + mp->m_flags |=XFS_MOUNT_UNMOUNTING ; + +xfs_ail_push_all_sync (mp->m_ail); +cancel_delayed_work_sync (&mp->m_reclaim_work); +xfs_reclaim_inodes (mp); +xfs_health_unmount (mp); +} + +/* * This function does the following on an initial mount of a file system: * - reads the superblock from disk and init the mount struct * - if we're a 32-bit kernel, do a size check on the superblock
@@ -1005,7 +1046,7 @@ xfs_mountfs(/* Clean out dquots that might be in memory after quotacheck. */ xfs_qm_unmount (mp);/* -* Cancel all delayed reclaim work and reclaim the inodes directly. +* Flush all inode reclamation work and flush the log. * We have to do this /after/ rtunmount and qm_unmount because those * two will have scheduled delayed reclaim for the rt/quota inodes. *
@@ -1015,11 +1056,8 @@ xfs_mountfs(* qm_unmount_quotas and therefore rely on qm_unmount to release the * quota inodes. */ -cancel_delayed_work_sync (&mp->m_reclaim_work); -xfs_reclaim_inodes (mp); -xfs_health_unmount (mp); +xfs_unmount_flush_inodes (mp); out_log_dealloc: - mp->m_flags |=XFS_MOUNT_UNMOUNTING ;xfs_log_mount_cancel (mp); out_fail_wait:if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
@@ -1060,47 +1098,7 @@ xfs_unmountfs(xfs_rtunmount_inodes (mp);xfs_irele (mp->m_rootip); -/* -* We can potentially deadlock here if we have an inode cluster -* that has been freed has its buffer still pinned in memory because -* the transaction is still sitting in a iclog. The stale inodes -* on that buffer will be pinned to the buffer until the -* transaction hits the disk and the callbacks run. Pushing the AIL will -* skip the stale inodes and may never see the pinned buffer, so -* nothing will push out the iclog and unpin the buffer. Hence we -* need to force the log here to ensure all items are flushed into the -* AIL before we go any further. -*/ -xfs_log_force (mp,XFS_LOG_SYNC ); - -/* -* Wait for all busy extents to be freed, including completion of -* any discard operation. -*/ -xfs_extent_busy_wait_all (mp); -flush_workqueue (xfs_discard_wq); - -/* -* We now need to tell the world we are unmounting. This will allow -* us to detect that the filesystem is going away and we should error -* out anything that we have been retrying in the background. This will -* prevent neverending retries in AIL pushing from hanging the unmount. -*/ - mp->m_flags |=XFS_MOUNT_UNMOUNTING ; - -/* -* Flush all pending changes from the AIL. -*/ -xfs_ail_push_all_sync (mp->m_ail); - -/* -* Reclaim all inodes. At this point there should be no dirty inodes and -* none should be pinned or locked. Stop background inode reclaim here -* if it is still running. -*/ -cancel_delayed_work_sync (&mp->m_reclaim_work); -xfs_reclaim_inodes (mp); -xfs_health_unmount (mp); +xfs_unmount_flush_inodes (mp);xfs_qm_unmount (mp);
Greg Kroah-Hartman
maintainerPATCH 436/452 xfs: consider shutdown in bmapbt cursor delete assert
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
commit 1cd738b13ae9b29e03d6149f0246c61f76e81fcf upstream.
The assert in xfs_btree_del_cursor() checks that the bmapbt block allocation field has been handled correctly before the cursor is freed. This field is used for accurate calculation of indirect block reservation requirements (for delayed allocations), for example. generic/019 reproduces a scenario where this assert fails because the filesystem has shutdown while in the middle of a bmbt record insertion. This occurs after a bmbt block has been allocated via the cursor but before the higher level bmap function (i.e. xfs_bmap_add_extent_hole_real()) completes and resets the field.
Update the assert to accommodate the transient state if the filesystem has shutdown. While here, clean up the indentation and comments in the function.
--- fs/xfs/libxfs/xfs_btree.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-)
fs/xfs/libxfs/xfs_btree.c +12 -21
@@ -353,20 +353,17 @@ xfs_btree_free_block(*/ void xfs_btree_del_cursor ( -xfs_btree_cur_t *cur,/* btree cursor */ -int error)/* del because of error */ +struct xfs_btree_cur *cur,/* btree cursor */ +int error)/* del because of error */ { -int i;/* btree level */ +int i;/* btree level */ /* -* Clear the buffer pointers, and release the buffers. -* If we're doing this in the face of an error, we -* need to make sure to inspect all of the entries -* in the bc_bufs array for buffers to be unlocked. -* This is because some of the btree code works from -* level n down to 0, and if we get an error along -* the way we won't have initialized all the entries -* down to 0. +* Clear the buffer pointers and release the buffers. If we're doing +* this because of an error, inspect all of the entries in the bc_bufs +* array for buffers to be unlocked. This is because some of the btree +* code works from level n down to 0, and if we get an error along the +* way we won't have initialized all the entries down to 0. */ for (i =0 ; i < cur->bc_nlevels; i++) {if (cur->bc_bufs[i])
@@ -374,17 +371,11 @@ xfs_btree_del_cursor(else if (!error)break ; } -/* -* Can't free a bmap cursor without having dealt with the -* allocated indirect blocks' accounting. -*/ -ASSERT (cur->bc_btnum !=XFS_BTNUM_BMAP || - cur->bc_ino.allocated ==0 ); -/* -* Free the cursor. -*/ + +ASSERT (cur->bc_btnum !=XFS_BTNUM_BMAP || cur->bc_ino.allocated ==0 || +XFS_FORCED_SHUTDOWN (cur->bc_mp));if (unlikely (cur->bc_flags &XFS_BTREE_STAGING )) -kmem_free ((void *)cur->bc_ops); +kmem_free (cur->bc_ops);kmem_cache_free (xfs_btree_cur_zone, cur); }
Greg Kroah-Hartman
maintainerPATCH 437/452 xfs: assert in xfs_btree_del_cursor should take into account error
In reply to Greg Kroah-HartmanFrom: Dave Chinner <[email protected]>
commit 56486f307100e8fc66efa2ebd8a71941fa10bf6f upstream.
xfs/538 on a 1kB block filesystem failed with this assert:
XFS: Assertion failed: cur->bc_btnum != XFS_BTNUM_BMAP || cur->bc_ino.allocated == 0 || xfs_is_shutdown(cur->bc_mp), file: fs/xfs/libxfs/xfs_btree.c, line: 448
The problem was that an allocation failed unexpectedly in xfs_bmbt_alloc_block() after roughly 150,000 minlen allocation error injections, resulting in an EFSCORRUPTED error being returned to xfs_bmapi_write(). The error occurred on extent-to-btree format conversion allocating the new root block:
RIP: 0010:xfs_bmbt_alloc_block+0x177/0x210 Call Trace: <TASK> xfs_btree_new_iroot+0xdf/0x520 xfs_btree_make_block_unfull+0x10d/0x1c0 xfs_btree_insrec+0x364/0x790 xfs_btree_insert+0xaa/0x210 xfs_bmap_add_extent_hole_real+0x1fe/0x9a0 xfs_bmapi_allocate+0x34c/0x420 xfs_bmapi_write+0x53c/0x9c0 xfs_alloc_file_space+0xee/0x320 xfs_file_fallocate+0x36b/0x450 vfs_fallocate+0x148/0x340 __x64_sys_fallocate+0x3c/0x70 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x44/0xa
Why the allocation failed at this point is unknown, but is likely that we ran the transaction out of reserved space and filesystem out of space with bmbt blocks because of all the minlen allocations being done causing worst case fragmentation of a large allocation.
Regardless of the cause, we've then called xfs_bmapi_finish() which calls xfs_btree_del_cursor(cur, error) to tear down the cursor.
So we have a failed operation, error != 0, cur->bc_ino.allocated > 0 and the filesystem is still up. The assert fails to take into account that allocation can fail with an error and the transaction teardown will shut the filesystem down if necessary. i.e. the assert needs to check "|| error != 0" as well, because at this point shutdown is pending because the current transaction is dirty....
--- fs/xfs/libxfs/xfs_btree.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_btree.c +7 -1
@@ -372,8 +372,14 @@ xfs_btree_del_cursor(break ; } +/* +* If we are doing a BMBT update, the number of unaccounted blocks +* allocated during this cursor life time should be zero. If it's not +* zero, then we should be shut down or on our way to shutdown due to +* cancelling a dirty transaction on error. +*/ ASSERT (cur->bc_btnum !=XFS_BTNUM_BMAP || cur->bc_ino.allocated ==0 || -XFS_FORCED_SHUTDOWN (cur->bc_mp)); +XFS_FORCED_SHUTDOWN (cur->bc_mp) || error !=0 );if (unlikely (cur->bc_flags &XFS_BTREE_STAGING ))kmem_free (cur->bc_ops);kmem_cache_free (xfs_btree_cur_zone, cur);
Greg Kroah-Hartman
maintainerPATCH 438/452 kseltest/cgroup: Make test_stress.sh work if run interactively
In reply to Greg Kroah-HartmanFrom: Waiman Long <[email protected]>
commit 213adc63dfbcdff9a0c19ec1f2681fda9c05cf6d upstream.
Commit 54de76c01239 ("kselftest/cgroup: fix test_stress.sh to use OUTPUT dir") changes the test_core command path from . to $OUTPUT. However, variable OUTPUT may not be defined if the command is run interactively. Fix that by using ${OUTPUT:-.} to cover both cases.
--- tools/testing/selftests/cgroup/test_stress.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/cgroup/test_stress.sh +1 -1
@@ -1,4 +1,4 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -./with_stress.sh -s subsys -s fork ${OUTPUT}/test_core +./with_stress.sh -s subsys -s fork ${OUTPUT:-.}/test_core
Greg Kroah-Hartman
maintainerPATCH 439/452 thermal/core: fix a UAF bug in __thermal_cooling_device_register()
In reply to Greg Kroah-HartmanFrom: Ziyang Xuan <[email protected]>
commit 0a5c26712f963f0500161a23e0ffff8d29f742ab upstream.
When device_register() return failed, program will goto out_kfree_type to release 'cdev->device' by put_device(). That will call thermal_release() to free 'cdev'. But the follow-up processes access 'cdev' continually. That trggers the UAF bug.
====================================================================
BUG: KASAN: use-after-free in __thermal_cooling_device_register+0x75b/0xa90 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 Call Trace: dump_stack_lvl+0xe2/0x152 print_address_description.constprop.0+0x21/0x140 ? __thermal_cooling_device_register+0x75b/0xa90 kasan_report.cold+0x7f/0x11b ? __thermal_cooling_device_register+0x75b/0xa90 __thermal_cooling_device_register+0x75b/0xa90 ? memset+0x20/0x40 ? __sanitizer_cov_trace_pc+0x1d/0x50 ? __devres_alloc_node+0x130/0x180 devm_thermal_of_cooling_device_register+0x67/0xf0 max6650_probe.cold+0x557/0x6aa
......
Freed by task 258: kasan_save_stack+0x1b/0x40 kasan_set_track+0x1c/0x30 kasan_set_free_info+0x20/0x30 __kasan_slab_free+0x109/0x140 kfree+0x117/0x4c0 thermal_release+0xa0/0x110 device_release+0xa7/0x240 kobject_put+0x1ce/0x540 put_device+0x20/0x30 __thermal_cooling_device_register+0x731/0xa90 devm_thermal_of_cooling_device_register+0x67/0xf0 max6650_probe.cold+0x557/0x6aa [max6650]
Do not use 'cdev' again after put_device() to fix the problem like doing in thermal_zone_device_register().
[dlezcano]: as requested by Rafael, change the affectation into two statements.
--- drivers/thermal/thermal_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/thermal/thermal_core.c +4 -2
@@ -1092,7 +1092,7 @@ __thermal_cooling_device_register(struct {struct thermal_cooling_device *cdev;struct thermal_zone_device *pos =NULL ; -int ret; +int id, ret;if (!ops || !ops->get_max_state || !ops->get_cur_state || !ops->set_cur_state)
@@ -1106,6 +1106,7 @@ __thermal_cooling_device_register(structif (ret <0 ) goto out_kfree_cdev; cdev->id = ret; + id = ret; cdev->type =kstrdup (type ? type :"" ,GFP_KERNEL );if (!cdev->type) {
@@ -1147,8 +1148,9 @@ out_kfree_type:thermal_cooling_device_destroy_sysfs (cdev);kfree (cdev->type);put_device (&cdev->device); + cdev =NULL ; out_ida_remove: -ida_simple_remove (&thermal_cdev_ida, cdev->id); +ida_simple_remove (&thermal_cdev_ida, id); out_kfree_cdev:return ERR_PTR (ret); }
Greg Kroah-Hartman
maintainerPATCH 440/452 thermal/core: Fix memory leak in the error path
In reply to Greg Kroah-HartmanFrom: Daniel Lezcano <[email protected]>
commit d44616c6cc3e35eea03ecfe9040edfa2b486a059 upstream.
Fix the following error:
smatch warnings:
drivers/thermal/thermal_core.c:1020 __thermal_cooling_device_register() warn: possible memory leak of 'cdev'
by freeing the cdev when exiting the function in the error path.
--- drivers/thermal/thermal_core.c | 1 + 1 file changed, 1 insertion(+)
drivers/thermal/thermal_core.c +1 -0
@@ -1152,6 +1152,7 @@ out_kfree_type: out_ida_remove:ida_simple_remove (&thermal_cdev_ida, id); out_kfree_cdev: +kfree (cdev);return ERR_PTR (ret); }
Greg Kroah-Hartman
maintainerPATCH 441/452 bfq: Avoid merging queues with different parents
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit c1cee4ab36acef271be9101590756ed0c0c374d9 upstream.
It can happen that the parent of a bfqq changes between the moment we decide two queues are worth to merge (and set bic->stable_merge_bfqq) and the moment bfq_setup_merge() is called. This can happen e.g. because the process submitted IO for a different cgroup and thus bfqq got reparented. It can even happen that the bfqq we are merging with has parent cgroup that is already offline and going to be destroyed in which case the merge can lead to use-after-free issues such as:
BUG: KASAN: use-after-free in __bfq_deactivate_entity+0x9cb/0xa50 Read of size 8 at addr ffff88800693c0c0 by task runc:[2:INIT]/10544 CPU: 0 PID: 10544 Comm: runc:[2:INIT] Tainted: G E 5.15.2-0.g5fb85fd-default #1 openSUSE Tumbleweed (unreleased) f1f3b891c72369aebecd2e43e4641a6358867c70 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a-rebuilt.opensuse.org 04/01/2014 Call Trace: <IRQ> dump_stack_lvl+0x46/0x5a print_address_description.constprop.0+0x1f/0x140 ? __bfq_deactivate_entity+0x9cb/0xa50 kasan_report.cold+0x7f/0x11b ? __bfq_deactivate_entity+0x9cb/0xa50 __bfq_deactivate_entity+0x9cb/0xa50 ? update_curr+0x32f/0x5d0 bfq_deactivate_entity+0xa0/0x1d0 bfq_del_bfqq_busy+0x28a/0x420 ? resched_curr+0x116/0x1d0 ? bfq_requeue_bfqq+0x70/0x70 ? check_preempt_wakeup+0x52b/0xbc0 __bfq_bfqq_expire+0x1a2/0x270 bfq_bfqq_expire+0xd16/0x2160 ? try_to_wake_up+0x4ee/0x1260 ? bfq_end_wr_async_queues+0xe0/0xe0 ? _raw_write_unlock_bh+0x60/0x60 ? _raw_spin_lock_irq+0x81/0xe0 bfq_idle_slice_timer+0x109/0x280 ? bfq_dispatch_request+0x4870/0x4870 __hrtimer_run_queues+0x37d/0x700 ? enqueue_hrtimer+0x1b0/0x1b0 ? kvm_clock_get_cycles+0xd/0x10 ? ktime_get_update_offsets_now+0x6f/0x280 hrtimer_interrupt+0x2c8/0x740
Fix the problem by checking that the parent of the two bfqqs we are merging in bfq_setup_merge() is the same.
--- block/bfq-iosched.c | 8 ++++++++ 1 file changed, 8 insertions(+)
block/bfq-iosched.c +8 -0
@@ -2509,6 +2509,14 @@ bfq_setup_merge(struct bfq_queue *bfqq,if (process_refs ==0 || new_process_refs ==0 )return NULL ; +/* +* Make sure merged queues belong to the same parent. Parents could +* have changed since the time we decided the two queues are suitable +* for merging. +*/ +if (new_bfqq->entity.parent != bfqq->entity.parent) +return NULL ; +bfq_log_bfqq (bfqq->bfqd, bfqq,"scheduling merge with queue %d" , new_bfqq->pid);
Greg Kroah-Hartman
maintainerPATCH 442/452 bfq: Drop pointless unlock-lock pair
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit fc84e1f941b91221092da5b3102ec82da24c5673 upstream.
In bfq_insert_request() we unlock bfqd->lock only to call trace_block_rq_insert() and then lock bfqd->lock again. This is really pointless since tracing is disabled if we really care about performance and even if the tracepoint is enabled, it is a quick call.
--- block/bfq-iosched.c | 3 --- 1 file changed, 3 deletions(-)
block/bfq-iosched.c +0 -3
@@ -5537,11 +5537,8 @@ static void bfq_insert_request(struct blreturn ; } -spin_unlock_irq (&bfqd->lock); -blk_mq_sched_request_inserted (rq); -spin_lock_irq (&bfqd->lock); bfqq =bfq_init_rq (rq);if (!bfqq || at_head ||blk_rq_is_passthrough (rq)) {if (at_head)
Greg Kroah-Hartman
maintainerPATCH 443/452 bfq: Remove pointless bfq_init_rq() calls
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 5f550ede5edf846ecc0067be1ba80514e6fe7f8e upstream.
We call bfq_init_rq() from request merging functions where requests we get should have already gone through bfq_init_rq() during insert and anyway we want to do anything only if the request is already tracked by BFQ. So replace calls to bfq_init_rq() with RQ_BFQQ() instead to simply skip requests untracked by BFQ. We move bfq_init_rq() call in bfq_insert_request() a bit earlier to cover request merging and thus can transfer FIFO position in case of a merge.
--- block/bfq-iosched.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
block/bfq-iosched.c +6 -6
@@ -2267,8 +2267,6 @@ static int bfq_request_merge(struct requreturn ELEVATOR_NO_MERGE ; } -static struct bfq_queue *bfq_init_rq (struct request *rq); -static void bfq_request_merged (struct request_queue *q,struct request *req,enum elv_merge type) {
@@ -2277,7 +2275,7 @@ static void bfq_request_merged(struct re blk_rq_pos(req) < blk_rq_pos(container_of(rb_prev(&req->rb_node), struct request, rb_node))) { -struct bfq_queue *bfqq =bfq_init_rq (req); +struct bfq_queue *bfqq =RQ_BFQQ (req);struct bfq_data *bfqd;struct request *prev, *next_rq;
@@ -2329,8 +2327,8 @@ static void bfq_request_merged(struct restatic void bfq_requests_merged (struct request_queue *q,struct request *rq,struct request *next) { -struct bfq_queue *bfqq =bfq_init_rq (rq), - *next_bfqq =bfq_init_rq (next); +struct bfq_queue *bfqq =RQ_BFQQ (rq), + *next_bfqq =RQ_BFQQ (next);if (!bfqq)return ;
@@ -5518,6 +5516,8 @@ static inline void bfq_update_insert_sta unsigned int cmd_flags) {}#endif /* CONFIG_BFQ_CGROUP_DEBUG */ +static struct bfq_queue *bfq_init_rq (struct request *rq); +static void bfq_insert_request (struct blk_mq_hw_ctx *hctx,struct request *rq,bool at_head) {
@@ -5532,6 +5532,7 @@ static void bfq_insert_request(struct blbfqg_stats_update_legacy_io (q, rq);#endif spin_lock_irq (&bfqd->lock); + bfqq =bfq_init_rq (rq);if (blk_mq_sched_try_insert_merge (q, rq)) {spin_unlock_irq (&bfqd->lock);return ;
@@ -5539,7 +5540,6 @@ static void bfq_insert_request(struct blblk_mq_sched_request_inserted (rq); - bfqq =bfq_init_rq (rq);if (!bfqq || at_head ||blk_rq_is_passthrough (rq)) {if (at_head)list_add (&rq->queuelist, &bfqd->dispatch);