5.15.46-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 448/667 ASoC: atmel-pdmic: Remove endianness flag on pdmic component
In reply to Greg Kroah-HartmanFrom: Charles Keepax <[email protected]>
[ Upstream commit 52857c3baa0e5ddeba7b2c84e56bb71c9674e048 ]
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-pdmic.c | 1 - 1 file changed, 1 deletion(-)
sound/soc/atmel/atmel-pdmic.c +0 -1
@@ -481,7 +481,6 @@ static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = { .num_controls = ARRAY_SIZE(atmel_pdmic_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 449/667 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 450/667 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
@@ -448,6 +448,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
@@ -363,6 +363,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 451/667 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
@@ -427,6 +428,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); }
@@ -454,6 +463,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;
@@ -465,6 +478,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 452/667 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
@@ -403,6 +403,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)
@@ -525,15 +530,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);
@@ -576,6 +572,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 453/667 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
@@ -174,7 +174,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)*/ 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 454/667 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),
@@ -243,21 +284,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
@@ -121,11 +121,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
@@ -164,28 +168,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 455/667 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
@@ -380,13 +380,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 456/667 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 457/667 ARM: dts: at91: sama7g5: remove interrupt-parent from gic node
In reply to Greg Kroah-HartmanFrom: Eugen Hristev <[email protected]>
[ Upstream commit b7e86ef7afd128577ff7bb0db0ae82d27d7ed7ad ]
interrupt-parent is not to be used as a boolean property.
It is already present in the DT in the proper way it's supposed to be used:
interrupt-parent = <&gic>;
This is also reported by dtbs_check:arch/arm/boot/dts/at91-sama7g5ek.dtb: interrupt-controller@e8c11000: interrupt-parent: True is not of type 'array'
From schema: /.local/lib/python3.8/site-packages/dtschema/schemas/interrupts.yaml
--- arch/arm/boot/dts/sama7g5.dtsi | 1 - 1 file changed, 1 deletion(-)
arch/arm/boot/dts/sama7g5.dtsi +0 -1
@@ -553,7 +553,6 @@ #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; - interrupt-parent; reg = <0xe8c11000 0x1000>, <0xe8c12000 0x2000>; };
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 458/667 hugetlbfs: fix hugetlbfs_statfs() locking
In reply to Greg Kroah-HartmanFrom: Mina Almasry <[email protected]>
[ Upstream commit 4b25f030ae69ba710eff587cabb4c57cb7e7a8a1 ]
After commit db71ef79b59b ("hugetlb: make free_huge_page irq safe"), the subpool lock should be locked with spin_lock_irq() and all call sites was modified as such, except for the ones in hugetlbfs_statfs().
--- fs/hugetlbfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/hugetlbfs/inode.c +2 -2
@@ -1048,12 +1048,12 @@ static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)if (sbinfo->spool) {long free_pages; -spin_lock (&sbinfo->spool->lock); +spin_lock_irq (&sbinfo->spool->lock); buf->f_blocks = sbinfo->spool->max_hpages; free_pages = sbinfo->spool->max_hpages - sbinfo->spool->used_hpages; buf->f_bavail = buf->f_bfree = free_pages; -spin_unlock (&sbinfo->spool->lock); +spin_unlock_irq (&sbinfo->spool->lock); buf->f_files = sbinfo->max_inodes; buf->f_ffree = sbinfo->free_inodes; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 459/667 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 460/667 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);
@@ -1196,7 +1201,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 461/667 PCI: microchip: Fix potential race in interrupt handling
In reply to Greg Kroah-HartmanFrom: Daire McNamara <[email protected]>
[ Upstream commit 7013654af694f6e1a2e699a6450ea50d309dd0e5 ]
Clear the MSI bit in ISTATUS_LOCAL register after reading it, but before reading and handling individual MSI bits from the ISTATUS_MSI register. This avoids a potential race where new MSI bits may be set on the ISTATUS_MSI register after it was read and be missed when the MSI bit in the ISTATUS_LOCAL register is cleared.
ISTATUS_LOCAL is a read/write/clear register; the register's bits are set when the corresponding interrupt source is activated. Each source is independent and thus multiple sources may be active simultaneously. The processor can monitor and clear status bits. If one or more ISTATUS_LOCAL interrupt sources are active, the RootPort issues an interrupt towards the processor (on the AXI domain). Bit 28 of this register reports an MSI has been received by the RootPort.
ISTATUS_MSI is a read/write/clear register. Bits 31-0 are asserted when an MSI with message number 31-0 is received by the RootPort. The processor must monitor and clear these bits.
Effectively, Bit 28 of ISTATUS_LOCAL informs the processor that an MSI has arrived at the RootPort and ISTATUS_MSI informs the processor which MSI (in the range 0 - 31) needs handling.
Reported by: Bjorn Helgaas <[email protected]>
--- drivers/pci/controller/pcie-microchip-host.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/pci/controller/pcie-microchip-host.c +1 -5
@@ -416,6 +416,7 @@ static void mc_handle_msi(struct irq_desc *desc) status =readl_relaxed (bridge_base_addr +ISTATUS_LOCAL );if (status &PM_MSI_INT_MSI_MASK ) { +writel_relaxed (status &PM_MSI_INT_MSI_MASK , bridge_base_addr +ISTATUS_LOCAL ); status =readl_relaxed (bridge_base_addr +ISTATUS_MSI );for_each_set_bit (bit, &status, msi->num_vectors) { ret =generic_handle_domain_irq (msi->dev_domain, bit);
@@ -432,13 +433,8 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)void __iomem *bridge_base_addr = port->axi_base_addr +MC_PCIE_BRIDGE_ADDR ;u32 bitpos = data->hwirq; -unsigned long status;writel_relaxed (BIT (bitpos), bridge_base_addr +ISTATUS_MSI ); - status =readl_relaxed (bridge_base_addr +ISTATUS_MSI ); -if (!status) -writel_relaxed (BIT (PM_MSI_INT_MSI_SHIFT ), - bridge_base_addr +ISTATUS_LOCAL ); }static void mc_compose_msi_msg (struct irq_data *data,struct msi_msg *msg)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 462/667 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 463/667 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 464/667 powerpc/perf: Fix the threshold compare group constraint for power10
In reply to Greg Kroah-HartmanFrom: Kajol Jain <[email protected]>
[ Upstream commit 505d31650ba96d6032313480fdb566d289a4698c ]
Thresh compare bits for a event is used to program thresh compare field in Monitor Mode Control Register A (MMCRA: 8-18 bits for power10). When scheduling events as a group, all events in that group should match value in threshold bits. 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 in group_constraint function.
Patch also fixes the p10_thresh_cmp_val function to return -1, incase threshold bits are not valid and changes corresponding check in is_thresh_cmp_valid function to return false only when the thresh_cmp value is less then 0.
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 (3534401e0) and PM_THRESH_MET (34340101ec) is expected to fail as both event request different thresh control bits.
Result before the patch changes:
[command]# perf stat -e "{r35340401e0,r34340101ec}" sleep 1
Performance counter stats for 'sleep 1':
8,482 r35340401e0
0 r34340101ec
1.001474838 seconds time elapsed
0.001145000 seconds user
0.000000000 seconds sysResult after the patch changes:
[command]# perf stat -e "{r35340401e0,r34340101ec}" sleep 1
Performance counter stats for 'sleep 1':
<not counted> r35340401e0
<not supported> r34340101ec
1.001499607 seconds time elapsed
0.000204000 seconds user
0.000760000 seconds sys--- arch/powerpc/perf/isa207-common.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/powerpc/perf/isa207-common.c +5 -4
@@ -108,7 +108,7 @@ static void mmcra_sdar_mode(u64 event, unsigned long *mmcra) *mmcra |=MMCRA_SDAR_MODE_TLB ; } -static u64 p10_thresh_cmp_val (u64 value) +static int p10_thresh_cmp_val (u64 value) {int exp =0 ;u64 result = value;
@@ -139,7 +139,7 @@ static u64 p10_thresh_cmp_val(u64 value)* exponent is also zero. */ if (!(value &0xC0 ) && exp) - result =0 ; + result =-1 ;else result = (exp <<8 ) | value; }
@@ -187,7 +187,7 @@ static bool is_thresh_cmp_valid(u64 event)unsigned int cmp, exp;if (cpu_has_feature (CPU_FTR_ARCH_31 )) -return p10_thresh_cmp_val (event) !=0 ; +return p10_thresh_cmp_val (event) >=0 ;/* * Check the mantissa upper two bits are not zero, unless the
@@ -456,7 +456,8 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp, value |=CNST_THRESH_CTL_SEL_VAL (event >>EVENT_THRESH_SHIFT ); mask |= p10_CNST_THRESH_CMP_MASK; value |=p10_CNST_THRESH_CMP_VAL (p10_thresh_cmp_val (event_config1)); - } + }else if (event_is_threshold (event)) +return -1 ; }else if (cpu_has_feature (CPU_FTR_ARCH_300 )) {if (event_is_threshold (event) &&is_thresh_cmp_valid (event)) { mask |=CNST_THRESH_MASK ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 465/667 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
@@ -462,7 +462,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 466/667 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 467/667 powerpc/xive: Add some error handling code to xive_spapr_init()
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit e414e2938ee26e734f19e92a60cd090ebaff37e6 ]
'xive_irq_bitmap_add()' can return -ENOMEM.
In this case, we should free the memory already allocated and return 'false' to the caller.
Also add an error path which undoes the 'tima = ioremap(...)'
--- arch/powerpc/sysdev/xive/spapr.c | 36 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-)
arch/powerpc/sysdev/xive/spapr.c +28 -8
@@ -67,6 +67,17 @@ static int xive_irq_bitmap_add(int base, int count)return 0 ; } +static void xive_irq_bitmap_remove_all (void ) +{ +struct xive_irq_bitmap *xibm, *tmp; + +list_for_each_entry_safe (xibm, tmp, &xive_irq_bitmaps, list) { +list_del (&xibm->list); +kfree (xibm->bitmap); +kfree (xibm); + } +} +static int __xive_irq_bitmap_alloc (struct xive_irq_bitmap *xibm) {int irq;
@@ -803,7 +814,7 @@ bool __init xive_spapr_init(void)u32 val;u32 len;const __be32 *reg; -int i; +int i, err;if (xive_spapr_disabled ())return false;
@@ -828,23 +839,26 @@ bool __init xive_spapr_init(void) }if (!xive_get_max_prio (&max_prio)) -return false; + goto err_unmap;/* Feed the IRQ number allocator with the ranges given in the DT */ reg =of_get_property (np,"ibm,xive-lisn-ranges" , &len);if (!reg) {pr_err ("Failed to read 'ibm,xive-lisn-ranges' property\n" ); -return false; + goto err_unmap; }if (len % (2 *sizeof (u32)) !=0 ) {pr_err ("invalid 'ibm,xive-lisn-ranges' property\n" ); -return false; + goto err_unmap; } -for (i =0 ; i < len / (2 *sizeof (u32)); i++, reg +=2 ) -xive_irq_bitmap_add (be32_to_cpu (reg[0 ]), -be32_to_cpu (reg[1 ])); +for (i =0 ; i < len / (2 *sizeof (u32)); i++, reg +=2 ) { + err =xive_irq_bitmap_add (be32_to_cpu (reg[0 ]), +be32_to_cpu (reg[1 ])); +if (err <0 ) + goto err_mem_free; + }/* Iterate the EQ sizes and pick one */ of_property_for_each_u32 (np,"ibm,xive-eq-sizes" , prop, reg, val) {
@@ -855,10 +869,16 @@ bool __init xive_spapr_init(void)/* Initialize XIVE core with our backend */ if (!xive_core_init (np, &xive_spapr_ops, tima,TM_QW1_OS , max_prio)) -return false; + goto err_mem_free;pr_info ("Using %dkB queues\n" ,1 << (xive_queue_shift -10 ));return true; + +err_mem_free: +xive_irq_bitmap_remove_all (); +err_unmap: +iounmap (tima); +return false; }machine_arch_initcall (pseries, xive_core_debug_init);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 468/667 powerpc/xive: Fix refcount leak in xive_spapr_init
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
[ Upstream commit 1d1fb9618bdd5a5fbf9a9eb75133da301d33721c ]
of_find_compatible_node() 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.
--- arch/powerpc/sysdev/xive/spapr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
arch/powerpc/sysdev/xive/spapr.c +5 -2
@@ -830,12 +830,12 @@ bool __init xive_spapr_init(void)/* Resource 1 is the OS ring TIMA */ if (of_address_to_resource (np,1 , &r)) {pr_err ("Failed to get thread mgmnt area resource\n" ); -return false; + goto err_put; } tima =ioremap (r.start,resource_size (&r));if (!tima) {pr_err ("Failed to map thread mgmnt area\n" ); -return false; + goto err_put; }if (!xive_get_max_prio (&max_prio))
@@ -871,6 +871,7 @@ bool __init xive_spapr_init(void)if (!xive_core_init (np, &xive_spapr_ops, tima,TM_QW1_OS , max_prio)) goto err_mem_free; +of_node_put (np);pr_info ("Using %dkB queues\n" ,1 << (xive_queue_shift -10 ));return true;
@@ -878,6 +879,8 @@ bool __init xive_spapr_init(void)xive_irq_bitmap_remove_all (); err_unmap:iounmap (tima); +err_put: +of_node_put (np);return false; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 469/667 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 470/667 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 471/667 nfsd: destroy percpu stats counters after reply cache shutdown
In reply to Greg Kroah-HartmanFrom: Julian Schroeder <[email protected]>
[ Upstream commit fd5e363eac77ef81542db77ddad0559fa0f9204e ]
Upon nfsd shutdown any pending DRC cache is freed. DRC cache use is tracked via a percpu counter. In the current code the percpu counter is destroyed before. If any pending cache is still present, percpu_counter_add is called with a percpu counter==NULL. This causes a kernel crash.
The solution is to destroy the percpu counter after the cache is freed.
--- fs/nfsd/nfscache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfscache.c +1 -1
@@ -212,7 +212,6 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn)struct svc_cacherep *rp;unsigned int i; -nfsd_reply_cache_stats_destroy (nn);unregister_shrinker (&nn->nfsd_reply_cache_shrinker);for (i =0 ; i < nn->drc_hashsize; i++) {
@@ -223,6 +222,7 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) rp, nn); } } +nfsd_reply_cache_stats_destroy (nn);kvfree (nn->drc_hashtbl); nn->drc_hashtbl =NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 472/667 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 473/667 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
@@ -1288,11 +1288,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 474/667 KVM: LAPIC: Drop pending LAPIC timer injection when canceling the timer
In reply to Greg Kroah-HartmanFrom: Wanpeng Li <[email protected]>
[ Upstream commit 619f51da097952194a5d4d6a6c5f9ef3b9d1b25a ]
The timer is disarmed when switching between TSC deadline and other modes; however, the pending timer is still in-flight, so let's accurately remove any traces of the previous mode.
--- arch/x86/kvm/lapic.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/kvm/lapic.c +1 -0
@@ -1506,6 +1506,7 @@ static void cancel_apic_timer(struct kvm_lapic *apic)if (apic->lapic_timer.hv_timer_in_use)cancel_hv_timer (apic);preempt_enable (); +atomic_set (&apic->lapic_timer.pending,0 ); }static void apic_update_lvtt (struct kvm_lapic *apic)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 475/667 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 476/667 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
@@ -437,11 +437,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 477/667 f2fs: support fault injection for dquot_initialize()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
[ Upstream commit 10a26878564f27327b12e8f4b4d8d7b43065fae5 ]
This patch adds a new function f2fs_dquot_initialize() to wrap dquot_initialize(), and it supports to inject fault into f2fs_dquot_initialize() to simulate inner failure occurs in dquot_initialize().
Usage:
a) echo 65536 > /sys/fs/f2fs/<dev>/inject_type or
b) mount -o fault_type=65536 <dev> <mountpoint>
--- Documentation/filesystems/f2fs.rst | 1 + fs/f2fs/checkpoint.c | 2 +- fs/f2fs/f2fs.h | 2 ++ fs/f2fs/file.c | 6 +++--- fs/f2fs/inline.c | 2 +- fs/f2fs/inode.c | 2 +- fs/f2fs/namei.c | 30 +++++++++++++++--------------- fs/f2fs/recovery.c | 6 +++--- fs/f2fs/super.c | 16 ++++++++++++++++ fs/f2fs/verity.c | 2 +- fs/f2fs/xattr.c | 2 +- 11 files changed, 45 insertions(+), 26 deletions(-)
Documentation/filesystems/f2fs.rst +1 -0
@@ -197,6 +197,7 @@ fault_type=%d Support configuring fault injection type, should be FAULT_DISCARD 0x000002000 FAULT_WRITE_IO 0x000004000 FAULT_SLAB_ALLOC 0x000008000 + FAULT_DQUOT_INIT 0x000010000 =================== =========== mode=%s Control block allocation mode which supports "adaptive" and "lfs". In "lfs" mode, there should be no random
fs/f2fs/checkpoint.c +1 -1
@@ -653,7 +653,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)return PTR_ERR (inode); } - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err) {iput (inode); goto err_out;
fs/f2fs/f2fs.h +2 -0
@@ -55,6 +55,7 @@ enum {FAULT_DISCARD ,FAULT_WRITE_IO ,FAULT_SLAB_ALLOC , +FAULT_DQUOT_INIT , FAULT_MAX, };
@@ -3375,6 +3376,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)*/ int f2fs_inode_dirtied (struct inode *inode,bool sync);void f2fs_inode_synced (struct inode *inode); +int f2fs_dquot_initialize (struct inode *inode);int f2fs_enable_quota_files (struct f2fs_sb_info *sbi,bool rdonly);int f2fs_quota_sync (struct super_block *sb,int type);loff_t max_file_blocks (struct inode *inode);
fs/f2fs/file.c +3 -3
@@ -786,7 +786,7 @@ int f2fs_truncate(struct inode *inode)return -EIO ; } - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err;
@@ -916,7 +916,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,return err;if (is_quota_modification (inode, attr)) { - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err; }
@@ -3023,7 +3023,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid) }f2fs_put_page (ipage,1 ); - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err;
fs/f2fs/inline.c +1 -1
@@ -192,7 +192,7 @@ int f2fs_convert_inline_inode(struct inode *inode) f2fs_hw_is_readonly(sbi) || f2fs_readonly(sbi->sb))return 0 ; - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err;
fs/f2fs/inode.c +1 -1
@@ -759,7 +759,7 @@ void f2fs_evict_inode(struct inode *inode)if (inode->i_nlink ||is_bad_inode (inode)) goto no_delete; - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err) { err =0 ;set_sbi_flag (sbi,SBI_QUOTA_NEED_REPAIR );
fs/f2fs/namei.c +15 -15
@@ -74,7 +74,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)if (err) goto fail_drop; - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err) goto fail_drop;
@@ -345,7 +345,7 @@ static int f2fs_create(struct user_namespace *mnt_userns, struct inode *dir,if (!f2fs_is_checkpoint_ready (sbi))return -ENOSPC ; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -404,7 +404,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, F2FS_I(old_dentry->d_inode)->i_projid)))return -EXDEV ; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -460,7 +460,7 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)return 0 ; } - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -598,10 +598,10 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) goto fail; } - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err) goto fail; - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err) goto fail;
@@ -675,7 +675,7 @@ static int f2fs_symlink(struct user_namespace *mnt_userns, struct inode *dir,if (err)return err; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -746,7 +746,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,if (unlikely (f2fs_cp_error (sbi)))return -EIO ; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -803,7 +803,7 @@ static int f2fs_mknod(struct user_namespace *mnt_userns, struct inode *dir,if (!f2fs_is_checkpoint_ready (sbi))return -ENOSPC ; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -841,7 +841,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,struct inode *inode;int err; - err =dquot_initialize (dir); + err =f2fs_dquot_initialize (dir);if (err)return err;
@@ -965,16 +965,16 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,return err; } - err =dquot_initialize (old_dir); + err =f2fs_dquot_initialize (old_dir);if (err) goto out; - err =dquot_initialize (new_dir); + err =f2fs_dquot_initialize (new_dir);if (err) goto out;if (new_inode) { - err =dquot_initialize (new_inode); + err =f2fs_dquot_initialize (new_inode);if (err) goto out; }
@@ -1138,11 +1138,11 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, F2FS_I(new_dentry->d_inode)->i_projid)))return -EXDEV ; - err =dquot_initialize (old_dir); + err =f2fs_dquot_initialize (old_dir);if (err) goto out; - err =dquot_initialize (new_dir); + err =f2fs_dquot_initialize (new_dir);if (err) goto out;
fs/f2fs/recovery.c +3 -3
@@ -81,7 +81,7 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,if (IS_ERR (inode))return ERR_CAST (inode); - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err) goto err_out;
@@ -203,7 +203,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage, goto out_put; } - err =dquot_initialize (einode); + err =f2fs_dquot_initialize (einode);if (err) {iput (einode); goto out_put;
@@ -508,7 +508,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,if (IS_ERR (inode))return PTR_ERR (inode); - ret =dquot_initialize (inode); + ret =f2fs_dquot_initialize (inode);if (ret) {iput (inode);return ret;
fs/f2fs/super.c +16 -0
@@ -58,6 +58,7 @@ const char *f2fs_fault_name[FAULT_MAX] = { [FAULT_DISCARD] = "discard error", [FAULT_WRITE_IO] = "write IO error", [FAULT_SLAB_ALLOC] = "slab alloc", + [FAULT_DQUOT_INIT] = "dquot initialize", }; void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
@@ -2535,6 +2536,16 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type,return len - towrite; } +int f2fs_dquot_initialize (struct inode *inode) +{ +if (time_to_inject (F2FS_I_SB (inode),FAULT_DQUOT_INIT )) { +f2fs_show_injection_info (F2FS_I_SB (inode),FAULT_DQUOT_INIT ); +return -ESRCH ; + } + +return dquot_initialize (inode); +} +static struct dquot **f2fs_get_dquots (struct inode *inode) {return F2FS_I (inode)->i_dquot;
@@ -2919,6 +2930,11 @@ static const struct quotactl_ops f2fs_quotactl_ops = { .get_nextdqblk = dquot_get_next_dqblk, };#else +int f2fs_dquot_initialize (struct inode *inode) +{ +return 0 ; +} +int f2fs_quota_sync (struct super_block *sb,int type) {return 0 ;
fs/f2fs/verity.c +1 -1
@@ -136,7 +136,7 @@ static int f2fs_begin_enable_verity(struct file *filp)* here and not rely on ->open() doing it. This must be done before * evicting the inline data. */ - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err;
fs/f2fs/xattr.c +1 -1
@@ -782,7 +782,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,if (!f2fs_is_checkpoint_ready (sbi))return -ENOSPC ; - err =dquot_initialize (inode); + err =f2fs_dquot_initialize (inode);if (err)return err;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 478/667 f2fs: fix to do sanity check on inline_dots inode
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
[ Upstream commit 12662d19467b391b5b509ac5e9ab4f583c6dde16 ]
As Wenqing reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215765
It will cause a kernel panic with steps:
- mkdir mnt
- mount tmp40.img mnt
- ls mnt
folio_mark_dirty+0x33/0x50 f2fs_add_regular_entry+0x541/0xad0 [f2fs] f2fs_add_dentry+0x6c/0xb0 [f2fs] f2fs_do_add_link+0x182/0x230 [f2fs] __recover_dot_dentries+0x2d6/0x470 [f2fs] f2fs_lookup+0x5af/0x6a0 [f2fs] __lookup_slow+0xac/0x200 lookup_slow+0x45/0x70 walk_component+0x16c/0x250 path_lookupat+0x8b/0x1f0 filename_lookup+0xef/0x250 user_path_at_empty+0x46/0x70 vfs_statx+0x98/0x190 __do_sys_newlstat+0x41/0x90 __x64_sys_newlstat+0x1a/0x30 do_syscall_64+0x37/0xb0 entry_SYSCALL_64_after_hwframe+0x44/0xae
The root cause is for special file: e.g. character, block, fifo or socket file, f2fs doesn't assign address space operations pointer array for mapping->a_ops field, so, in a fuzzed image, if inline_dots flag was tagged in special file, during lookup(), when f2fs runs into __recover_dot_dentries(), it will cause NULL pointer access once f2fs_add_regular_entry() calls a_ops->set_dirty_page().
--- fs/f2fs/namei.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/f2fs/namei.c +7 -0
@@ -460,6 +460,13 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)return 0 ; } +if (!S_ISDIR (dir->i_mode)) { +f2fs_err (sbi,"inconsistent inode status, skip recovering inline_dots inode (ino:%lu, i_mode:%u, pino:%u)" , + dir->i_ino, dir->i_mode, pino); +set_sbi_flag (sbi,SBI_NEED_FSCK ); +return -ENOTDIR ; + } + err =f2fs_dquot_initialize (dir);if (err)return err;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 479/667 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, !page_private_atomic (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 480/667 iommu/amd: Enable swiotlb in all cases
In reply to Greg Kroah-HartmanFrom: Mario Limonciello <[email protected]>
[ Upstream commit 121660bba631104154b7c15e88f208c48c8c3297 ]
Previously the AMD IOMMU would only enable SWIOTLB in certain circumstances:
* IOMMU in passthrough mode
* SME enabled
This logic however doesn't work when an untrusted device is plugged in that doesn't do page aligned DMA transactions. The expectation is that a bounce buffer is used for those transactions.
This fails like this:
swiotlb buffer is full (sz: 4096 bytes), total 0 (slots), used 0 (slots)
That happens because the bounce buffers have been allocated, followed by freed during startup but the bounce buffering code expects that all IOMMUs have left it enabled.
Remove the criteria to set up bounce buffers on AMD systems to ensure they're always available for supporting untrusted devices.
--- drivers/iommu/amd/iommu.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/iommu/amd/iommu.c +0 -7
@@ -1816,17 +1816,10 @@ void amd_iommu_domain_update(struct protection_domain *domain)amd_iommu_domain_flush_complete (domain); } -static void __init amd_iommu_init_dma_ops (void ) -{ - swiotlb = (iommu_default_passthrough () || sme_me_mask) ?1 :0 ; -} -int __init amd_iommu_init_api (void ) {int err; -amd_iommu_init_dma_ops (); - err =bus_set_iommu (&pci_bus_type, &amd_iommu_ops);if (err)return err;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 481/667 iommu/mediatek: Fix 2 HW sharing pgtable issue
In reply to Greg Kroah-HartmanFrom: Yong Wu <[email protected]>
[ Upstream commit 645b87c190c959e9bb4f216b8c4add4ee880451a ]
In the commit 4f956c97d26b ("iommu/mediatek: Move domain_finalise into attach_device"), I overlooked the sharing pgtable case. After that commit, the "data" in the mtk_iommu_domain_finalise always is the data of the current IOMMU HW. Fix this for the sharing pgtable case.
Only affect mt2712 which is the only SoC that share pgtable currently.
--- drivers/iommu/mtk_iommu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/iommu/mtk_iommu.c +5 -2
@@ -451,7 +451,7 @@ static void mtk_iommu_domain_free(struct iommu_domain *domain)static int mtk_iommu_attach_device (struct iommu_domain *domain,struct device *dev) { -struct mtk_iommu_data *data =dev_iommu_priv_get (dev); +struct mtk_iommu_data *data =dev_iommu_priv_get (dev), *frstdata;struct mtk_iommu_domain *dom =to_mtk_domain (domain);struct device *m4udev = data->dev;int ret, domid;
@@ -461,7 +461,10 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,return domid;if (!dom->data) { -if (mtk_iommu_domain_finalise (dom, data, domid)) +/* Data is in the frstdata in sharing pgtable case. */ + frstdata =mtk_iommu_get_m4u_data (); + +if (mtk_iommu_domain_finalise (dom, frstdata, domid))return -ENODEV ; dom->data = data; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 482/667 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
@@ -954,8 +954,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);device_link_remove (data->smicomm_dev, &pdev->dev);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 483/667 iommu/mediatek: Remove clk_disable in mtk_iommu_remove
In reply to Greg Kroah-HartmanFrom: Yong Wu <[email protected]>
[ Upstream commit 98df772bdd1c4ce717a26289efea15cbbe4b64ed ]
After the commit b34ea31fe013 ("iommu/mediatek: Always enable the clk on resume"), the iommu clock is controlled by the runtime callback. thus remove the clk control in the mtk_iommu_remove.
Otherwise, it will warning like:
echo 14018000.iommu > /sys/bus/platform/drivers/mtk-iommu/unbind
[ 51.413044] ------------[ cut here ]------------
[ 51.413648] vpp0_smi_iommu already disabled
[ 51.414233] WARNING: CPU: 2 PID: 157 at */v5.15-rc1/kernel/mediatek/
drivers/clk/clk.c:952 clk_core_disable+0xb0/0xb8
[ 51.417174] Hardware name: MT8195V/C(ENG) (DT)
[ 51.418635] pc : clk_core_disable+0xb0/0xb8
[ 51.419177] lr : clk_core_disable+0xb0/0xb8
...
[ 51.429375] Call trace:
[ 51.429694] clk_core_disable+0xb0/0xb8
[ 51.430193] clk_core_disable_lock+0x24/0x40
[ 51.430745] clk_disable+0x20/0x30
[ 51.431189] mtk_iommu_remove+0x58/0x118
[ 51.431705] platform_remove+0x28/0x60
[ 51.432197] device_release_driver_internal+0x110/0x1f0
[ 51.432873] device_driver_detach+0x18/0x28
[ 51.433418] unbind_store+0xd4/0x108
[ 51.433886] drv_attr_store+0x24/0x38
[ 51.434363] sysfs_kf_write+0x40/0x58
[ 51.434843] kernfs_fop_write_iter+0x164/0x1e0--- drivers/iommu/mtk_iommu.c | 1 - 1 file changed, 1 deletion(-)
drivers/iommu/mtk_iommu.c +0 -1
@@ -956,7 +956,6 @@ static int mtk_iommu_remove(struct platform_device *pdev)list_del (&data->list); -clk_disable_unprepare (data->bclk);device_link_remove (data->smicomm_dev, &pdev->dev);pm_runtime_disable (&pdev->dev);devm_free_irq (&pdev->dev, data->irq, data);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 484/667 iommu/mediatek: Add mutex for m4u_group and m4u_dom in data
In reply to Greg Kroah-HartmanFrom: Yong Wu <[email protected]>
[ Upstream commit 0e5a3f2e630b28e88e018655548212ef8eb4dfcb ]
Add a mutex to protect the data in the structure mtk_iommu_data, like ->"m4u_group" ->"m4u_dom". For the internal data, we should protect it in ourselves driver. Add a mutex for this. This could be a fix for the multi-groups support.
--- drivers/iommu/mtk_iommu.c | 13 +++++++++++-- drivers/iommu/mtk_iommu.h | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-)
drivers/iommu/mtk_iommu.c +11 -2
@@ -469,15 +469,16 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, dom->data = data; } +mutex_lock (&data->mutex);if (!data->m4u_dom) {/* Initialize the M4U HW */ ret =pm_runtime_resume_and_get (m4udev);if (ret <0 ) -return ret; + goto err_unlock; ret =mtk_iommu_hw_init (data);if (ret) {pm_runtime_put (m4udev); -return ret; + goto err_unlock; } data->m4u_dom = dom; writel(dom->cfg.arm_v7s_cfg.ttbr & MMU_PT_ADDR_MASK,
@@ -485,9 +486,14 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,pm_runtime_put (m4udev); } +mutex_unlock (&data->mutex);mtk_iommu_config (data, dev, true, domid);return 0 ; + +err_unlock: +mutex_unlock (&data->mutex); +return ret; } static void mtk_iommu_detach_device(struct iommu_domain *domain,
@@ -627,6 +633,7 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev)if (domid <0 )return ERR_PTR (domid); +mutex_lock (&data->mutex); group = data->m4u_group[domid];if (!group) { group =iommu_group_alloc ();
@@ -635,6 +642,7 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) }else {iommu_group_ref_get (group); } +mutex_unlock (&data->mutex);return group; }
@@ -909,6 +917,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) }platform_set_drvdata (pdev, data); +mutex_init (&data->mutex); ret =iommu_device_sysfs_add (&data->iommu, dev,NULL ,"mtk-iommu.%pa" , &ioaddr);
drivers/iommu/mtk_iommu.h +2 -0
@@ -80,6 +80,8 @@ struct mtk_iommu_data {struct dma_iommu_mapping *mapping;/* For mtk_iommu_v1.c */ +struct mutex mutex;/* Protect m4u_group/m4u_dom above */ +struct list_head list;struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX ]; };
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 485/667 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
@@ -656,6 +656,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);
@@ -703,7 +704,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 486/667 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
@@ -580,7 +580,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 487/667 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)
@@ -547,7 +549,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 ("/" );
@@ -571,11 +572,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 ;
@@ -584,6 +585,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 488/667 iommu/arm-smmu-v3-sva: Fix mm use-after-free
In reply to Greg Kroah-HartmanFrom: Jean-Philippe Brucker <[email protected]>
[ Upstream commit cbd23144f7662b00bcde32a938c4a4057e476d68 ]
We currently call arm64_mm_context_put() without holding a reference to the mm, which can result in use-after-free. Call mmgrab()/mmdrop() to ensure the mm only gets freed after we unpinned the ASID.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +11 -2
@@ -6,6 +6,7 @@#include <linux/mm.h> #include <linux/mmu_context.h> #include <linux/mmu_notifier.h> +#include <linux/sched/mm.h> #include <linux/slab.h> #include "arm-smmu-v3.h"
@@ -96,9 +97,14 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm)struct arm_smmu_ctx_desc *cd;struct arm_smmu_ctx_desc *ret =NULL ; +/* Don't free the mm until we release the ASID */ +mmgrab (mm); + asid =arm64_mm_context_get (mm); -if (!asid) -return ERR_PTR (-ESRCH ); +if (!asid) { + err = -ESRCH ; + goto out_drop_mm; + } cd =kzalloc (sizeof (*cd),GFP_KERNEL );if (!cd) {
@@ -165,6 +171,8 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm)kfree (cd); out_put_context:arm64_mm_context_put (mm); +out_drop_mm: +mmdrop (mm);return err <0 ?ERR_PTR (err) : ret; }
@@ -173,6 +181,7 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd)if (arm_smmu_free_asid (cd)) {/* Unpin ASID */ arm64_mm_context_put (cd->mm); +mmdrop (cd->mm);kfree (cd); } }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 489/667 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 490/667 iommu/mediatek: Fix NULL pointer dereference when printing dev_name
In reply to Greg Kroah-HartmanFrom: Miles Chen <[email protected]>
[ Upstream commit de78657e16f41417da9332f09c2d67d100096939 ]
When larbdev is NULL (in the case I hit, the node is incorrectly set iommus = <&iommu NUM>), it will cause device_link_add() fail and kernel crashes when we try to print dev_name(larbdev).
Let's fail the probe if a larbdev is NULL to avoid invalid inputs from dts.
It should work for normal correct setting and avoid the crash caused by my incorrect setting.
Error log:
[ 18.189042][ T301] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000050 ... [ 18.344519][ T301] pstate: a0400005 (NzCv daif +PAN -UAO) [ 18.345213][ T301] pc : mtk_iommu_probe_device+0xf8/0x118 [mtk_iommu] [ 18.346050][ T301] lr : mtk_iommu_probe_device+0xd0/0x118 [mtk_iommu] [ 18.346884][ T301] sp : ffffffc00a5635e0 [ 18.347392][ T301] x29: ffffffc00a5635e0 x28: ffffffd44a46c1d8 [ 18.348156][ T301] x27: ffffff80c39a8000 x26: ffffffd44a80cc38 [ 18.348917][ T301] x25: 0000000000000000 x24: ffffffd44a80cc38 [ 18.349677][ T301] x23: ffffffd44e4da4c6 x22: ffffffd44a80cc38 [ 18.350438][ T301] x21: ffffff80cecd1880 x20: 0000000000000000 [ 18.351198][ T301] x19: ffffff80c439f010 x18: ffffffc00a50d0c0 [ 18.351959][ T301] x17: ffffffffffffffff x16: 0000000000000004 [ 18.352719][ T301] x15: 0000000000000004 x14: ffffffd44eb5d420 [ 18.353480][ T301] x13: 0000000000000ad2 x12: 0000000000000003 [ 18.354241][ T301] x11: 00000000fffffad2 x10: c0000000fffffad2 [ 18.355003][ T301] x9 : a0d288d8d7142d00 x8 : a0d288d8d7142d00 [ 18.355763][ T301] x7 : ffffffd44c2bc640 x6 : 0000000000000000 [ 18.356524][ T301] x5 : 0000000000000080 x4 : 0000000000000001 [ 18.357284][ T301] x3 : 0000000000000000 x2 : 0000000000000005 [ 18.358045][ T301] x1 : 0000000000000000 x0 : 0000000000000000 [ 18.360208][ T301] Hardware name: MT6873 (DT) [ 18.360771][ T301] Call trace: [ 18.361168][ T301] dump_backtrace+0xf8/0x1f0 [ 18.361737][ T301] dump_stack_lvl+0xa8/0x11c [ 18.362305][ T301] dump_stack+0x1c/0x2c [ 18.362816][ T301] mrdump_common_die+0x184/0x40c [mrdump] [ 18.363575][ T301] ipanic_die+0x24/0x38 [mrdump] [ 18.364230][ T301] atomic_notifier_call_chain+0x128/0x2b8 [ 18.364937][ T301] die+0x16c/0x568 [ 18.365394][ T301] __do_kernel_fault+0x1e8/0x214 [ 18.365402][ T301] do_page_fault+0xb8/0x678 [ 18.366934][ T301] do_translation_fault+0x48/0x64 [ 18.368645][ T301] do_mem_abort+0x68/0x148 [ 18.368652][ T301] el1_abort+0x40/0x64 [ 18.368660][ T301] el1h_64_sync_handler+0x54/0x88 [ 18.368668][ T301] el1h_64_sync+0x68/0x6c [ 18.368673][ T301] mtk_iommu_probe_device+0xf8/0x118 [mtk_iommu]
...
--- drivers/iommu/mtk_iommu.c | 6 ++++++ drivers/iommu/mtk_iommu_v1.c | 7 +++++++ 2 files changed, 13 insertions(+)
drivers/iommu/mtk_iommu.c +6 -0
@@ -586,6 +586,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)* All the ports in each a device should be in the same larbs. */ larbid =MTK_M4U_TO_LARB (fwspec->ids[0 ]); +if (larbid >=MTK_LARB_NR_MAX ) +return ERR_PTR (-EINVAL ); +for (i =1 ; i < fwspec->num_ids; i++) { larbidx =MTK_M4U_TO_LARB (fwspec->ids[i]);if (larbid != larbidx) {
@@ -595,6 +598,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) } } larbdev = data->larb_imu[larbid].dev; +if (!larbdev) +return ERR_PTR (-EINVAL ); + link =device_link_add (dev, larbdev,DL_FLAG_PM_RUNTIME |DL_FLAG_STATELESS );if (!link)
drivers/iommu/mtk_iommu_v1.c +7 -0
@@ -80,6 +80,7 @@/* MTK generation one iommu HW only support 4K size mapping */ #define MT2701_IOMMU_PAGE_SHIFT 12#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT) +#define MT2701_LARB_NR_MAX 3/* * MTK m4u support 4GB iova address space, and only support 4K page
@@ -457,6 +458,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)/* Link the consumer device with the smi-larb device(supplier) */ larbid =mt2701_m4u_to_larb (fwspec->ids[0 ]); +if (larbid >=MT2701_LARB_NR_MAX ) +return ERR_PTR (-EINVAL ); +for (idx =1 ; idx < fwspec->num_ids; idx++) { larbidx =mt2701_m4u_to_larb (fwspec->ids[idx]);if (larbid != larbidx) {
@@ -467,6 +471,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) } larbdev = data->larb_imu[larbid].dev; +if (!larbdev) +return ERR_PTR (-EINVAL ); + link =device_link_add (dev, larbdev,DL_FLAG_PM_RUNTIME |DL_FLAG_STATELESS );if (!link)
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 491/667 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
@@ -656,7 +656,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 492/667 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
@@ -369,10 +369,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 493/667 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
@@ -1419,7 +1419,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 494/667 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 495/667 NFS: Dont report ENOSPC write errors twice
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit e6005436f6cc9ed13288f936903f0151e5543485 ]
Any errors reported by the write() system call need to be cleared from the file descriptor's error tracking. The current call to nfs_wb_all() causes the error to be reported, but since it doesn't call file_check_and_advance_wb_err(), we can end up reporting the same error a second time when the application calls fsync().
Note that since Linux 4.13, the rule is that EIO may be reported for write(), but it must be reported by a subsequent fsync(), so let's just drop reporting it in write.
The check for nfs_ctx_key_to_expire() is just a duplicate to the one already in nfs_write_end(), so let's drop that too.
--- fs/nfs/file.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-)
fs/nfs/file.c +14 -20
@@ -591,18 +591,6 @@ static const struct vm_operations_struct nfs_file_vm_ops = { .page_mkwrite = nfs_vm_page_mkwrite, }; -static int nfs_need_check_write (struct file *filp,struct inode *inode, -int error) -{ -struct nfs_open_context *ctx; - - ctx =nfs_file_open_context (filp); -if (nfs_error_is_fatal_on_server (error) || -nfs_ctx_key_to_expire (ctx, inode)) -return 1 ; -return 0 ; -} -ssize_t nfs_file_write (struct kiocb *iocb,struct iov_iter *from) {struct file *file = iocb->ki_filp;
@@ -630,7 +618,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)if (iocb->ki_flags &IOCB_APPEND || iocb->ki_pos >i_size_read (inode)) { result =nfs_revalidate_file_size (inode, file);if (result) - goto out; +return result; }nfs_clear_invalid_mapping (file->f_mapping);
@@ -649,6 +637,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) written = result; iocb->ki_pos += written; +nfs_add_stats (inode,NFSIOS_NORMALWRITTENBYTES , written);if (mntflags &NFS_MOUNT_WRITE_EAGER ) { result = filemap_fdatawrite_range(file->f_mapping,
@@ -666,17 +655,22 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) } result =generic_write_sync (iocb, written);if (result <0 ) - goto out; +return result; +out:/* Return error values */ error =filemap_check_wb_err (file->f_mapping, since); -if (nfs_need_check_write (file, inode, error)) { -int err =nfs_wb_all (inode); -if (err <0 ) - result = err; +switch (error) { +default : +break ; +case -EDQUOT : +case -EFBIG : +case -ENOSPC : +nfs_wb_all (inode); + error =file_check_and_advance_wb_err (file); +if (error <0 ) + result = error; } -nfs_add_stats (inode,NFSIOS_NORMALWRITTENBYTES , written); -out:return result; out_swapfile:
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 496/667 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 497/667 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)
@@ -737,9 +733,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 498/667 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
@@ -2000,6 +2000,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;
@@ -2128,6 +2129,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 499/667 NFS: Further fixes to the writeback error handling
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit c6fd3511c3397dd9cbc6dc5d105bbedb69bf4061 ]
When we handle an error by redirtying the page, we're not corrupting the mapping, so we don't want the error to be recorded in the mapping. If the caller has specified a sync_mode of WB_SYNC_NONE, we can just return AOP_WRITEPAGE_ACTIVATE. However if we're dealing with WB_SYNC_ALL, we need to ensure that retries happen when the errors are non-fatal.
--- fs/nfs/write.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-)
fs/nfs/write.c +18 -21
@@ -601,8 +601,9 @@ static void nfs_write_error(struct nfs_page *req, int error)* Find an associated nfs write request, and prepare to flush it out * May return an error if the user signalled nfs_wait_on_request(). */ -static int nfs_page_async_flush (struct nfs_pageio_descriptor *pgio, -struct page *page) +static int nfs_page_async_flush (struct page *page, +struct writeback_control *wbc, +struct nfs_pageio_descriptor *pgio) {struct nfs_page *req;int ret =0 ;
@@ -628,11 +629,11 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,/* * Remove the problematic req upon fatal errors on the server */ -if (nfs_error_is_fatal (ret)) { -if (nfs_error_is_fatal_on_server (ret)) - goto out_launder; - }else - ret = -EAGAIN ; +if (nfs_error_is_fatal_on_server (ret)) + goto out_launder; +if (wbc->sync_mode ==WB_SYNC_NONE ) + ret =AOP_WRITEPAGE_ACTIVATE ; +redirty_page_for_writepage (wbc, page);nfs_redirty_request (req); pgio->pg_error =0 ; }else
@@ -648,15 +649,8 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,static int nfs_do_writepage (struct page *page,struct writeback_control *wbc,struct nfs_pageio_descriptor *pgio) { -int ret; -nfs_pageio_cond_complete (pgio,page_index (page)); - ret =nfs_page_async_flush (pgio, page); -if (ret == -EAGAIN ) { -redirty_page_for_writepage (wbc, page); - ret =AOP_WRITEPAGE_ACTIVATE ; - } -return ret; +return nfs_page_async_flush (page, wbc, pgio); }/*
@@ -723,12 +717,15 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) priority =wb_priority (wbc); } -nfs_pageio_init_write (&pgio, inode, priority, false, - &nfs_async_write_completion_ops); - pgio.pg_io_completion = ioc; - err =write_cache_pages (mapping, wbc, nfs_writepages_callback, &pgio); - pgio.pg_error =0 ; -nfs_pageio_complete (&pgio); +do { +nfs_pageio_init_write (&pgio, inode, priority, false, + &nfs_async_write_completion_ops); + pgio.pg_io_completion = ioc; + err =write_cache_pages (mapping, wbc, nfs_writepages_callback, + &pgio); + pgio.pg_error =0 ; +nfs_pageio_complete (&pgio); + }while (err <0 && !nfs_error_is_fatal (err));nfs_io_completion_put (ioc);if (err <0 )
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 500/667 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
@@ -758,12 +758,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 501/667 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 0x3
@@ -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 502/667 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 503/667 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 504/667 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 505/667 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 506/667 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 507/667 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
@@ -1070,8 +1070,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 */
@@ -1100,19 +1102,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);
@@ -1129,7 +1131,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 508/667 perf build: Fix btf__load_from_kernel_by_id() feature check
In reply to Greg Kroah-HartmanFrom: Jiri Olsa <[email protected]>
[ Upstream commit 73534617dfa3c4cd95fe5ffaeff5315e9ffc2de6 ]
The btf__load_from_kernel_by_id() only takes one arg, not two.
Committer notes:
I tested it just with an older libbpf, one where btf__load_from_kernel_by_id() wasn't introduced yet.
A test with a newer dynamic libbpf would fail because the btf__load_from_kernel_by_id() is there, but takes just one arg.
--- .../build/feature/test-libbpf-btf__load_from_kernel_by_id.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/build/feature/test-libbpf-btf__load_from_kernel_by_id.c +3 -2
@@ -1,7 +1,8 @@// SPDX-License-Identifier: GPL-2.0 -#include <bpf/libbpf.h> +#include <bpf/btf.h> int main (void ) { -return btf__load_from_kernel_by_id (20151128 ,NULL ); +btf__load_from_kernel_by_id (20151128 ); +return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 509/667 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
@@ -2733,9 +2733,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,
@@ -2765,6 +2763,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 510/667 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
@@ -604,7 +604,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 511/667 video: fbdev: vesafb: Fix a use-after-free due early fb_info cleanup
In reply to Greg Kroah-HartmanFrom: Javier Martinez Canillas <[email protected]>
[ Upstream commit acde4003efc16480375543638484d8f13f2e99a3 ]
Commit b3c9a924aab6 ("fbdev: vesafb: Cleanup fb_info in .fb_destroy rather than .remove") fixed a use-after-free error due the vesafb driver freeing the fb_info in the .remove handler instead of doing it in .fb_destroy.
This can happen if the .fb_destroy callback is executed after the .remove callback, since the former tries to access a pointer freed by the latter.
But that change didn't take into account that another possible scenario is that .fb_destroy is called before the .remove callback. For example, if no process has the fbdev chardev opened by the time the driver is removed.
If that's the case, fb_info will be freed when unregister_framebuffer() is called, making the fb_info pointer accessed in vesafb_remove() after that to no longer be valid.
To prevent that, move the expression containing the info->par to happen before the unregister_framebuffer() function call.
--- drivers/video/fbdev/vesafb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/video/fbdev/vesafb.c +3 -2
@@ -490,11 +490,12 @@ static int vesafb_remove(struct platform_device *pdev) {struct fb_info *info =platform_get_drvdata (pdev); -/* vesafb_destroy takes care of info cleanup */ -unregister_framebuffer (info);if (((struct vesafb_par *)(info->par))->region)release_region (0x3c0 ,32 ); +/* vesafb_destroy takes care of info cleanup */ +unregister_framebuffer (info); +return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 512/667 NFS: Always initialise fattr->label in nfs_fattr_alloc()
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit d4a95a7e5a4d3b68b26f70668cf77324a11b5718 ]
We're about to add a check in nfs_free_fattr() for whether or not the label is non-zero.
--- fs/nfs/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfs/inode.c +3 -1
@@ -1581,8 +1581,10 @@ struct nfs_fattr *nfs_alloc_fattr(void)struct nfs_fattr *fattr; fattr =kmalloc (sizeof (*fattr),GFP_NOFS ); -if (fattr !=NULL ) +if (fattr !=NULL ) {nfs_fattr_init (fattr); + fattr->label =NULL ; + }return fattr; }EXPORT_SYMBOL_GPL (nfs_alloc_fattr);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 513/667 NFS: Create a new nfs_alloc_fattr_with_label() function
In reply to Greg Kroah-HartmanFrom: Anna Schumaker <[email protected]>
[ Upstream commit d755ad8dc752d44545613ea04d660aed674e540d ]
For creating fattrs with the label field already allocated for us. I also update nfs_free_fattr() to free the label in the end.
--- fs/nfs/getroot.c | 17 ++++++----------- fs/nfs/inode.c | 17 +++++++++++++++++ fs/nfs/internal.h | 9 --------- include/linux/nfs_fs.h | 13 +++++++++++++ 4 files changed, 36 insertions(+), 20 deletions(-)
fs/nfs/getroot.c +6 -11
@@ -80,18 +80,15 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc) goto out;/* get the actual root for this mount */ - fsinfo.fattr =nfs_alloc_fattr (); + fsinfo.fattr =nfs_alloc_fattr_with_label (server);if (fsinfo.fattr ==NULL ) goto out_name; - fsinfo.fattr->label =nfs4_label_alloc (server,GFP_KERNEL ); -if (IS_ERR (fsinfo.fattr->label)) - goto out_fattr; error = server->nfs_client->rpc_ops->getroot (server, ctx->mntfh, &fsinfo);if (error <0 ) {dprintk ("nfs_get_root: getattr error = %d\n" , -error);nfs_errorf (fc,"NFS: Couldn't getattr on root" ); - goto out_label; + goto out_fattr; } inode =nfs_fhget (s, ctx->mntfh, fsinfo.fattr,NULL );
@@ -99,12 +96,12 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)dprintk ("nfs_get_root: get root inode failed\n" ); error =PTR_ERR (inode);nfs_errorf (fc,"NFS: Couldn't get root inode" ); - goto out_label; + goto out_fattr; } error =nfs_superblock_set_dummy_root (s, inode);if (error !=0 ) - goto out_label; + goto out_fattr;/* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already
@@ -115,7 +112,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)dprintk ("nfs_get_root: get root dentry failed\n" ); error =PTR_ERR (root);nfs_errorf (fc,"NFS: Couldn't get root dentry" ); - goto out_label; + goto out_fattr; }security_d_instantiate (root, inode);
@@ -154,8 +151,6 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)nfs_setsecurity (inode, fsinfo.fattr, fsinfo.fattr->label); error =0 ; -out_label: -nfs4_label_free (fsinfo.fattr->label); out_fattr:nfs_free_fattr (fsinfo.fattr); out_name:
@@ -165,5 +160,5 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc) error_splat_root:dput (fc->root); fc->root =NULL ; - goto out_label; + goto out_fattr; }
fs/nfs/inode.c +17 -0
@@ -1589,6 +1589,23 @@ struct nfs_fattr *nfs_alloc_fattr(void) }EXPORT_SYMBOL_GPL (nfs_alloc_fattr); +struct nfs_fattr *nfs_alloc_fattr_with_label (struct nfs_server *server) +{ +struct nfs_fattr *fattr =nfs_alloc_fattr (); + +if (!fattr) +return NULL ; + + fattr->label =nfs4_label_alloc (server,GFP_NOFS ); +if (IS_ERR (fattr->label)) { +kfree (fattr); +return NULL ; + } + +return fattr; +} +EXPORT_SYMBOL_GPL (nfs_alloc_fattr_with_label); +struct nfs_fh *nfs_alloc_fhandle (void ) {struct nfs_fh *fh;
fs/nfs/internal.h +0 -9
@@ -351,14 +351,6 @@ nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)return dst; } -static inline void nfs4_label_free (struct nfs4_label *label) -{ -if (label) { -kfree (label->label); -kfree (label); - } -return ; -}static inline void nfs_zap_label_cache_locked (struct nfs_inode *nfsi) {
@@ -367,7 +359,6 @@ static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) }#else static inline struct nfs4_label *nfs4_label_alloc (struct nfs_server *server,gfp_t flags) {return NULL ; } -static inline void nfs4_label_free (void *label) {}static inline void nfs_zap_label_cache_locked (struct nfs_inode *nfsi) { }
include/linux/nfs_fs.h +13 -0
@@ -421,9 +421,22 @@ extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr);extern unsigned long nfs_inc_attr_generation_counter (void );extern struct nfs_fattr *nfs_alloc_fattr (void ); +extern struct nfs_fattr *nfs_alloc_fattr_with_label (struct nfs_server *server); + +static inline void nfs4_label_free (struct nfs4_label *label) +{ +#ifdef CONFIG_NFS_V4_SECURITY_LABEL +if (label) { +kfree (label->label); +kfree (label); + } +#endif +}static inline void nfs_free_fattr (const struct nfs_fattr *fattr) { +if (fattr) +nfs4_label_free (fattr->label);kfree (fattr); }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 514/667 NFS: Convert GFP_NOFS to GFP_KERNEL
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
[ Upstream commit da48f267f90d9dc9f930fd9a67753643657b404f ]
Assume that sections that should not re-enter the filesystem are already protected with memalloc_nofs_save/restore call, so relax those GFP_NOFS instances which might be used by other contexts.
--- fs/nfs/inode.c | 6 +++--- fs/nfs/nfs4proc.c | 15 +++++++-------- fs/nfs/nfs4state.c | 2 +- fs/nfs/pnfs.c | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-)
fs/nfs/inode.c +3 -3
@@ -1580,7 +1580,7 @@ struct nfs_fattr *nfs_alloc_fattr(void) {struct nfs_fattr *fattr; - fattr =kmalloc (sizeof (*fattr),GFP_NOFS ); + fattr =kmalloc (sizeof (*fattr),GFP_KERNEL );if (fattr !=NULL ) {nfs_fattr_init (fattr); fattr->label =NULL ;
@@ -1596,7 +1596,7 @@ struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server)if (!fattr)return NULL ; - fattr->label =nfs4_label_alloc (server,GFP_NOFS ); + fattr->label =nfs4_label_alloc (server,GFP_KERNEL );if (IS_ERR (fattr->label)) {kfree (fattr);return NULL ;
@@ -1610,7 +1610,7 @@ struct nfs_fh *nfs_alloc_fhandle(void) {struct nfs_fh *fh; - fh =kmalloc (sizeof (struct nfs_fh ),GFP_NOFS ); + fh =kmalloc (sizeof (struct nfs_fh ),GFP_KERNEL );if (fh !=NULL ) fh->size =0 ;return fh;
fs/nfs/nfs4proc.c +7 -8
@@ -5900,7 +5900,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu buflen = server->rsize; npages =DIV_ROUND_UP (buflen,PAGE_SIZE ) +1 ; - pages =kmalloc_array (npages,sizeof (struct page *),GFP_NOFS ); + pages =kmalloc_array (npages,sizeof (struct page *),GFP_KERNEL );if (!pages)return -ENOMEM ;
@@ -6621,7 +6621,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, };int status =0 ; - data =kzalloc (sizeof (*data),GFP_NOFS ); + data =kzalloc (sizeof (*data),GFP_KERNEL );if (data ==NULL )return -ENOMEM ;
@@ -6810,7 +6810,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,struct nfs4_state *state = lsp->ls_state;struct inode *inode = state->inode; - p =kzalloc (sizeof (*p),GFP_NOFS ); + p =kzalloc (sizeof (*p),GFP_KERNEL );if (p ==NULL )return NULL ; p->arg.fh =NFS_FH (inode);
@@ -7221,8 +7221,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fdprintk ("%s: begin!\n" , __func__); data =nfs4_alloc_lockdata (fl,nfs_file_open_context (fl->fl_file), - fl->fl_u.nfs4_fl.owner, - recovery_type ==NFS_LOCK_NEW ?GFP_KERNEL :GFP_NOFS ); + fl->fl_u.nfs4_fl.owner,GFP_KERNEL );if (data ==NULL )return -ENOMEM ;if (IS_SETLKW (cmd))
@@ -7645,7 +7644,7 @@ nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)if (server->nfs_client->cl_mvops->minor_version !=0 )return ; - data =kmalloc (sizeof (*data),GFP_NOFS ); + data =kmalloc (sizeof (*data),GFP_KERNEL );if (!data)return ; data->lsp = lsp;
@@ -9322,7 +9321,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, goto out_err; ret =ERR_PTR (-ENOMEM ); - calldata =kzalloc (sizeof (*calldata),GFP_NOFS ); + calldata =kzalloc (sizeof (*calldata),GFP_KERNEL );if (calldata ==NULL ) goto out_put_clp;nfs4_init_sequence (&calldata->args, &calldata->res,0 , is_privileged);
@@ -10266,7 +10265,7 @@ static int nfs41_free_stateid(struct nfs_server *server, &task_setup.rpc_client, &msg);dprintk ("NFS call free_stateid %p\n" , stateid); - data =kmalloc (sizeof (*data),GFP_NOFS ); + data =kmalloc (sizeof (*data),GFP_KERNEL );if (!data)return -ENOMEM ; data->server = server;
fs/nfs/nfs4state.c +1 -1
@@ -821,7 +821,7 @@ static void __nfs4_close(struct nfs4_state *state,void nfs4_close_state (struct nfs4_state *state,fmode_t fmode) { -__nfs4_close (state, fmode,GFP_NOFS ,0 ); +__nfs4_close (state, fmode,GFP_KERNEL ,0 ); }void nfs4_close_sync (struct nfs4_state *state,fmode_t fmode)
fs/nfs/pnfs.c +2 -2
@@ -1244,7 +1244,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo,int status =0 ; *pcred =NULL ; - lrp =kzalloc (sizeof (*lrp),GFP_NOFS ); + lrp =kzalloc (sizeof (*lrp),GFP_KERNEL );if (unlikely (lrp ==NULL )) { status = -ENOMEM ;spin_lock (&ino->i_lock);
@@ -3263,7 +3263,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void) {struct nfs4_threshold *thp; - thp =kzalloc (sizeof (*thp),GFP_NOFS ); + thp =kzalloc (sizeof (*thp),GFP_KERNEL );if (!thp) {dprintk ("%s mdsthreshold allocation failed\n" , __func__);return NULL ;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 515/667 NFSv4.1 mark qualified async operations as MOVEABLE tasks
In reply to Greg Kroah-HartmanFrom: Olga Kornievskaia <[email protected]>
[ Upstream commit 118f09eda21d392e1eeb9f8a4bee044958cccf20 ]
Mark async operations such as RENAME, REMOVE, COMMIT MOVEABLE for the nfsv4.1+ sessions.
--- fs/nfs/nfs4proc.c | 26 ++++++++++++++------------ fs/nfs/pagelist.c | 3 +++ fs/nfs/unlink.c | 8 ++++++++ fs/nfs/write.c | 4 ++++ include/linux/nfs_fs_sb.h | 1 + 5 files changed, 30 insertions(+), 12 deletions(-)
fs/nfs/nfs4proc.c +14 -12
@@ -1165,7 +1165,7 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, {unsigned short task_flags =0 ; -if (server->nfs_client->cl_minorversion) +if (server->caps &NFS_CAP_MOVEABLE ) task_flags =RPC_TASK_MOVEABLE ;return nfs4_do_call_sync (clnt, server, msg, args, res, task_flags); }
@@ -2578,7 +2578,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, };int status; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (dir,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ;kref_get (&data->kref);
@@ -3761,7 +3761,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) };int status = -ENOMEM ; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ; nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
@@ -4381,7 +4381,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, };unsigned short task_flags =0 ; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (dir,NFS_CAP_MOVEABLE )) task_flags =RPC_TASK_MOVEABLE ;/* Is this is an attribute revalidation, subject to softreval? */
@@ -6617,10 +6617,13 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, .rpc_client = server->client, .rpc_message = &msg, .callback_ops = &nfs4_delegreturn_ops, - .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT | RPC_TASK_MOVEABLE, + .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, };int status =0 ; +if (nfs_server_capable (inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + data =kzalloc (sizeof (*data),GFP_KERNEL );if (data ==NULL )return -ENOMEM ;
@@ -6935,10 +6938,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, .workqueue = nfsiod_workqueue, .flags = RPC_TASK_ASYNC, }; -struct nfs_client *client = -NFS_SERVER (lsp->ls_state->inode)->nfs_client; -if (client->cl_minorversion) +if (nfs_server_capable (lsp->ls_state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ; nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
@@ -7214,9 +7215,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, };int ret; -struct nfs_client *client =NFS_SERVER (state->inode)->nfs_client; -if (client->cl_minorversion) +if (nfs_server_capable (state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ;dprintk ("%s: begin!\n" , __func__);
@@ -10414,7 +10414,8 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | NFS_CAP_POSIX_LOCK |NFS_CAP_STATEID_NFSV41 |NFS_CAP_ATOMIC_OPEN_V1 - | NFS_CAP_LGOPEN, + |NFS_CAP_LGOPEN + | NFS_CAP_MOVEABLE, .init_client = nfs41_init_client, .shutdown_client = nfs41_shutdown_client, .match_stateid = nfs41_match_stateid,
@@ -10449,7 +10450,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | NFS_CAP_LAYOUTSTATS |NFS_CAP_CLONE |NFS_CAP_LAYOUTERROR - | NFS_CAP_READ_PLUS, + |NFS_CAP_READ_PLUS + | NFS_CAP_MOVEABLE, .init_client = nfs41_init_client, .shutdown_client = nfs41_shutdown_client, .match_stateid = nfs41_match_stateid,
fs/nfs/pagelist.c +3 -0
@@ -773,6 +773,9 @@ int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, .flags = RPC_TASK_ASYNC | flags, }; +if (nfs_server_capable (hdr->inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + hdr->rw_ops->rw_initiate (hdr, &msg, rpc_ops, &task_setup_data, how); dprintk("NFS: initiated pgio call "
fs/nfs/unlink.c +8 -0
@@ -102,6 +102,10 @@ static void nfs_do_call_unlink(struct inode *inode, struct nfs_unlinkdata *data) };struct rpc_task *task;struct inode *dir =d_inode (data->dentry->d_parent); + +if (nfs_server_capable (inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; +nfs_sb_active (dir->i_sb); data->args.fh =NFS_FH (dir);nfs_fattr_init (data->res.dir_attr);
@@ -344,6 +348,10 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, }; +if (nfs_server_capable (old_dir,NFS_CAP_MOVEABLE ) && +nfs_server_capable (new_dir,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + data =kzalloc (sizeof (*data),GFP_KERNEL );if (data ==NULL )return ERR_PTR (-ENOMEM );
fs/nfs/write.c +4 -0
@@ -1684,6 +1684,10 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, .flags = RPC_TASK_ASYNC | flags, .priority = priority, }; + +if (nfs_server_capable (data->inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; +/* Set up the initial task struct. */ nfs_ops->commit_setup (data, &msg, &task_setup_data.rpc_client);trace_nfs_initiate_commit (data);
include/linux/nfs_fs_sb.h +1 -0
@@ -288,4 +288,5 @@ struct nfs_server {#define NFS_CAP_XATTR (1U << 28)#define NFS_CAP_READ_PLUS (1U << 29)#define NFS_CAP_FS_LOCATIONS (1U << 30) +#define NFS_CAP_MOVEABLE (1U << 31)#endif
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 516/667 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
@@ -2487,11 +2487,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 517/667 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
@@ -1436,11 +1436,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 518/667 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
@@ -786,8 +786,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 519/667 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
@@ -571,11 +571,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;
@@ -601,19 +600,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 520/667 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
@@ -2705,7 +2705,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
@@ -2724,7 +2725,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 521/667 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
@@ -1079,8 +1079,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
@@ -4511,7 +4511,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_VECS,
@@ -4536,8 +4536,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;if (f2fs_block_unit_discard (sbi)) {/* build discard map only one time */
@@ -4577,15 +4577,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 (f2fs_block_unit_discard (sbi)) {if (is_set_ckpt_flags (sbi,CP_TRIMMED_FLAG )) {
@@ -4607,13 +4607,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 522/667 f2fs: dont use casefolded comparison for "." and ".."
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit b5639bb4313b9d455fc9fc4768d23a5e4ca8cb9d upstream.
Tryng to rename a directory that has all following properties fails with EINVAL and triggers the 'WARN_ON_ONCE(!fscrypt_has_encryption_key(dir))' in f2fs_match_ci_name():
- The directory is casefolded
- The directory is encrypted
- The directory's encryption key is not yet set up
- The parent directory is *not* encrypted
The problem is incorrect handling of the lookup of ".." to get the parent reference to update. fscrypt_setup_filename() treats ".." (and ".") specially, as it's never encrypted. It's passed through as-is, and setting up the directory's key is not attempted. As the name isn't a no-key name, f2fs treats it as a "normal" name and attempts a casefolded comparison. That breaks the assumption of the WARN_ON_ONCE() in f2fs_match_ci_name() which assumes that for encrypted directories, casefolded comparisons only happen when the directory's key is set up.
We could just remove this WARN_ON_ONCE(). However, since casefolding is always a no-op on "." and ".." anyway, let's instead just not casefold these names. This results in the standard bytewise comparison.
--- fs/f2fs/dir.c | 3 ++- fs/f2fs/f2fs.h | 10 +++++----- fs/f2fs/hash.c | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-)
fs/f2fs/dir.c +2 -1
@@ -82,7 +82,8 @@ int f2fs_init_casefolded_name(const stru#ifdef CONFIG_UNICODE struct super_block *sb = dir->i_sb; -if (IS_CASEFOLDED (dir)) { +if (IS_CASEFOLDED (dir) && + !is_dot_dotdot (fname->usr_fname->name, fname->usr_fname->len)) { fname->cf_name.name =f2fs_kmem_cache_alloc (f2fs_cf_name_slab,GFP_NOFS , false,F2FS_SB (sb));if (!fname->cf_name.name)
fs/f2fs/f2fs.h +5 -5
@@ -488,11 +488,11 @@ struct f2fs_filename {#ifdef CONFIG_UNICODE /* * For casefolded directories: the casefolded name, but it's left NULL -* if the original name is not valid Unicode, if the directory is both -* casefolded and encrypted and its encryption key is unavailable, or if -* the filesystem is doing an internal operation where usr_fname is also -* NULL. In all these cases we fall back to treating the name as an -* opaque byte sequence. +* if the original name is not valid Unicode, if the original name is +* "." or "..", if the directory is both casefolded and encrypted and +* its encryption key is unavailable, or if the filesystem is doing an +* internal operation where usr_fname is also NULL. In all these cases +* we fall back to treating the name as an opaque byte sequence. */ struct fscrypt_str cf_name;#endif
fs/f2fs/hash.c +6 -5
@@ -91,7 +91,7 @@ static u32 TEA_hash_name(const u8 *p, si/* * Compute @fname->hash. For all directories, @fname->disk_name must be set. * For casefolded directories, @fname->usr_fname must be set, and also -* @fname->cf_name if the filename is valid Unicode. +* @fname->cf_name if the filename is valid Unicode and is not "." or "..". */ void f2fs_hash_filename (const struct inode *dir,struct f2fs_filename *fname) {
@@ -110,10 +110,11 @@ void f2fs_hash_filename(const struct ino/* * If the casefolded name is provided, hash it instead of the * on-disk name. If the casefolded name is *not* provided, that -* should only be because the name wasn't valid Unicode, so fall -* back to treating the name as an opaque byte sequence. Note -* that to handle encrypted directories, the fallback must use -* usr_fname (plaintext) rather than disk_name (ciphertext). +* should only be because the name wasn't valid Unicode or was +* "." or "..", so fall back to treating the name as an opaque +* byte sequence. Note that to handle encrypted directories, +* the fallback must use usr_fname (plaintext) rather than +* disk_name (ciphertext). */ WARN_ON_ONCE (!fname->usr_fname->name);if (fname->cf_name.name) {
Greg Kroah-Hartman
maintainerPATCH 523/667 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
@@ -1768,6 +1768,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 524/667 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
@@ -3916,6 +3916,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
@@ -276,8 +276,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 525/667 objtool: Fix objtool regression on x32 systems
In reply to Greg Kroah-HartmanFrom: Mikulas Patocka <[email protected]>
commit 22682a07acc308ef78681572e19502ce8893c4d4 upstream.
Commit c087c6e7b551 ("objtool: Fix type of reloc::addend") failed to appreciate cross building from ILP32 hosts, where 'int' == 'long' and the issue persists.
As such, use s64/int64_t/Elf64_Sxword for this field and suffer the pain that is ISO C99 printf formats for it.
--- tools/objtool/check.c | 9 +++++---- tools/objtool/elf.c | 2 +- tools/objtool/include/objtool/elf.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-)
tools/objtool/check.c +5 -4
@@ -5,6 +5,7 @@#include <string.h> #include <stdlib.h> +#include <inttypes.h> #include <arch/elf.h> #include <objtool/builtin.h>
@@ -393,12 +394,12 @@ static int add_dead_ends(struct objtool_else if (reloc->addend == reloc->sym->sec->sh.sh_size) { insn =find_last_insn (file, reloc->sym->sec);if (!insn) { -WARN ("can't find unreachable insn at %s+0x%lx" , +WARN ("can't find unreachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; } }else { -WARN ("can't find unreachable insn at %s+0x%lx" , +WARN ("can't find unreachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; }
@@ -428,12 +429,12 @@ reachable:else if (reloc->addend == reloc->sym->sec->sh.sh_size) { insn =find_last_insn (file, reloc->sym->sec);if (!insn) { -WARN ("can't find reachable insn at %s+0x%lx" , +WARN ("can't find reachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; } }else { -WARN ("can't find reachable insn at %s+0x%lx" , +WARN ("can't find reachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; }
tools/objtool/elf.c +1 -1
@@ -485,7 +485,7 @@ static struct section *elf_create_reloc_ int reltype);int elf_add_reloc (struct elf *elf,struct section *sec,unsigned long offset, -unsigned int type,struct symbol *sym,long addend) +unsigned int type,struct symbol *sym,s64 addend) {struct reloc *reloc;
tools/objtool/include/objtool/elf.h +2 -2
@@ -69,7 +69,7 @@ struct reloc {struct symbol *sym;unsigned long offset;unsigned int type; -long addend; +s64 addend;int idx;bool jump_table_start; };
@@ -131,7 +131,7 @@ struct elf *elf_open_read(const char *nastruct section *elf_create_section (struct elf *elf,const char *name,unsigned int sh_flags,size_t entsize,int nr);int elf_add_reloc (struct elf *elf,struct section *sec,unsigned long offset, -unsigned int type,struct symbol *sym,long addend); +unsigned int type,struct symbol *sym,s64 addend);int elf_add_reloc_to_insn (struct elf *elf,struct section *sec,unsigned long offset,unsigned int type,struct section *insn_sec,unsigned long insn_off);
Greg Kroah-Hartman
maintainerPATCH 526/667 objtool: Fix symbol creation
In reply to Greg Kroah-HartmanFrom: Peter Zijlstra <[email protected]>
commit ead165fa1042247b033afad7be4be9b815d04ade upstream.
Nathan reported objtool failing with the following messages:
warning: objtool: no non-local symbols !?
warning: objtool: gelf_update_symshndx: invalid section index
The problem is due to commit 4abff6d48dbc ("objtool: Fix code relocs vs weak symbols") failing to consider the case where an object would have no non-local symbols.
The problem that commit tries to address is adding a STB_LOCAL symbol to the symbol table in light of the ELF spec's requirement that:
In each symbol table, all symbols with STB_LOCAL binding preced the weak and global symbols. As ``Sections'' above describes, a symbol table section's sh_info section header member holds the symbol table index for the first non-local symbol.
The approach taken is to find this first non-local symbol, move that to the end and then re-use the freed spot to insert a new local symbol and increment sh_info.
Except it never considered the case of object files without global symbols and got a whole bunch of details wrong -- so many in fact that it is a wonder it ever worked :/
Specifically:
- It failed to re-hash the symbol on the new index, so a subsequent find_symbol_by_index() would not find it at the new location and a query for the old location would now return a non-deterministic choice between the old and new symbol.
- It failed to appreciate that the GElf wrappers are not a valid disk format (it works because GElf is basically Elf64 and we only support x86_64 atm.)
- It failed to fully appreciate how horrible the libelf API really is and got the gelf_update_symshndx() call pretty much completely wrong; with the direct consequence that if inserting a second STB_LOCAL symbol would require moving the same STB_GLOBAL symbol again it would completely come unstuck.
Write a new elf_update_symbol() function that wraps all the magic required to update or create a new symbol at a given index.
Specifically, gelf_update_sym*() require an @ndx argument that is relative to the @data argument; this means you have to manually iterate the section data descriptor list and update @ndx.
--- tools/objtool/elf.c | 196 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 68 deletions(-)
tools/objtool/elf.c +128 -68
@@ -314,6 +314,8 @@ static void elf_add_symbol(struct elf *estruct list_head *entry;struct rb_node *pnode; + sym->alias = sym; + sym->type =GELF_ST_TYPE (sym->sym.st_info); sym->bind =GELF_ST_BIND (sym->sym.st_info);
@@ -375,7 +377,6 @@ static int read_symbols(struct elf *elf)return -1 ; }memset (sym,0 ,sizeof (*sym)); - sym->alias = sym; sym->idx = i;
@@ -539,24 +540,21 @@ static void elf_dirty_reloc_sym(struct e }/* -* Move the first global symbol, as per sh_info, into a new, higher symbol -* index. This fees up the shndx for a new local symbol. +* The libelf API is terrible; gelf_update_sym*() takes a data block relative +* index value, *NOT* the symbol index. As such, iterate the data blocks and +* adjust index until it fits. +* +* If no data block is found, allow adding a new data block provided the index +* is only one past the end. */ -static int elf_move_global_symbol (struct elf *elf,struct section *symtab, -struct section *symtab_shndx) +static int elf_update_symbol (struct elf *elf,struct section *symtab, +struct section *symtab_shndx,struct symbol *sym) { -Elf_Data *data, *shndx_data =NULL ; -Elf32_Word first_non_local; -struct symbol *sym; -Elf_Scn *s; - - first_non_local = symtab->sh.sh_info; - - sym =find_symbol_by_index (elf, first_non_local); -if (!sym) { -WARN ("no non-local symbols !?" ); -return first_non_local; - } +Elf32_Word shndx = sym->sec ? sym->sec->idx :SHN_UNDEF ; +Elf_Data *symtab_data =NULL , *shndx_data =NULL ; +Elf64_Xword entsize = symtab->sh.sh_entsize; +int max_idx, idx = sym->idx; +Elf_Scn *s, *t =NULL ; s =elf_getscn (elf->elf, symtab->idx);if (!s) {
@@ -564,79 +562,124 @@ static int elf_move_global_symbol(structreturn -1 ; } - data =elf_newdata (s); -if (!data) { -WARN_ELF ("elf_newdata" ); -return -1 ; +if (symtab_shndx) { + t =elf_getscn (elf->elf, symtab_shndx->idx); +if (!t) { +WARN_ELF ("elf_getscn" ); +return -1 ; + } } - data->d_buf = &sym->sym; - data->d_size =sizeof (sym->sym); - data->d_align =1 ; - data->d_type =ELF_T_SYM ; +for (;;) { +/* get next data descriptor for the relevant sections */ + symtab_data =elf_getdata (s, symtab_data); +if (t) + shndx_data =elf_getdata (t, shndx_data); + +/* end-of-list */ +if (!symtab_data) { +void *buf; + +if (idx) { +/* we don't do holes in symbol tables */ +WARN ("index out of range" ); +return -1 ; + } - sym->idx = symtab->sh.sh_size /sizeof (sym->sym); -elf_dirty_reloc_sym (elf, sym); +/* if @idx == 0, it's the next contiguous entry, create it */ + symtab_data =elf_newdata (s); +if (t) + shndx_data =elf_newdata (t); + + buf =calloc (1 , entsize); +if (!buf) { +WARN ("malloc" ); +return -1 ; + } - symtab->sh.sh_info +=1 ; - symtab->sh.sh_size += data->d_size; - symtab->changed = true; + symtab_data->d_buf = buf; + symtab_data->d_size = entsize; + symtab_data->d_align =1 ; + symtab_data->d_type =ELF_T_SYM ; + + symtab->sh.sh_size += entsize; + symtab->changed = true; + +if (t) { + shndx_data->d_buf = &sym->sec->idx; + shndx_data->d_size =sizeof (Elf32_Word); + shndx_data->d_align =sizeof (Elf32_Word); + shndx_data->d_type =ELF_T_WORD ; -if (symtab_shndx) { - s =elf_getscn (elf->elf, symtab_shndx->idx); -if (!s) { -WARN_ELF ("elf_getscn" ); + symtab_shndx->sh.sh_size +=sizeof (Elf32_Word); + symtab_shndx->changed = true; + } + +break ; + } + +/* empty blocks should not happen */ +if (!symtab_data->d_size) { +WARN ("zero size data" );return -1 ; } - shndx_data =elf_newdata (s); +/* is this the right block? */ + max_idx = symtab_data->d_size / entsize; +if (idx < max_idx) +break ; + +/* adjust index and try again */ + idx -= max_idx; + } + +/* something went side-ways */ +if (idx <0 ) { +WARN ("negative index" ); +return -1 ; + } + +/* setup extended section index magic and write the symbol */ +if (shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) { + sym->sym.st_shndx = shndx; +if (!shndx_data) + shndx =0 ; + }else { + sym->sym.st_shndx =SHN_XINDEX ;if (!shndx_data) { -WARN_ELF ("elf_newshndx_data" ); +WARN ("no .symtab_shndx" );return -1 ; } + } - shndx_data->d_buf = &sym->sec->idx; - shndx_data->d_size =sizeof (Elf32_Word); - shndx_data->d_align =4 ; - shndx_data->d_type =ELF_T_WORD ; - - symtab_shndx->sh.sh_size +=4 ; - symtab_shndx->changed = true; +if (!gelf_update_symshndx (symtab_data, shndx_data, idx, &sym->sym, shndx)) { +WARN_ELF ("gelf_update_symshndx" ); +return -1 ; } -return first_non_local; +return 0 ; }static struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec) {struct section *symtab, *symtab_shndx; -Elf_Data *shndx_data =NULL ; -struct symbol *sym; -Elf32_Word shndx; +Elf32_Word first_non_local, new_idx; +struct symbol *sym, *old; symtab =find_section_by_name (elf,".symtab" );if (symtab) { symtab_shndx =find_section_by_name (elf,".symtab_shndx" ); -if (symtab_shndx) - shndx_data = symtab_shndx->data; }else {WARN ("no .symtab" );return NULL ; } - sym =malloc (sizeof (*sym)); + sym =calloc (1 ,sizeof (*sym));if (!sym) {perror ("malloc" );return NULL ; } -memset (sym,0 ,sizeof (*sym)); - - sym->idx =elf_move_global_symbol (elf, symtab, symtab_shndx); -if (sym->idx <0 ) { -WARN ("elf_move_global_symbol" ); -return NULL ; - } sym->name = sec->name; sym->sec = sec;
@@ -646,24 +689,41 @@ elf_create_section_symbol(struct elf *el// st_other 0 // st_value 0 // st_size 0 - shndx = sec->idx; -if (shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) { - sym->sym.st_shndx = shndx; -if (!shndx_data) - shndx =0 ; - }else { - sym->sym.st_shndx =SHN_XINDEX ; -if (!shndx_data) { -WARN ("no .symtab_shndx" ); + +/* +* Move the first global symbol, as per sh_info, into a new, higher +* symbol index. This fees up a spot for a new local symbol. +*/ + first_non_local = symtab->sh.sh_info; + new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize; + old =find_symbol_by_index (elf, first_non_local); +if (old) { + old->idx = new_idx; + +hlist_del (&old->hash); +elf_hash_add (symbol, &old->hash, old->idx); + +elf_dirty_reloc_sym (elf, old); + +if (elf_update_symbol (elf, symtab, symtab_shndx, old)) { +WARN ("elf_update_symbol move" );return NULL ; } + + new_idx = first_non_local; } -if (!gelf_update_symshndx (symtab->data, shndx_data, sym->idx, &sym->sym, shndx)) { -WARN_ELF ("gelf_update_symshndx" ); + sym->idx = new_idx; +if (elf_update_symbol (elf, symtab, symtab_shndx, sym)) { +WARN ("elf_update_symbol" );return NULL ; } +/* +* Either way, we added a LOCAL symbol. +*/ + symtab->sh.sh_info +=1 ; +elf_add_symbol (elf, sym);return sym;
Greg Kroah-Hartman
maintainerPATCH 527/667 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
@@ -1746,12 +1746,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 528/667 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
@@ -563,6 +563,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 529/667 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
@@ -1806,11 +1806,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) {
@@ -1886,7 +1887,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 ()) {/*
@@ -1908,7 +1911,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);
@@ -1922,14 +1925,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 530/667 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 531/667 bfq: Avoid false marking of bic as stably merged
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 70456e5210f40ffdb8f6d905acfdcec5bd5fad9e upstream.
bfq_setup_cooperator() can mark bic as stably merged even though it decides to not merge its bfqqs (when bfq_setup_merge() returns NULL). Make sure to mark bic as stably merged only if we are really going to merge bfqqs.
--- block/bfq-iosched.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
block/bfq-iosched.c +6 -3
@@ -2773,9 +2773,12 @@ bfq_setup_cooperator(struct bfq_data *bfstruct bfq_queue *new_bfqq =bfq_setup_merge (bfqq, stable_merge_bfqq); - bic->stably_merged = true; -if (new_bfqq && new_bfqq->bic) - new_bfqq->bic->stably_merged = true; +if (new_bfqq) { + bic->stably_merged = true; +if (new_bfqq->bic) + new_bfqq->bic->stably_merged = + true; + }return new_bfqq; }else return NULL ;
Greg Kroah-Hartman
maintainerPATCH 532/667 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
@@ -2636,6 +2636,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 533/667 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
@@ -733,9 +733,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
@@ -5193,7 +5193,7 @@ static void bfq_put_stable_ref(struct bfbfq_put_queue (bfqq); } -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
@@ -977,6 +977,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 534/667 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
@@ -2335,10 +2335,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 535/667 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
@@ -6012,11 +6012,8 @@ static void bfq_insert_request(struct blreturn ; } -spin_unlock_irq (&bfqd->lock); -trace_block_rq_insert (rq); -spin_lock_irq (&bfqd->lock); bfqq =bfq_init_rq (rq);if (!bfqq || at_head) {if (at_head)
Greg Kroah-Hartman
maintainerPATCH 536/667 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
@@ -2375,8 +2375,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) {
@@ -2385,7 +2383,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;
@@ -2437,8 +2435,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) goto remove;
@@ -5991,6 +5989,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) {
@@ -6006,6 +6006,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, &free)) {spin_unlock_irq (&bfqd->lock);blk_mq_free_requests (&free);
@@ -6014,7 +6015,6 @@ static void bfq_insert_request(struct bltrace_block_rq_insert (rq); - bfqq =bfq_init_rq (rq);if (!bfqq || at_head) {if (at_head)list_add (&rq->queuelist, &bfqd->dispatch);
Greg Kroah-Hartman
maintainerPATCH 537/667 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
@@ -555,6 +555,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 ; }
@@ -601,7 +602,6 @@ struct bfq_group *bfq_find_set_group(strstruct bfq_entity *entity; bfqg =bfq_lookup_bfqg (bfqd, blkcg); -if (unlikely (!bfqg))return NULL ;
@@ -969,6 +969,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
@@ -926,6 +926,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 538/667 bfq: Get rid of __bio_blkcg() usage
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 4e54a2493e582361adc3bfbf06c7d50d19d18837 upstream.
BFQ usage of __bio_blkcg() is a relict from the past. Furthermore if bio would not be associated with any blkcg, the usage of __bio_blkcg() in BFQ is prone to races with the task being migrated between cgroups as __bio_blkcg() calls at different places could return different blkcgs.
Convert BFQ to the new situation where bio->bi_blkg is initialized in bio_set_dev() and thus practically always valid. This allows us to save blkcg_gq lookup and noticeably simplify the code.
--- block/bfq-cgroup.c | 63 ++++++++++++++++++---------------------------------- block/bfq-iosched.c | 11 --------- block/bfq-iosched.h | 3 -- 3 files changed, 25 insertions(+), 52 deletions(-)
block/bfq-cgroup.c +23 -40
@@ -584,27 +584,11 @@ static void bfq_group_set_parent(struct entity->sched_data = &parent->sched_data; } -static struct bfq_group *bfq_lookup_bfqg (struct bfq_data *bfqd, -struct blkcg *blkcg) +static void bfq_link_bfqg (struct bfq_data *bfqd,struct bfq_group *bfqg) { -struct blkcg_gq *blkg; - - blkg =blkg_lookup (blkcg, bfqd->queue); -if (likely (blkg)) -return blkg_to_bfqg (blkg); -return NULL ; -} - -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd, -struct blkcg *blkcg) -{ -struct bfq_group *bfqg, *parent; +struct bfq_group *parent;struct bfq_entity *entity; - bfqg =bfq_lookup_bfqg (bfqd, blkcg); -if (unlikely (!bfqg)) -return NULL ; -/* * Update chain of bfq_groups as we might be handling a leaf group * which, along with some of its relatives, has not been hooked yet
@@ -621,8 +605,15 @@ struct bfq_group *bfq_find_set_group(strbfq_group_set_parent (curr_bfqg, parent); } } +} -return bfqg; +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) +{ +struct blkcg_gq *blkg = bio->bi_blkg; + +if (!blkg) +return bfqd->root_group; +return blkg_to_bfqg (blkg); }/**
@@ -704,25 +695,15 @@ void bfq_bfqq_move(struct bfq_data *bfqd* Move bic to blkcg, assuming that bfqd->lock is held; which makes * sure that the reference to cgroup is valid across the call (see * comments in bfq_bic_update_cgroup on this issue) -* -* NOTE: an alternative approach might have been to store the current -* cgroup in bfqq and getting a reference to it, reducing the lookup -* time here, at the price of slightly more complex code. */ -static struct bfq_group *__bfq_bic_change_cgroup (struct bfq_data *bfqd, -struct bfq_io_cq *bic, -struct blkcg *blkcg) +static void *__bfq_bic_change_cgroup (struct bfq_data *bfqd, +struct bfq_io_cq *bic, +struct bfq_group *bfqg) {struct bfq_queue *async_bfqq =bic_to_bfqq (bic,0 );struct bfq_queue *sync_bfqq =bic_to_bfqq (bic,1 ); -struct bfq_group *bfqg;struct bfq_entity *entity; - bfqg =bfq_find_set_group (bfqd, blkcg); - -if (unlikely (!bfqg)) - bfqg = bfqd->root_group; -if (async_bfqq) { entity = &async_bfqq->entity;
@@ -774,20 +755,24 @@ static struct bfq_group *__bfq_bic_changvoid bfq_bic_update_cgroup (struct bfq_io_cq *bic,struct bio *bio) {struct bfq_data *bfqd =bic_to_bfqd (bic); -struct bfq_group *bfqg =NULL ; +struct bfq_group *bfqg =bfq_bio_bfqg (bfqd, bio);uint64_t serial_nr; -rcu_read_lock (); - serial_nr =__bio_blkcg (bio)->css.serial_nr; + serial_nr =bfqg_to_blkg (bfqg)->blkcg->css.serial_nr;/* * Check whether blkcg has changed. The condition may trigger * spuriously on a newly created cic but there's no harm. */ if (unlikely (!bfqd) ||likely (bic->blkcg_serial_nr == serial_nr)) - goto out; +return ; - bfqg =__bfq_bic_change_cgroup (bfqd, bic,__bio_blkcg (bio)); +/* +* New cgroup for this process. Make sure it is linked to bfq internal +* cgroup hierarchy. +*/ +bfq_link_bfqg (bfqd, bfqg); +__bfq_bic_change_cgroup (bfqd, bic, bfqg);/* * Update blkg_path for bfq_log_* functions. We cache this * path, and update it here, for the following
@@ -840,8 +825,6 @@ void bfq_bic_update_cgroup(struct bfq_io*/ blkg_path (bfqg_to_blkg (bfqg), bfqg->blkg_path,sizeof (bfqg->blkg_path)); bic->blkcg_serial_nr = serial_nr; -out: -rcu_read_unlock (); }/**
@@ -1459,7 +1442,7 @@ void bfq_end_wr_async(struct bfq_data *bbfq_end_wr_async_queues (bfqd, bfqd->root_group); } -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd,struct blkcg *blkcg) +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) {return bfqd->root_group; }
block/bfq-iosched.c +1 -10
@@ -5604,14 +5604,7 @@ static struct bfq_queue *bfq_get_queue(sstruct bfq_queue *bfqq;struct bfq_group *bfqg; -rcu_read_lock (); - - bfqg =bfq_find_set_group (bfqd,__bio_blkcg (bio)); -if (!bfqg) { - bfqq = &bfqd->oom_bfqq; - goto out; - } - + bfqg =bfq_bio_bfqg (bfqd, bio);if (!is_sync) { async_bfqq =bfq_async_queue_prio (bfqd, bfqg, ioprio_class, ioprio);
@@ -5657,8 +5650,6 @@ out:if (bfqq != &bfqd->oom_bfqq && is_sync && !respawn) bfqq =bfq_do_or_sched_stable_merge (bfqd, bfqq, bic); - -rcu_read_unlock ();return bfqq; }
block/bfq-iosched.h +1 -2
@@ -1007,8 +1007,7 @@ void bfq_bfqq_move(struct bfq_data *bfqdvoid bfq_init_entity (struct bfq_entity *entity,struct bfq_group *bfqg);void bfq_bic_update_cgroup (struct bfq_io_cq *bic,struct bio *bio);void bfq_end_wr_async (struct bfq_data *bfqd); -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd, -struct blkcg *blkcg); +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio);struct blkcg_gq *bfqg_to_blkg (struct bfq_group *bfqg);struct bfq_group *bfqq_group (struct bfq_queue *bfqq);struct bfq_group *bfq_create_group_hierarchy (struct bfq_data *bfqd,int node);
Greg Kroah-Hartman
maintainerPATCH 539/667 bfq: Make sure bfqg for which we are queueing requests is online
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 075a53b78b815301f8d3dd1ee2cd99554e34f0dd upstream.
Bios queued into BFQ IO scheduler can be associated with a cgroup that was already offlined. This may then cause insertion of this bfq_group into a service tree. But this bfq_group will get freed as soon as last bio associated with it is completed leading to use after free issues for service tree users. Fix the problem by making sure we always operate on online bfq_group. If the bfq_group associated with the bio is not online, we pick the first online parent.
--- block/bfq-cgroup.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
block/bfq-cgroup.c +12 -3
@@ -610,10 +610,19 @@ static void bfq_link_bfqg(struct bfq_datstruct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) {struct blkcg_gq *blkg = bio->bi_blkg; +struct bfq_group *bfqg; -if (!blkg) -return bfqd->root_group; -return blkg_to_bfqg (blkg); +while (blkg) { + bfqg =blkg_to_bfqg (blkg); +if (bfqg->online) { +bio_associate_blkg_from_css (bio, &blkg->blkcg->css); +return bfqg; + } + blkg = blkg->parent; + } +bio_associate_blkg_from_css (bio, + &bfqg_to_blkg (bfqd->root_group)->blkcg->css); +return bfqd->root_group; }/**
Greg Kroah-Hartman
maintainerPATCH 540/667 ext4: mark group as trimmed only if it was fully scanned
In reply to Greg Kroah-HartmanFrom: Dmitry Monakhov <[email protected]>
commit d63c00ea435a5352f486c259665a4ced60399421 upstream.
Otherwise nonaligned fstrim calls will works inconveniently for iterative scanners, for example:
// trim [0,16MB] for group-1, but mark full group as trimmed
fstrim -o $((1024*1024*128)) -l $((1024*1024*16)) ./m
// handle [16MB,16MB] for group-1, do nothing because group already has the flag. fstrim -o $((1024*1024*144)) -l $((1024*1024*16)) ./m
[ Update function documentation for ext4_trim_all_free -- TYT ]
--- fs/ext4/mballoc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
fs/ext4/mballoc.c +12 -6
@@ -6378,6 +6378,7 @@ __releases(ext4_group_lock_ptr(sb, e4b->* @start: first group block to examine * @max: last group block to examine * @minblocks: minimum extent block count +* @set_trimmed: set the trimmed flag if at least one block is trimmed * * ext4_trim_all_free walks through group's block bitmap searching for free * extents. When the free extent is found, mark it as used in group buddy
@@ -6387,7 +6388,7 @@ __releases(ext4_group_lock_ptr(sb, e4b->static ext4_grpblk_t ext4_trim_all_free (struct super_block *sb,ext4_group_t group,ext4_grpblk_t start,ext4_grpblk_t max, -ext4_grpblk_t minblocks) +ext4_grpblk_t minblocks,bool set_trimmed) {struct ext4_buddy e4b;int ret;
@@ -6406,7 +6407,7 @@ ext4_trim_all_free(struct super_block *sif (!EXT4_MB_GRP_WAS_TRIMMED (e4b.bd_info) || minblocks <atomic_read (&EXT4_SB (sb)->s_last_trim_minblks)) { ret =ext4_try_to_trim_range (sb, &e4b, start, max, minblocks); -if (ret >=0 ) +if (ret >=0 && set_trimmed)EXT4_MB_GRP_SET_TRIMMED (e4b.bd_info); }else { ret =0 ;
@@ -6443,6 +6444,7 @@ int ext4_trim_fs(struct super_block *sb,ext4_fsblk_t first_data_blk =le32_to_cpu (EXT4_SB (sb)->s_es->s_first_data_block);ext4_fsblk_t max_blks =ext4_blocks_count (EXT4_SB (sb)->s_es); +bool whole_group, eof = false;int ret =0 ; start = range->start >> sb->s_blocksize_bits;
@@ -6461,8 +6463,10 @@ int ext4_trim_fs(struct super_block *sb,if (minlen >EXT4_CLUSTERS_PER_GROUP (sb)) goto out; } -if (end >= max_blks) +if (end >= max_blks -1 ) { end = max_blks -1 ; + eof = true; + }if (end <= first_data_blk) goto out;if (start < first_data_blk)
@@ -6476,6 +6480,7 @@ int ext4_trim_fs(struct super_block *sb,/* end now represents the last cluster to discard in this group */ end =EXT4_CLUSTERS_PER_GROUP (sb) -1 ; + whole_group = true;for (group = first_group; group <= last_group; group++) { grp =ext4_get_group_info (sb, group);
@@ -6492,12 +6497,13 @@ int ext4_trim_fs(struct super_block *sb,* change it for the last group, note that last_cluster is * already computed earlier by ext4_get_group_no_and_offset() */ -if (group == last_group) +if (group == last_group) { end = last_cluster; - + whole_group = eof ? true : end ==EXT4_CLUSTERS_PER_GROUP (sb) -1 ; + }if (grp->bb_free >= minlen) { cnt =ext4_trim_all_free (sb, group, first_cluster, - end, minlen); + end, minlen, whole_group);if (cnt <0 ) { ret = cnt;break ;
Greg Kroah-Hartman
maintainerPATCH 541/667 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
@@ -3455,6 +3455,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 */
@@ -3463,9 +3466,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 542/667 ext4: fix race condition between ext4_write and ext4_convert_inline_data
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit f87c7a4b084afc13190cbb263538e444cb2b392a upstream.
Hulk Robot reported a BUG_ON:
==================================================================
EXT4-fs error (device loop3): ext4_mb_generate_buddy:805: group 0, block bitmap and bg descriptor inconsistent: 25 vs 31513 free clusters kernel BUG at fs/ext4/ext4_jbd2.c:53!
invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 0 PID: 25371 Comm: syz-executor.3 Not tainted 5.10.0+ #1 RIP: 0010:ext4_put_nojournal fs/ext4/ext4_jbd2.c:53 [inline] RIP: 0010:__ext4_journal_stop+0x10e/0x110 fs/ext4/ext4_jbd2.c:116 [...] Call Trace: ext4_write_inline_data_end+0x59a/0x730 fs/ext4/inline.c:795 generic_perform_write+0x279/0x3c0 mm/filemap.c:3344 ext4_buffered_write_iter+0x2e3/0x3d0 fs/ext4/file.c:270 ext4_file_write_iter+0x30a/0x11c0 fs/ext4/file.c:520 do_iter_readv_writev+0x339/0x3c0 fs/read_write.c:732 do_iter_write+0x107/0x430 fs/read_write.c:861 vfs_writev fs/read_write.c:934 [inline] do_pwritev+0x1e5/0x380 fs/read_write.c:1031 [...] ==================================================================
Above issue may happen as follows:
cpu1 cpu2
__________________________|__________________________ do_pwritev
vfs_writev
do_iter_write
ext4_file_write_iter
ext4_buffered_write_iter
generic_perform_write
ext4_da_write_begin
vfs_fallocate
ext4_fallocate
ext4_convert_inline_data
ext4_convert_inline_data_nolock
ext4_destroy_inline_data_nolock
clear EXT4_STATE_MAY_INLINE_DATA
ext4_map_blocks
ext4_ext_map_blocks
ext4_mb_new_blocks
ext4_mb_regular_allocator
ext4_mb_good_group_nolock
ext4_mb_init_group
ext4_mb_init_cache
ext4_mb_generate_buddy --> error
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)
ext4_restore_inline_data
set EXT4_STATE_MAY_INLINE_DATA
ext4_block_write_begin
ext4_da_write_end
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)
ext4_write_inline_data_end
handle=NULL
ext4_journal_stop(handle)
__ext4_journal_stop
ext4_put_nojournal(handle)
ref_cnt = (unsigned long)handle
BUG_ON(ref_cnt == 0) ---> BUG_ONThe lock held by ext4_convert_inline_data is xattr_sem, but the lock held by generic_perform_write is i_rwsem. Therefore, the two locks can be concurrent.
To solve above issue, we add inode_lock() for ext4_convert_inline_data(). At the same time, move ext4_convert_inline_data() in front of ext4_punch_hole(), remove similar handling from ext4_punch_hole().
--- fs/ext4/extents.c | 10 ++++++---- fs/ext4/inode.c | 9 --------- 2 files changed, 6 insertions(+), 13 deletions(-)
fs/ext4/extents.c +6 -4
@@ -4699,15 +4699,17 @@ long ext4_fallocate(struct file *file, iext4_fc_start_update (inode); +inode_lock (inode); + ret =ext4_convert_inline_data (inode); +inode_unlock (inode); +if (ret) + goto exit; +if (mode &FALLOC_FL_PUNCH_HOLE ) { ret =ext4_punch_hole (file, offset, len); goto exit; } - ret =ext4_convert_inline_data (inode); -if (ret) - goto exit; -if (mode &FALLOC_FL_COLLAPSE_RANGE ) { ret =ext4_collapse_range (file, offset, len); goto exit;
fs/ext4/inode.c +0 -9
@@ -3953,15 +3953,6 @@ int ext4_punch_hole(struct file *file, ltrace_ext4_punch_hole (inode, offset, length,0 ); -ext4_clear_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA ); -if (ext4_has_inline_data (inode)) { -filemap_invalidate_lock (mapping); - ret =ext4_convert_inline_data (inode); -filemap_invalidate_unlock (mapping); -if (ret) -return ret; - } -/* * Write out all dirty pages to avoid race conditions * Then release them.
Greg Kroah-Hartman
maintainerPATCH 543/667 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
@@ -5364,6 +5364,7 @@ int ext4_setattr(struct user_namespace *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 ))) {
@@ -5437,6 +5438,7 @@ int ext4_setattr(struct user_namespace * 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)
@@ -5448,6 +5450,8 @@ int ext4_setattr(struct user_namespace **/ 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 544/667 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
@@ -2011,6 +2011,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 545/667 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
@@ -4391,7 +4391,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));
@@ -5937,7 +5937,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 546/667 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
@@ -372,7 +372,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 ;
@@ -396,11 +396,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--; }
@@ -420,13 +420,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 547/667 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
@@ -277,9 +277,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(struct inode *dir, char *from, char *to, struct dx_map_entry *offsets,
@@ -1249,15 +1249,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) {if (ext4_hash_in_dirent (dir)) h.hash =EXT4_DIRENT_HASH (de);
@@ -1270,8 +1278,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; }
@@ -1943,8 +1950,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 548/667 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
@@ -777,12 +777,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 );
@@ -854,6 +856,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)) {
@@ -882,15 +886,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 549/667 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 550/667 tty: goldfish: Introduce gf_ioread32()/gf_iowrite32()
In reply to Greg Kroah-HartmanFrom: Laurent Vivier <[email protected]>
commit 2e2ac4a3327479f7e2744cdd88a5c823f2057bad upstream.
The goldfish TTY device was clearly defined as having little-endian registers, but the switch to __raw_{read,write}l(() broke its driver when running on big-endian kernels (if anyone ever tried this).
The m68k qemu implementation got this wrong, and assumed native-endian registers. While this is a bug in qemu, it is probably impossible to fix that since there is no way of knowing which other operating systems have started relying on that bug over the years.
Hence revert commit da31de35cd2f ("tty: goldfish: use __raw_writel()/__raw_readl()", and define gf_ioread32()/gf_iowrite32() to be able to use accessors defined by the architecture.
--- drivers/tty/goldfish.c | 20 ++++++++++---------- include/linux/goldfish.h | 15 +++++++++++---- 2 files changed, 21 insertions(+), 14 deletions(-)
drivers/tty/goldfish.c +10 -10
@@ -61,13 +61,13 @@ static void do_rw_io(struct goldfish_ttyspin_lock_irqsave (&qtty->lock, irq_flags);gf_write_ptr ((void *)address, base +GOLDFISH_TTY_REG_DATA_PTR , base +GOLDFISH_TTY_REG_DATA_PTR_HIGH ); -__raw_writel (count, base +GOLDFISH_TTY_REG_DATA_LEN ); +gf_iowrite32 (count, base +GOLDFISH_TTY_REG_DATA_LEN );if (is_write) -__raw_writel (GOLDFISH_TTY_CMD_WRITE_BUFFER , +gf_iowrite32 (GOLDFISH_TTY_CMD_WRITE_BUFFER , base +GOLDFISH_TTY_REG_CMD );else -__raw_writel (GOLDFISH_TTY_CMD_READ_BUFFER , +gf_iowrite32 (GOLDFISH_TTY_CMD_READ_BUFFER , base +GOLDFISH_TTY_REG_CMD );spin_unlock_irqrestore (&qtty->lock, irq_flags);
@@ -142,7 +142,7 @@ static irqreturn_t goldfish_tty_interrupunsigned char *buf;u32 count; - count =__raw_readl (base +GOLDFISH_TTY_REG_BYTES_READY ); + count =gf_ioread32 (base +GOLDFISH_TTY_REG_BYTES_READY );if (count ==0 )return IRQ_NONE ;
@@ -159,7 +159,7 @@ static int goldfish_tty_activate(struct { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); -__raw_writel (GOLDFISH_TTY_CMD_INT_ENABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_ENABLE , qtty->base +GOLDFISH_TTY_REG_CMD );return 0 ; }
@@ -167,7 +167,7 @@ static void goldfish_tty_shutdown(struct { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); -__raw_writel (GOLDFISH_TTY_CMD_INT_DISABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_DISABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); }static int goldfish_tty_open (struct tty_struct *tty,struct file *filp)
@@ -202,7 +202,7 @@ static unsigned int goldfish_tty_chars_i {struct goldfish_tty *qtty = &goldfish_ttys[tty->index];void __iomem *base = qtty->base; -return __raw_readl (base +GOLDFISH_TTY_REG_BYTES_READY ); +return gf_ioread32 (base +GOLDFISH_TTY_REG_BYTES_READY ); } static void goldfish_tty_console_write(struct console *co, const char *b,
@@ -357,7 +357,7 @@ static int goldfish_tty_probe(struct pla* on Ranchu emulator (qemu2) returns 1 here and * driver will use physical addresses. */ - qtty->version =__raw_readl (base +GOLDFISH_TTY_REG_VERSION ); + qtty->version =gf_ioread32 (base +GOLDFISH_TTY_REG_VERSION );/* * Goldfish TTY device on Ranchu emulator (qemu2)
@@ -376,7 +376,7 @@ static int goldfish_tty_probe(struct pla } } -__raw_writel (GOLDFISH_TTY_CMD_INT_DISABLE , base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_DISABLE , base +GOLDFISH_TTY_REG_CMD ); ret =request_irq (irq, goldfish_tty_interrupt,IRQF_SHARED ,"goldfish_tty" , qtty);
@@ -438,7 +438,7 @@ static int goldfish_tty_remove(struct pl#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE static void gf_early_console_putchar (struct uart_port *port,int ch) { -__raw_writel (ch, port->membase); +gf_iowrite32 (ch, port->membase); }static void gf_early_write (struct console *con,const char *s,unsigned int n)
include/linux/goldfish.h +11 -4
@@ -8,14 +8,21 @@/* Helpers for Goldfish virtual platform */ +#ifndef gf_ioread32 +#define gf_ioread32 ioread32 +#endif +#ifndef gf_iowrite32 +#define gf_iowrite32 iowrite32 +#endif +static inline void gf_write_ptr (const void *ptr,void __iomem *portl,void __iomem *porth) {const unsigned long addr = (unsigned long )ptr; -__raw_writel (lower_32_bits (addr), portl); +gf_iowrite32 (lower_32_bits (addr), portl);#ifdef CONFIG_64BIT -__raw_writel (upper_32_bits (addr), porth); +gf_iowrite32 (upper_32_bits (addr), porth);#endif }
@@ -23,9 +30,9 @@ static inline void gf_write_dma_addr(convoid __iomem *portl, void __iomem *porth) { -__raw_writel (lower_32_bits (addr ),portl ); +gf_iowrite32 (lower_32_bits (addr ),portl );#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -__raw_writel (upper_32_bits (addr), porth); +gf_iowrite32 (upper_32_bits (addr), porth);#endif }
Greg Kroah-Hartman
maintainerPATCH 551/667 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
@@ -1838,8 +1838,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 552/667 tracing: Initialize integer variable to prevent garbage return value
In reply to Greg Kroah-HartmanFrom: Gautam Menghani <[email protected]>
commit 154827f8e53d8c492b3fb0cb757fbcadb5d516b5 upstream.
Initialize the integer variable to 0 to fix the clang scan warning:
Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]
return ret;
--- kernel/trace/trace_boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_boot.c +1 -1
@@ -300,7 +300,7 @@ trace_boot_hist_add_handlers(struct xbc_ {struct xbc_node *node;const char *p, *handler; -int ret; +int ret =0 ; handler =xbc_node_get_data (hnode);
Greg Kroah-Hartman
maintainerPATCH 553/667 drm/amdgpu: add beige goby PCI ID
In reply to Greg Kroah-HartmanFrom: Alex Deucher <[email protected]>
commit 62e9bd20035b53ff6c679499c08546d96c6c60a7 upstream.
Add a beige goby PCI ID.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +1 -0
@@ -1949,6 +1949,7 @@ static const struct pci_device_id pciidl {0x1002, 0x7421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x7422, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x7423, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, + {0x1002, 0x7424, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x743F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0, 0, 0}
Greg Kroah-Hartman
maintainerPATCH 554/667 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
@@ -2888,6 +2888,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 555/667 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
@@ -1521,17 +1521,14 @@ static int qcom_pcie_probe(struct platfo pp->ops = &qcom_pcie_dw_ops; 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 556/667 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
@@ -1529,11 +1529,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 557/667 staging: r8188eu: prevent ->Ssid overflow in rtw_wx_set_scan()
In reply to Greg Kroah-HartmanFrom: Denis Efremov <[email protected]>
commit bc10916e890948d8927a5c8c40fb5dc44be5e1b8 upstream.
This code has a check to prevent read overflow but it needs another check to prevent writing beyond the end of the ->Ssid[] array.
--- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/staging/r8188eu/os_dep/ioctl_linux.c +4 -2
@@ -1249,9 +1249,11 @@ static int rtw_wx_set_scan(struct net_debreak ; } sec_len = *(pos++); len -=1 ; -if (sec_len >0 && sec_len <= len) { +if (sec_len >0 && + sec_len <= len && + sec_len <=32 ) { ssid[ssid_index].SsidLength = sec_len; -memcpy (ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); +memcpy (ssid[ssid_index].Ssid, pos, sec_len); ssid_index++; } pos += sec_len;
Greg Kroah-Hartman
maintainerPATCH 558/667 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
@@ -1815,6 +1815,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 559/667 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
@@ -30,7 +30,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 560/667 s390/stp: clock_delta should be signed
In reply to Greg Kroah-HartmanFrom: Sven Schnelle <[email protected]>
commit 5ace65ebb5ce9fe1cc8fdbdd97079fb566ef0ea4 upstream.
clock_delta is declared as unsigned long in various places. However, the clock sync delta can be negative. This would add a huge positive offset in clock_sync_global where clock_delta is added to clk.eitod which is a 72 bit integer. Declare it as signed long to fix this.
--- arch/s390/include/asm/cio.h | 2 +- arch/s390/kernel/time.c | 8 ++++---- drivers/s390/cio/chsc.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/s390/include/asm/cio.h +1 -1
@@ -369,7 +369,7 @@ void cio_gp_dma_destroy(struct gen_poolstruct gen_pool *cio_gp_dma_create (struct device *dma_dev,int nr_pages);/* Function from drivers/s390/cio/chsc.c */ -int chsc_sstpc (void *page,unsigned int op,u16 ctrl,u64 *clock_delta); +int chsc_sstpc (void *page,unsigned int op,u16 ctrl,long *clock_delta);int chsc_sstpi (void *page,void *result,size_t size);int chsc_stzi (void *page,void *result,size_t size);int chsc_sgib (u32 origin);
arch/s390/kernel/time.c +4 -4
@@ -364,7 +364,7 @@ static inline int check_sync_clock(void)* Apply clock delta to the global data structures. * This is called once on the CPU that performed the clock sync. */ -static void clock_sync_global (unsigned long delta) +static void clock_sync_global (long delta) {unsigned long now, adj;struct ptff_qto qto;
@@ -400,7 +400,7 @@ static void clock_sync_global(unsigned l* Apply clock delta to the per-CPU data structures of this CPU. * This is called for each online CPU after the call to clock_sync_global. */ -static void clock_sync_local (unsigned long delta) +static void clock_sync_local (long delta) {/* Add the delta to the clock comparator. */ if (S390_lowcore.clock_comparator != clock_comparator_max) {
@@ -424,7 +424,7 @@ static void __init time_init_wq(void)struct clock_sync_data {atomic_t cpus;int in_sync; -unsigned long clock_delta; +long clock_delta; };/*
@@ -544,7 +544,7 @@ static int stpinfo_valid(void)static int stp_sync_clock (void *data) {struct clock_sync_data *sync = data; -u64 clock_delta, flags; +long clock_delta, flags;static int first;int rc;
drivers/s390/cio/chsc.c +2 -2
@@ -1255,7 +1255,7 @@ exit:EXPORT_SYMBOL_GPL (css_general_characteristics);EXPORT_SYMBOL_GPL (css_chsc_characteristics); -int chsc_sstpc (void *page,unsigned int op,u16 ctrl,u64 *clock_delta) +int chsc_sstpc (void *page,unsigned int op,u16 ctrl,long *clock_delta) {struct {struct chsc_header request;
@@ -1266,7 +1266,7 @@ int chsc_sstpc(void *page, unsigned intunsigned int rsvd2[5 ];struct chsc_header response;unsigned int rsvd3[3 ]; -u64 clock_delta; +s64 clock_delta;unsigned int rsvd4[2 ]; } *rr;int rc;
Greg Kroah-Hartman
maintainerPATCH 561/667 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 562/667 dlm: uninitialized variable on error in dlm_listen_for_all()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
commit 1f4f10845e14690b02410de50d9ea9684625a4ae upstream.
The "sock" variable is not initialized on this error path.
--- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dlm/lowcomms.c +1 -1
@@ -1776,7 +1776,7 @@ static int dlm_listen_for_all(void) SOCK_STREAM, dlm_proto_ops->proto, &sock);if (result <0 ) {log_print ("Can't create comms socket, check SCTP is loaded" ); - goto out; +return result; }sock_set_mark (sock->sk, dlm_config.ci_mark);
Greg Kroah-Hartman
maintainerPATCH 563/667 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 ; }
@@ -5310,11 +5312,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 564/667 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
@@ -433,6 +433,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,
@@ -595,7 +600,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 ;
@@ -609,12 +614,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; }
@@ -625,6 +635,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 565/667 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
@@ -3590,10 +3590,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 566/667 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
@@ -678,8 +678,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 567/667 landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6cc2df8e3a3967e7c13a424f87f6efb1d4a62d80 upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions. This enables to keep aligned values, which is much more readable than packed definitions.
--- include/uapi/linux/landlock.h | 4 ++++ security/landlock/fs.c | 2 ++ security/landlock/limits.h | 4 ++++ 3 files changed, 10 insertions(+)
include/uapi/linux/landlock.h +4 -0
@@ -33,7 +33,9 @@ struct landlock_ruleset_attr {* - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI * version. */ +/* clang-format off */ #define LANDLOCK_CREATE_RULESET_VERSION (1U << 0) +/* clang-format on */ /** * enum landlock_rule_type - Landlock rule type
@@ -120,6 +122,7 @@ struct landlock_path_beneath_attr {* :manpage:`access(2)`. * Future Landlock evolutions will enable to restrict them. */ +/* clang-format off */ #define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)#define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
@@ -133,5 +136,6 @@ struct landlock_path_beneath_attr {#define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12) +/* clang-format on */ #endif /* _UAPI_LINUX_LANDLOCK_H */
security/landlock/fs.c +2 -0
@@ -141,10 +141,12 @@ retry: }/* All access rights that can be tied to files. */ +/* clang-format off */ #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE) +/* clang-format on */ /* * @path: Should have been checked by get_path_from_fd().
security/landlock/limits.h +4 -0
@@ -12,10 +12,14 @@#include <linux/limits.h> #include <uapi/linux/landlock.h> +/* clang-format off */ +#define LANDLOCK_MAX_NUM_LAYERS 64#define LANDLOCK_MAX_NUM_RULES U32_MAX#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) +/* clang-format on */ +#endif /* _SECURITY_LANDLOCK_LIMITS_H */
Greg Kroah-Hartman
maintainerPATCH 568/667 landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 06a1c40a09a8dded4bf0e7e3ccbda6bddcccd7c8 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i security/landlock/*.[ch] include/uapi/linux/landlock.h
--- security/landlock/cred.c | 4 +- security/landlock/cred.h | 8 ++-- security/landlock/fs.c | 78 +++++++++++++++++++++-------------------- security/landlock/fs.h | 11 +++-- security/landlock/object.c | 6 +-- security/landlock/object.h | 6 +-- security/landlock/ptrace.c | 10 ++--- security/landlock/ruleset.c | 80 +++++++++++++++++++++---------------------- security/landlock/ruleset.h | 15 ++++---- security/landlock/syscalls.c | 60 ++++++++++++++++---------------- 10 files changed, 142 insertions(+), 136 deletions(-)
security/landlock/cred.c +2 -2
@@ -15,7 +15,7 @@#include "setup.h" static int hook_cred_prepare (struct cred *const new, -const struct cred *const old,const gfp_t gfp) +const struct cred *const old,const gfp_t gfp) {struct landlock_ruleset *const old_dom =landlock_cred (old)->domain;
@@ -42,5 +42,5 @@ static struct security_hook_list landloc__init void landlock_add_cred_hooks (void ) {security_add_hooks (landlock_hooks,ARRAY_SIZE (landlock_hooks), -LANDLOCK_NAME ); +LANDLOCK_NAME ); }
security/landlock/cred.h +4 -4
@@ -20,8 +20,8 @@ struct landlock_cred_security {struct landlock_ruleset *domain; }; -static inline struct landlock_cred_security *landlock_cred ( -const struct cred *cred) +static inline struct landlock_cred_security * +landlock_cred (const struct cred *cred) {return cred->security + landlock_blob_sizes.lbs_cred; }
@@ -34,8 +34,8 @@ static inline const struct landlock_rule/* * The call needs to come from an RCU read-side critical section. */ -static inline const struct landlock_ruleset *landlock_get_task_domain ( -const struct task_struct *const task) +static inline const struct landlock_ruleset * +landlock_get_task_domain (const struct task_struct *const task) {return landlock_cred (__task_cred (task))->domain; }
security/landlock/fs.c +40 -38
205 lines not on this page · raw message
security/landlock/fs.h +6 -5
@@ -50,14 +50,14 @@ struct landlock_superblock_security {atomic_long_t inode_refs; }; -static inline struct landlock_inode_security *landlock_inode ( -const struct inode *const inode) +static inline struct landlock_inode_security * +landlock_inode (const struct inode *const inode) {return inode->i_security + landlock_blob_sizes.lbs_inode; } -static inline struct landlock_superblock_security *landlock_superblock ( -const struct super_block *const superblock) +static inline struct landlock_superblock_security * +landlock_superblock (const struct super_block *const superblock) {return superblock->s_security + landlock_blob_sizes.lbs_superblock; }
@@ -65,6 +65,7 @@ static inline struct landlock_superblock__init void landlock_add_fs_hooks (void );int landlock_append_fs_rule (struct landlock_ruleset *const ruleset, -const struct path *const path,u32 access_hierarchy); +const struct path *const path, +u32 access_hierarchy);#endif /* _SECURITY_LANDLOCK_FS_H */
security/landlock/object.c +3 -3
@@ -17,9 +17,9 @@#include "object.h" -struct landlock_object *landlock_create_object ( -const struct landlock_object_underops *const underops, -void *const underobj) +struct landlock_object * +landlock_create_object (const struct landlock_object_underops *const underops, +void *const underobj) {struct landlock_object *new_object;
security/landlock/object.h +3 -3
@@ -76,9 +76,9 @@ struct landlock_object { }; }; -struct landlock_object *landlock_create_object ( -const struct landlock_object_underops *const underops, -void *const underobj); +struct landlock_object * +landlock_create_object (const struct landlock_object_underops *const underops, +void *const underobj);void landlock_put_object (struct landlock_object *const object);
security/landlock/ptrace.c +5 -5
@@ -30,7 +30,7 @@* means a subset of) the @child domain. */ static bool domain_scope_le (const struct landlock_ruleset *const parent, -const struct landlock_ruleset *const child) +const struct landlock_ruleset *const child) {const struct landlock_hierarchy *walker;
@@ -48,7 +48,7 @@ static bool domain_scope_le(const struct }static bool task_is_scoped (const struct task_struct *const parent, -const struct task_struct *const child) +const struct task_struct *const child) {bool is_scoped;const struct landlock_ruleset *dom_parent, *dom_child;
@@ -62,7 +62,7 @@ static bool task_is_scoped(const struct }static int task_ptrace (const struct task_struct *const parent, -const struct task_struct *const child) +const struct task_struct *const child) {/* Quick return for non-landlocked tasks. */ if (!landlocked (parent))
@@ -86,7 +86,7 @@ static int task_ptrace(const struct task* granted, -errno if denied. */ static int hook_ptrace_access_check (struct task_struct *const child, -const unsigned int mode) +const unsigned int mode) {return task_ptrace (current, child); }
@@ -116,5 +116,5 @@ static struct security_hook_list landloc__init void landlock_add_ptrace_hooks (void ) {security_add_hooks (landlock_hooks,ARRAY_SIZE (landlock_hooks), -LANDLOCK_NAME ); +LANDLOCK_NAME ); }
security/landlock/ruleset.c +40 -40
200 lines not on this page · raw message
security/landlock/ruleset.h +8 -7
@@ -146,15 +146,16 @@ void landlock_put_ruleset(struct landlocvoid landlock_put_ruleset_deferred (struct landlock_ruleset *const ruleset);int landlock_insert_rule (struct landlock_ruleset *const ruleset, -struct landlock_object *const object,const u32 access); +struct landlock_object *const object, +const u32 access); -struct landlock_ruleset *landlock_merge_ruleset ( -struct landlock_ruleset *const parent, -struct landlock_ruleset *const ruleset); +struct landlock_ruleset * +landlock_merge_ruleset (struct landlock_ruleset *const parent, +struct landlock_ruleset *const ruleset); -const struct landlock_rule *landlock_find_rule ( -const struct landlock_ruleset *const ruleset, -const struct landlock_object *const object); +const struct landlock_rule * +landlock_find_rule (const struct landlock_ruleset *const ruleset, +const struct landlock_object *const object);static inline void landlock_get_ruleset (struct landlock_ruleset *const ruleset) {
security/landlock/syscalls.c +31 -29
167 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 569/667 selftests/landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 4598d9abf4215e1e371a35683350d50122793c80 upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions and the TEST_F_FORK macro. This enables to keep aligned values, which is much more readable than packed definitions.
Add other clang-format exceptions for FIXTURE() and FIXTURE_VARIANT_ADD() declarations to force space before open brace, which is reported by checkpatch.pl .
--- tools/testing/selftests/landlock/common.h | 2 ++ tools/testing/selftests/landlock/fs_test.c | 23 +++++++++++++++++------ tools/testing/selftests/landlock/ptrace_test.c | 20 +++++++++++++++++++- 3 files changed, 38 insertions(+), 7 deletions(-)
tools/testing/selftests/landlock/common.h +2 -0
@@ -29,6 +29,7 @@* this to be possible, we must not call abort() but instead exit smoothly * (hence the step print). */ +/* clang-format off */ #define TEST_F_FORK (fixture_name, test_name) \ static void fixture_name##_##test_name##_child( \ struct __test_metadata *_metadata, \
@@ -75,6 +76,7 @@FIXTURE_DATA (fixture_name) __attribute__((unused)) *self, \ const FIXTURE_VARIANT(fixture_name) \ __attribute__((unused)) *variant) +/* clang-format on */ #ifndef landlock_create_ruleset static inline int landlock_create_ruleset(
tools/testing/selftests/landlock/fs_test.c +17 -6
@@ -221,8 +221,9 @@ static void remove_layout1(struct __testEXPECT_EQ (0 ,remove_path (dir_s3d2)); } -FIXTURE (layout1) { -}; +/* clang-format off */ +FIXTURE (layout1) {}; +/* clang-format on */ FIXTURE_SETUP (layout1) {
@@ -376,6 +377,8 @@ TEST_F_FORK(layout1, inval)ASSERT_EQ (0 ,close (ruleset_fd)); } +/* clang-format off */ +#define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \
@@ -396,6 +399,8 @@ TEST_F_FORK(layout1, inval) LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ ACCESS_LAST) +/* clang-format on */ + TEST_F_FORK(layout1, file_access_rights) {__u64 access;
@@ -452,6 +457,8 @@ struct rule {__u64 access; }; +/* clang-format off */ +#define ACCESS_RO ( \ LANDLOCK_ACCESS_FS_READ_FILE | \ LANDLOCK_ACCESS_FS_READ_DIR)
@@ -460,6 +467,8 @@ struct rule { ACCESS_RO | \ LANDLOCK_ACCESS_FS_WRITE_FILE) +/* clang-format on */ +static int create_ruleset (struct __test_metadata *const _metadata,const __u64 handled_access_fs,const struct rule rules[]) {
@@ -2070,8 +2079,9 @@ TEST_F_FORK(layout1, proc_pipe)ASSERT_EQ (0 ,close (pipe_fds[1 ])); } -FIXTURE (layout1_bind) { -}; +/* clang-format off */ +FIXTURE (layout1_bind) {}; +/* clang-format on */ FIXTURE_SETUP (layout1_bind) {
@@ -2411,8 +2421,9 @@ static const char (*merge_sub_files[])[]* └── work */ -FIXTURE (layout2_overlay) { -}; +/* clang-format off */ +FIXTURE (layout2_overlay) {}; +/* clang-format on */ FIXTURE_SETUP (layout2_overlay) {
tools/testing/selftests/landlock/ptrace_test.c +19 -1
@@ -59,7 +59,9 @@ static int test_ptrace_read(const pid_treturn 0 ; } -FIXTURE (hierarchy) { }; +/* clang-format off */ +FIXTURE (hierarchy) {}; +/* clang-format on */ FIXTURE_VARIANT (hierarchy) {const bool domain_both;
@@ -83,7 +85,9 @@ FIXTURE_VARIANT(hierarchy) {* \ P2 -> P1 : allow * 'P2 */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_without_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = false, .domain_child = false,
@@ -98,7 +102,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* | P2 | * '------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_with_one_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = false, .domain_child = true,
@@ -112,7 +118,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* ' * P2 */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_parent_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = true, .domain_child = false,
@@ -127,7 +135,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | P2 | * '------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_sibling_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = true, .domain_child = true,
@@ -142,7 +152,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | P2 | * '-------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_sibling_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = false, .domain_child = false,
@@ -158,7 +170,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_sib* | '------' | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_with_nested_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = false, .domain_child = true,
@@ -174,7 +188,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* | P2 | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_nested_and_parent_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = true, .domain_child = false,
@@ -192,7 +208,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | '------' | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_forked_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = true, .domain_child = true,
Greg Kroah-Hartman
maintainerPATCH 570/667 selftests/landlock: Normalize array assignment
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 135464f9d29c5b306d7201220f1d00dab30fea89 upstream.
Add a comma after each array value to make clang-format keep the current array formatting. See the following commit.
Automatically modified with:
sed -i 's/\t\({}\|NULL\)$/\0,/' tools/testing/selftests/landlock/fs_test.c
--- tools/testing/selftests/landlock/fs_test.c | 112 ++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-)
tools/testing/selftests/landlock/fs_test.c +56 -56
@@ -514,7 +514,7 @@ TEST_F_FORK(layout1, proc_nsfs) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };struct landlock_path_beneath_attr path_beneath; const int ruleset_fd = create_ruleset(_metadata, rules[0].access |
@@ -560,7 +560,7 @@ TEST_F_FORK(layout1, unpriv) { .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd;
@@ -588,7 +588,7 @@ TEST_F_FORK(layout1, effective_access) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);char buf;
@@ -635,7 +635,7 @@ TEST_F_FORK(layout1, unhandled_access) .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };/* Here, we only handle read accesses, not write accesses. */ const int ruleset_fd =create_ruleset (_metadata,ACCESS_RO , rules);
@@ -669,7 +669,7 @@ TEST_F_FORK(layout1, ruleset_overlap) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -703,14 +703,14 @@ TEST_F_FORK(layout1, non_overlapping_acc .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_REG, }, - {} + {}, };const struct rule layer2[] = { { .path = dir_s1d3, .access =LANDLOCK_ACCESS_FS_REMOVE_FILE , }, - {} + {}, };int ruleset_fd;
@@ -767,7 +767,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = file1_s1d3, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };/* First rule with write restrictions. */ const struct rule layer2_read_write[] = {
@@ -782,7 +782,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const struct rule layer3_read[] = { /* Allows read access via its great-grandparent directory. */
@@ -790,7 +790,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d1, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer4_read_write[] = {/*
@@ -801,7 +801,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer5_read[] = {/*
@@ -812,7 +812,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer6_execute[] = {/*
@@ -823,7 +823,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s2d1, .access = LANDLOCK_ACCESS_FS_EXECUTE, }, - {} + {}, };const struct rule layer7_read_write[] = {/*
@@ -834,7 +834,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;
@@ -932,7 +932,7 @@ TEST_F_FORK(layout1, inherit_subset) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1048,7 +1048,7 @@ TEST_F_FORK(layout1, inherit_superset) .path = dir_s1d3, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1084,7 +1084,7 @@ TEST_F_FORK(layout1, max_layers) .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1146,7 +1146,7 @@ TEST_F_FORK(layout1, rule_on_mountpoint) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1175,7 +1175,7 @@ TEST_F_FORK(layout1, rule_over_mountpoin .path = dir_s3d1, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1203,7 +1203,7 @@ TEST_F_FORK(layout1, rule_over_root_allo .path = "/", .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1233,7 +1233,7 @@ TEST_F_FORK(layout1, rule_over_root_deny .path = "/", .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1253,7 +1253,7 @@ TEST_F_FORK(layout1, rule_inside_mount_n .path = "s3d3", .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd;
@@ -1280,7 +1280,7 @@ TEST_F_FORK(layout1, mount_and_pivot) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1303,7 +1303,7 @@ TEST_F_FORK(layout1, move_mount) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1344,7 +1344,7 @@ TEST_F_FORK(layout1, release_inodes) .path = dir_s3d3, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1382,7 +1382,7 @@ static void test_relative_path(struct __ .path = TMP_DIR, .access = ACCESS_RO, }, - {} + {}, };const struct rule layer2_subs[] = { {
@@ -1393,7 +1393,7 @@ static void test_relative_path(struct __ .path = dir_s2d2, .access = ACCESS_RO, }, - {} + {}, };int dirfd, ruleset_fd;
@@ -1558,7 +1558,7 @@ TEST_F_FORK(layout1, execute) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_EXECUTE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1591,7 +1591,7 @@ TEST_F_FORK(layout1, link) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_REG, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1628,7 +1628,7 @@ TEST_F_FORK(layout1, rename_file) .path = dir_s2d2, .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1705,7 +1705,7 @@ TEST_F_FORK(layout1, rename_dir) .path = dir_s2d1, .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1759,7 +1759,7 @@ TEST_F_FORK(layout1, remove_dir) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1796,7 +1796,7 @@ TEST_F_FORK(layout1, remove_file) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1821,7 +1821,7 @@ static void test_make_file(struct __test .path = dir_s1d2, .access = access, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, access, rules);
@@ -1907,7 +1907,7 @@ TEST_F_FORK(layout1, make_sym) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_SYM, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1952,7 +1952,7 @@ TEST_F_FORK(layout1, make_dir) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1992,7 +1992,7 @@ TEST_F_FORK(layout1, proc_unlinked_file) .path = file1_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };int reg_fd, proc_fd; const int ruleset_fd = create_ruleset(_metadata,
@@ -2034,7 +2034,7 @@ TEST_F_FORK(layout1, proc_pipe) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };/* Limits read and write access to files tied to the filesystem. */ const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
@@ -2171,7 +2171,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s2d1, .access = ACCESS_RW, }, - {} + {}, };/* * Sets access rights on the same bind-mounted directories. The result
@@ -2187,7 +2187,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s2d2, .access = ACCESS_RW, }, - {} + {}, };/* Only allow read-access to the s1d3 hierarchies. */ const struct rule layer3_source[] = {
@@ -2195,7 +2195,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s1d3, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };/* Removes all access rights. */ const struct rule layer4_destination[] = {
@@ -2203,7 +2203,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = bind_file1_s1d3, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;
@@ -2305,18 +2305,18 @@ static const char lower_do1_fl3[] = LOWEstatic const char (*lower_base_files[])[] = { &lower_fl1, &lower_fo1, -NULL +NULL , };static const char (*lower_base_directories[])[] = { &lower_dl1, &lower_do1, -NULL +NULL , };static const char (*lower_sub_files[])[] = { &lower_dl1_fl2, &lower_do1_fo2, &lower_do1_fl3, -NULL +NULL , };#define UPPER_BASE TMP_DIR "/upper"
@@ -2333,18 +2333,18 @@ static const char upper_do1_fu3[] = UPPEstatic const char (*upper_base_files[])[] = { &upper_fu1, &upper_fo1, -NULL +NULL , };static const char (*upper_base_directories[])[] = { &upper_du1, &upper_do1, -NULL +NULL , };static const char (*upper_sub_files[])[] = { &upper_du1_fu2, &upper_do1_fo2, &upper_do1_fu3, -NULL +NULL , };#define MERGE_BASE TMP_DIR "/merge"
@@ -2365,13 +2365,13 @@ static const char (*merge_base_files[])[ &merge_fl1, &merge_fu1, &merge_fo1, -NULL + NULL, };static const char (*merge_base_directories[])[] = { &merge_dl1, &merge_du1, &merge_do1, -NULL +NULL , };static const char (*merge_sub_files[])[] = { &merge_dl1_fl2,
@@ -2379,7 +2379,7 @@ static const char (*merge_sub_files[])[] &merge_do1_fo2, &merge_do1_fl3, &merge_do1_fu3, - NULL + NULL, };/*
@@ -2544,7 +2544,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = MERGE_BASE, .access = ACCESS_RW, }, - {} + {}, };const struct rule layer2_data[] = { {
@@ -2559,7 +2559,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = MERGE_DATA, .access = ACCESS_RW, }, - {} + {}, };/* Sets access right on directories inside both layers. */ const struct rule layer3_subdirs[] = {
@@ -2591,7 +2591,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = merge_do1, .access = ACCESS_RW, }, - {} + {}, };/* Tighten access rights to the files. */ const struct rule layer4_files[] = {
@@ -2644,7 +2644,7 @@ TEST_F_FORK(layout2_overlay, same_conten .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const struct rule layer5_merge_only[] = { {
@@ -2652,7 +2652,7 @@ TEST_F_FORK(layout2_overlay, same_conten .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;size_t i;
Greg Kroah-Hartman
maintainerPATCH 571/667 selftests/landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 371183fa578a4cf56b3ae12e54b7f01a4249add1 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i tools/testing/selftests/landlock/*.[ch]
[mic: Update style according to
https://lore.kernel.org/r/[email protected]]
--- tools/testing/selftests/landlock/base_test.c | 80 ++--- tools/testing/selftests/landlock/common.h | 64 ++-- tools/testing/selftests/landlock/fs_test.c | 399 +++++++++++++------------ tools/testing/selftests/landlock/ptrace_test.c | 20 - 4 files changed, 312 insertions(+), 251 deletions(-)
tools/testing/selftests/landlock/base_test.c +46 -34
@@ -18,10 +18,11 @@#include "common.h" #ifndef O_PATH -#define O_PATH 010000000 +#define O_PATH 010000000#endif -TEST (inconsistent_attr) { +TEST (inconsistent_attr) +{const long page_size =sysconf (_SC_PAGESIZE);char *const buf =malloc (page_size +1 );struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
@@ -39,15 +40,16 @@ TEST(inconsistent_attr) {/* The size if less than sizeof(struct landlock_attr_enforce). */ ASSERT_EQ (EFAULT , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (NULL , -sizeof (struct landlock_ruleset_attr ),0 )); +ASSERT_EQ (-1 ,landlock_create_ruleset ( +NULL ,sizeof (struct landlock_ruleset_attr ),0 ));ASSERT_EQ (EFAULT , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size +1 ,0 ));ASSERT_EQ (E2BIG , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, -sizeof (struct landlock_ruleset_attr ),0 )); +ASSERT_EQ (-1 ,landlock_create_ruleset ( + ruleset_attr, +sizeof (struct landlock_ruleset_attr ),0 ));ASSERT_EQ (ENOMSG , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size,0 ));ASSERT_EQ (ENOMSG , errno);
@@ -63,32 +65,35 @@ TEST(inconsistent_attr) {free (buf); } -TEST (abi_version) { +TEST (abi_version) +{const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_READ_FILE , };ASSERT_EQ (1 ,landlock_create_ruleset (NULL ,0 , -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,0 , -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,sizeof (ruleset_attr), -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr), -LANDLOCK_CREATE_RULESET_VERSION )); +ASSERT_EQ (-1 , +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,0 , -LANDLOCK_CREATE_RULESET_VERSION |1 <<31 )); +LANDLOCK_CREATE_RULESET_VERSION | +1 <<31 ));ASSERT_EQ (EINVAL , errno); } -TEST (inval_create_ruleset_flags) { +TEST (inval_create_ruleset_flags) +{const int last_flag =LANDLOCK_CREATE_RULESET_VERSION ;const int invalid_flag = last_flag <<1 ;const struct landlock_ruleset_attr ruleset_attr = {
@@ -102,38 +107,42 @@ TEST(inval_create_ruleset_flags) {ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,sizeof (ruleset_attr), - invalid_flag)); + invalid_flag));ASSERT_EQ (EINVAL , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr), invalid_flag)); +ASSERT_EQ (-1 , +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), + invalid_flag));ASSERT_EQ (EINVAL , errno); } -TEST (empty_path_beneath_attr) { +TEST (empty_path_beneath_attr) +{const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_EXECUTE , }; -const int ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); +const int ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd);/* Similar to struct landlock_path_beneath_attr.parent_fd = 0 */ ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , -NULL ,0 )); +NULL ,0 ));ASSERT_EQ (EFAULT , errno);ASSERT_EQ (0 ,close (ruleset_fd)); } -TEST (inval_fd_enforce) { +TEST (inval_fd_enforce) +{ASSERT_EQ (0 ,prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 ));ASSERT_EQ (-1 ,landlock_restrict_self (-1 ,0 ));ASSERT_EQ (EBADF , errno); } -TEST (unpriv_enforce_without_no_new_privs) { +TEST (unpriv_enforce_without_no_new_privs) +{int err;drop_caps (_metadata);
@@ -151,8 +160,8 @@ TEST(ruleset_fd_io)char buf;drop_caps (_metadata); - ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd);ASSERT_EQ (-1 ,write (ruleset_fd,"." ,1 ));
@@ -197,14 +206,15 @@ TEST(ruleset_fd_transfer)drop_caps (_metadata);/* Creates a test ruleset with a simple rule. */ - ruleset_fd_tx =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); + ruleset_fd_tx = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd_tx); - path_beneath_attr.parent_fd =open ("/tmp" ,O_PATH |O_NOFOLLOW | -O_DIRECTORY |O_CLOEXEC ); + path_beneath_attr.parent_fd = +open ("/tmp" ,O_PATH |O_NOFOLLOW |O_DIRECTORY |O_CLOEXEC );ASSERT_LE (0 , path_beneath_attr.parent_fd); -ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd_tx,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath_attr,0 )); +ASSERT_EQ (0 , +landlock_add_rule (ruleset_fd_tx,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 ));ASSERT_EQ (0 ,close (path_beneath_attr.parent_fd)); cmsg =CMSG_FIRSTHDR (&msg);
@@ -215,7 +225,8 @@ TEST(ruleset_fd_transfer)memcpy (CMSG_DATA (cmsg), &ruleset_fd_tx,sizeof (ruleset_fd_tx));/* Sends the ruleset FD over a socketpair and then close it. */ -ASSERT_EQ (0 ,socketpair (AF_UNIX ,SOCK_STREAM |SOCK_CLOEXEC ,0 , socket_fds)); +ASSERT_EQ (0 ,socketpair (AF_UNIX ,SOCK_STREAM |SOCK_CLOEXEC ,0 , + socket_fds));ASSERT_EQ (sizeof (data_tx),sendmsg (socket_fds[0 ], &msg,0 ));ASSERT_EQ (0 ,close (socket_fds[0 ]));ASSERT_EQ (0 ,close (ruleset_fd_tx));
@@ -226,7 +237,8 @@ TEST(ruleset_fd_transfer)int ruleset_fd_rx; *(char *)msg.msg_iov->iov_base ='\0' ; -ASSERT_EQ (sizeof (data_tx),recvmsg (socket_fds[1 ], &msg,MSG_CMSG_CLOEXEC )); +ASSERT_EQ (sizeof (data_tx), +recvmsg (socket_fds[1 ], &msg,MSG_CMSG_CLOEXEC ));ASSERT_EQ ('.' , *(char *)msg.msg_iov->iov_base);ASSERT_EQ (0 ,close (socket_fds[1 ])); cmsg =CMSG_FIRSTHDR (&msg);
tools/testing/selftests/landlock/common.h +36 -28
131 lines not on this page · raw message
tools/testing/selftests/landlock/fs_test.c +218 -181
1,021 lines not on this page · raw message
tools/testing/selftests/landlock/ptrace_test.c +12 -8
@@ -26,9 +26,10 @@ static void create_domain(struct __test_ .handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_BLOCK, }; - ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); - EXPECT_LE(0, ruleset_fd) { + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); + EXPECT_LE(0, ruleset_fd) + {TH_LOG ("Failed to create a ruleset: %s" ,strerror (errno)); }EXPECT_EQ (0 ,prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 ));
@@ -43,7 +44,7 @@ static int test_ptrace_read(const pid_tint procenv_path_size, fd; procenv_path_size =snprintf (procenv_path,sizeof (procenv_path), - path_template, pid); + path_template, pid);if (procenv_path_size >=sizeof (procenv_path))return E2BIG ;
@@ -63,7 +64,8 @@ static int test_ptrace_read(const pid_tFIXTURE (hierarchy) {};/* clang-format on */ -FIXTURE_VARIANT (hierarchy) { +FIXTURE_VARIANT (hierarchy) +{const bool domain_both;const bool domain_parent;const bool domain_child;
@@ -217,10 +219,12 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with };FIXTURE_SETUP (hierarchy) -{ } +{ +}FIXTURE_TEARDOWN (hierarchy) -{ } +{ +}/* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */ TEST_F (hierarchy, trace)
@@ -348,7 +352,7 @@ TEST_F(hierarchy, trace)ASSERT_EQ (1 ,write (pipe_parent[1 ],"." ,1 ));ASSERT_EQ (child,waitpid (child, &status,0 ));if (WIFSIGNALED (status) || !WIFEXITED (status) || -WEXITSTATUS (status) !=EXIT_SUCCESS ) +WEXITSTATUS (status) !=EXIT_SUCCESS ) _metadata->passed =0 ; }
Greg Kroah-Hartman
maintainerPATCH 572/667 samples/landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 9805a722db071e1772b80e6e0ff33f35355639ac upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions. This enables to keep aligned values, which is much more readable than packed definitions.
--- samples/landlock/sandboxer.c | 8 ++++++++ 1 file changed, 8 insertions(+)
samples/landlock/sandboxer.c +8 -0
@@ -70,11 +70,15 @@ static int parse_path(char *env_path, coreturn num_paths; } +/* clang-format off */ +#define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE) +/* clang-format on */ +static int populate_ruleset (const char *const env_var,const int ruleset_fd,const __u64 allowed_access)
@@ -139,6 +143,8 @@ out_free_name:return ret; } +/* clang-format off */ +#define ACCESS_FS_ROUGHLY_READ ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_READ_FILE | \
@@ -156,6 +162,8 @@ out_free_name: LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ LANDLOCK_ACCESS_FS_MAKE_SYM) +/* clang-format on */ +int main (const int argc,char *const argv[],char *const *const envp) {const char *cmd_path;
Greg Kroah-Hartman
maintainerPATCH 573/667 samples/landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 81709f3dccacf4104a4bc2daa80bdd767a9c4c54 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i samples/landlock/*.[ch]
--- samples/landlock/sandboxer.c | 96 +++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 44 deletions(-)
samples/landlock/sandboxer.c +52 -44
@@ -22,9 +22,9 @@#include <unistd.h> #ifndef landlock_create_ruleset -static inline int landlock_create_ruleset ( -const struct landlock_ruleset_attr *const attr, -const size_t size,const __u32 flags) +static inline int +landlock_create_ruleset (const struct landlock_ruleset_attr *const attr, +const size_t size,const __u32 flags) {return syscall (__NR_landlock_create_ruleset, attr, size, flags); }
@@ -32,17 +32,18 @@ static inline int landlock_create_rulese#ifndef landlock_add_rulestatic inline int landlock_add_rule (const int ruleset_fd, -const enum landlock_rule_type rule_type, -const void *const rule_attr,const __u32 flags) +const enum landlock_rule_type rule_type, +const void *const rule_attr, +const __u32 flags) { -return syscall (__NR_landlock_add_rule, ruleset_fd, rule_type, - rule_attr, flags); +return syscall (__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, + flags); }#endif #ifndef landlock_restrict_selfstatic inline int landlock_restrict_self (const int ruleset_fd, -const __u32 flags) +const __u32 flags) {return syscall (__NR_landlock_restrict_self, ruleset_fd, flags); }
@@ -79,9 +80,8 @@ static int parse_path(char *env_path, co/* clang-format on */ -static int populate_ruleset ( -const char *const env_var,const int ruleset_fd, -const __u64 allowed_access) +static int populate_ruleset (const char *const env_var,const int ruleset_fd, +const __u64 allowed_access) {int num_paths, i, ret =1 ;char *env_path_name;
@@ -111,12 +111,10 @@ static int populate_ruleset(for (i =0 ; i < num_paths; i++) {struct stat statbuf; - path_beneath.parent_fd =open (path_list[i],O_PATH | -O_CLOEXEC ); + path_beneath.parent_fd =open (path_list[i],O_PATH |O_CLOEXEC );if (path_beneath.parent_fd <0 ) {fprintf (stderr,"Failed to open \"%s\": %s\n" , - path_list[i], -strerror (errno)); + path_list[i],strerror (errno)); goto out_free_name; }if (fstat (path_beneath.parent_fd, &statbuf)) {
@@ -127,9 +125,10 @@ static int populate_ruleset(if (!S_ISDIR (statbuf.st_mode)) path_beneath.allowed_access &=ACCESS_FILE ;if (landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath,0 )) { -fprintf (stderr,"Failed to update the ruleset with \"%s\": %s\n" , - path_list[i],strerror (errno)); + &path_beneath,0 )) { +fprintf (stderr, +"Failed to update the ruleset with \"%s\": %s\n" , + path_list[i],strerror (errno));close (path_beneath.parent_fd); goto out_free_name; }
@@ -171,55 +170,64 @@ int main(const int argc, char *const argint ruleset_fd;struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =ACCESS_FS_ROUGHLY_READ | -ACCESS_FS_ROUGHLY_WRITE , +ACCESS_FS_ROUGHLY_WRITE , };if (argc <2 ) { -fprintf (stderr,"usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n" , -ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); -fprintf (stderr,"Launch a command in a restricted environment.\n\n" ); +fprintf (stderr, +"usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n" , +ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); +fprintf (stderr, +"Launch a command in a restricted environment.\n\n" );fprintf (stderr,"Environment variables containing paths, " "each separated by a colon:\n" ); -fprintf (stderr,"* %s: list of paths allowed to be used in a read-only way.\n" , -ENV_FS_RO_NAME ); -fprintf (stderr,"* %s: list of paths allowed to be used in a read-write way.\n" , -ENV_FS_RW_NAME ); -fprintf (stderr,"\nexample:\n" -"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" " -"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " -"%s bash -i\n" , -ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); +fprintf (stderr, +"* %s: list of paths allowed to be used in a read-only way.\n" , +ENV_FS_RO_NAME ); +fprintf (stderr, +"* %s: list of paths allowed to be used in a read-write way.\n" , +ENV_FS_RW_NAME ); +fprintf (stderr, +"\nexample:\n" +"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" " +"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " +"%s bash -i\n" , +ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]);return 1 ; } - ruleset_fd =landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );if (ruleset_fd <0 ) {const int err = errno;perror ("Failed to create a ruleset" );switch (err) {case ENOSYS : -fprintf (stderr,"Hint: Landlock is not supported by the current kernel. " -"To support it, build the kernel with " -"CONFIG_SECURITY_LANDLOCK=y and prepend " -"\"landlock,\" to the content of CONFIG_LSM.\n" ); +fprintf (stderr, +"Hint: Landlock is not supported by the current kernel. " +"To support it, build the kernel with " +"CONFIG_SECURITY_LANDLOCK=y and prepend " +"\"landlock,\" to the content of CONFIG_LSM.\n" );break ;case EOPNOTSUPP : -fprintf (stderr,"Hint: Landlock is currently disabled. " -"It can be enabled in the kernel configuration by " -"prepending \"landlock,\" to the content of CONFIG_LSM, " -"or at boot time by setting the same content to the " -"\"lsm\" kernel parameter.\n" ); +fprintf (stderr, +"Hint: Landlock is currently disabled. " +"It can be enabled in the kernel configuration by " +"prepending \"landlock,\" to the content of CONFIG_LSM, " +"or at boot time by setting the same content to the " +"\"lsm\" kernel parameter.\n" );break ; }return 1 ; }if (populate_ruleset (ENV_FS_RO_NAME , ruleset_fd, -ACCESS_FS_ROUGHLY_READ )) { +ACCESS_FS_ROUGHLY_READ )) { goto err_close_ruleset; }if (populate_ruleset (ENV_FS_RW_NAME , ruleset_fd, -ACCESS_FS_ROUGHLY_READ |ACCESS_FS_ROUGHLY_WRITE )) { +ACCESS_FS_ROUGHLY_READ | +ACCESS_FS_ROUGHLY_WRITE )) { goto err_close_ruleset; }if (prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 )) {
@@ -236,7 +244,7 @@ int main(const int argc, char *const arg cmd_argv = argv +1 ;execvpe (cmd_path, cmd_argv, envp);fprintf (stderr,"Failed to execute \"%s\": %s\n" , cmd_path, -strerror (errno)); +strerror (errno));fprintf (stderr,"Hint: access to the binary, the interpreter or " "shared libraries may be denied.\n" );return 1 ;
Greg Kroah-Hartman
maintainerPATCH 574/667 landlock: Fix landlock_add_rule(2) documentation
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit a13e248ff90e81e9322406c0e618cf2168702f4e upstream.
It is not mandatory to pass a file descriptor obtained with the O_PATH flag. Also, replace rule's accesses with ruleset's accesses.
--- include/uapi/linux/landlock.h | 5 +++-- security/landlock/syscalls.c | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-)
include/uapi/linux/landlock.h +3 -2
@@ -62,8 +62,9 @@ struct landlock_path_beneath_attr {*/ __u64 allowed_access;/** -* @parent_fd: File descriptor, open with ``O_PATH``, which identifies -* the parent directory of a file hierarchy, or just a file. +* @parent_fd: File descriptor, preferably opened with ``O_PATH``, +* which identifies the parent directory of a file hierarchy, or just a +* file. */ __s32 parent_fd;/*
security/landlock/syscalls.c +3 -4
@@ -292,14 +292,13 @@ out_fdput:* * - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. -* &landlock_path_beneath_attr.allowed_access is not a subset of the rule's -* accesses); +* &landlock_path_beneath_attr.allowed_access is not a subset of the +* ruleset handled accesses); * - ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); * - EBADF: @ruleset_fd is not a file descriptor for the current thread, or a * member of @rule_attr is not a file descriptor as expected; * - EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of -* @rule_attr is not the expected file descriptor type (e.g. file open -* without O_PATH); +* @rule_attr is not the expected file descriptor type; * - EPERM: @ruleset_fd has no write access to the underlying ruleset; * - EFAULT: @rule_attr inconsistency. */