Message ID | 20240819122401.513203-1-mpe@ellerman.id.au (mailing list archive) |
---|---|
State | Under Review |
Headers | show |
Series | powerpc/pseries: Fix dtl_access_lock to be a rw_semaphore | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/github-powerpc_selftests | success | Successfully ran 8 jobs. |
snowpatch_ozlabs/github-powerpc_ppctests | success | Successfully ran 8 jobs. |
snowpatch_ozlabs/github-powerpc_kernel_qemu | success | Successfully ran 21 jobs. |
snowpatch_ozlabs/github-powerpc_clang | success | Successfully ran 5 jobs. |
snowpatch_ozlabs/github-powerpc_sparse | success | Successfully ran 4 jobs. |
On Mon, Aug 19, 2024 at 10:24:01PM GMT, Michael Ellerman wrote: <snip> > Fixes: 06220d78f24a ("powerpc/pseries: Introduce rwlock to gatekeep DTLB usage") > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > --- > arch/powerpc/include/asm/dtl.h | 3 ++- > arch/powerpc/platforms/pseries/dtl.c | 8 ++++---- > arch/powerpc/platforms/pseries/lpar.c | 8 ++++---- > 3 files changed, 10 insertions(+), 9 deletions(-) > > diff --git a/arch/powerpc/include/asm/dtl.h b/arch/powerpc/include/asm/dtl.h > index d6f43d149f8d..e21bac6c065c 100644 > --- a/arch/powerpc/include/asm/dtl.h > +++ b/arch/powerpc/include/asm/dtl.h > @@ -1,6 +1,7 @@ > #ifndef _ASM_POWERPC_DTL_H > #define _ASM_POWERPC_DTL_H > > +#include <linux/rwsem.h> > #include <asm/lppaca.h> > #include <linux/spinlock_types.h> The above include is redundant now and can be removed. Reviewed-by: Nysal Jan K.A <nysal@linux.ibm.com> > > @@ -35,7 +36,7 @@ struct dtl_entry { > #define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT) > > extern struct kmem_cache *dtl_cache; > -extern rwlock_t dtl_access_lock; > +extern struct rw_semaphore dtl_access_lock; > > extern void register_dtl_buffer(int cpu); > extern void alloc_dtl_buffers(unsigned long *time_limit); > diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c > index 3f1cdccebc9c..ecc04ef8c53e 100644 > --- a/arch/powerpc/platforms/pseries/dtl.c > +++ b/arch/powerpc/platforms/pseries/dtl.c > @@ -191,7 +191,7 @@ static int dtl_enable(struct dtl *dtl) > return -EBUSY; > > /* ensure there are no other conflicting dtl users */ > - if (!read_trylock(&dtl_access_lock)) > + if (!down_read_trylock(&dtl_access_lock)) > return -EBUSY; > > n_entries = dtl_buf_entries; > @@ -199,7 +199,7 @@ static int dtl_enable(struct dtl *dtl) > if (!buf) { > printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", > __func__, dtl->cpu); > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > return -ENOMEM; > } > > @@ -217,7 +217,7 @@ static int dtl_enable(struct dtl *dtl) > spin_unlock(&dtl->lock); > > if (rc) { > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > kmem_cache_free(dtl_cache, buf); > } > > @@ -232,7 +232,7 @@ static void dtl_disable(struct dtl *dtl) > dtl->buf = NULL; > dtl->buf_entries = 0; > spin_unlock(&dtl->lock); > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > } > > /* file interface */ > diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c > index c1d8bee8f701..bb09990eec30 100644 > --- a/arch/powerpc/platforms/pseries/lpar.c > +++ b/arch/powerpc/platforms/pseries/lpar.c > @@ -169,7 +169,7 @@ struct vcpu_dispatch_data { > */ > #define NR_CPUS_H NR_CPUS > > -DEFINE_RWLOCK(dtl_access_lock); > +DECLARE_RWSEM(dtl_access_lock); > static DEFINE_PER_CPU(struct vcpu_dispatch_data, vcpu_disp_data); > static DEFINE_PER_CPU(u64, dtl_entry_ridx); > static DEFINE_PER_CPU(struct dtl_worker, dtl_workers); > @@ -463,7 +463,7 @@ static int dtl_worker_enable(unsigned long *time_limit) > { > int rc = 0, state; > > - if (!write_trylock(&dtl_access_lock)) { > + if (!down_write_trylock(&dtl_access_lock)) { > rc = -EBUSY; > goto out; > } > @@ -479,7 +479,7 @@ static int dtl_worker_enable(unsigned long *time_limit) > pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n"); > free_dtl_buffers(time_limit); > reset_global_dtl_mask(); > - write_unlock(&dtl_access_lock); > + up_write(&dtl_access_lock); > rc = -EINVAL; > goto out; > } > @@ -494,7 +494,7 @@ static void dtl_worker_disable(unsigned long *time_limit) > cpuhp_remove_state(dtl_worker_state); > free_dtl_buffers(time_limit); > reset_global_dtl_mask(); > - write_unlock(&dtl_access_lock); > + up_write(&dtl_access_lock); > } > > static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p, > -- > 2.46.0 > >
Hi Michael, Thanks for the patch, the patch looks fine to me. Tested-by: Kajol Jain<kjain@linux.ibm.com> Reviewed-by: Kajol Jain<kjain@linux.ibm.com> Thanks, Kajol Jain On 8/19/24 17:54, Michael Ellerman wrote: > The dtl_access_lock needs to be a rw_sempahore, a sleeping lock, because > the code calls kmalloc() while holding it, which can sleep: > > # echo 1 > /proc/powerpc/vcpudispatch_stats > BUG: sleeping function called from invalid context at include/linux/sched/mm.h:337 > in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 199, name: sh > preempt_count: 1, expected: 0 > 3 locks held by sh/199: > #0: c00000000a0743f8 (sb_writers#3){.+.+}-{0:0}, at: vfs_write+0x324/0x438 > #1: c0000000028c7058 (dtl_enable_mutex){+.+.}-{3:3}, at: vcpudispatch_stats_write+0xd4/0x5f4 > #2: c0000000028c70b8 (dtl_access_lock){+.+.}-{2:2}, at: vcpudispatch_stats_write+0x220/0x5f4 > CPU: 0 PID: 199 Comm: sh Not tainted 6.10.0-rc4 #152 > Hardware name: IBM pSeries (emulated by qemu) POWER9 (raw) 0x4e1202 0xf000005 of:SLOF,HEAD hv:linux,kvm pSeries > Call Trace: > dump_stack_lvl+0x130/0x148 (unreliable) > __might_resched+0x174/0x410 > kmem_cache_alloc_noprof+0x340/0x3d0 > alloc_dtl_buffers+0x124/0x1ac > vcpudispatch_stats_write+0x2a8/0x5f4 > proc_reg_write+0xf4/0x150 > vfs_write+0xfc/0x438 > ksys_write+0x88/0x148 > system_call_exception+0x1c4/0x5a0 > system_call_common+0xf4/0x258 > > Fixes: 06220d78f24a ("powerpc/pseries: Introduce rwlock to gatekeep DTLB usage") > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > --- > arch/powerpc/include/asm/dtl.h | 3 ++- > arch/powerpc/platforms/pseries/dtl.c | 8 ++++---- > arch/powerpc/platforms/pseries/lpar.c | 8 ++++---- > 3 files changed, 10 insertions(+), 9 deletions(-) > > diff --git a/arch/powerpc/include/asm/dtl.h b/arch/powerpc/include/asm/dtl.h > index d6f43d149f8d..e21bac6c065c 100644 > --- a/arch/powerpc/include/asm/dtl.h > +++ b/arch/powerpc/include/asm/dtl.h > @@ -1,6 +1,7 @@ > #ifndef _ASM_POWERPC_DTL_H > #define _ASM_POWERPC_DTL_H > > +#include <linux/rwsem.h> > #include <asm/lppaca.h> > #include <linux/spinlock_types.h> > > @@ -35,7 +36,7 @@ struct dtl_entry { > #define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT) > > extern struct kmem_cache *dtl_cache; > -extern rwlock_t dtl_access_lock; > +extern struct rw_semaphore dtl_access_lock; > > extern void register_dtl_buffer(int cpu); > extern void alloc_dtl_buffers(unsigned long *time_limit); > diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c > index 3f1cdccebc9c..ecc04ef8c53e 100644 > --- a/arch/powerpc/platforms/pseries/dtl.c > +++ b/arch/powerpc/platforms/pseries/dtl.c > @@ -191,7 +191,7 @@ static int dtl_enable(struct dtl *dtl) > return -EBUSY; > > /* ensure there are no other conflicting dtl users */ > - if (!read_trylock(&dtl_access_lock)) > + if (!down_read_trylock(&dtl_access_lock)) > return -EBUSY; > > n_entries = dtl_buf_entries; > @@ -199,7 +199,7 @@ static int dtl_enable(struct dtl *dtl) > if (!buf) { > printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", > __func__, dtl->cpu); > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > return -ENOMEM; > } > > @@ -217,7 +217,7 @@ static int dtl_enable(struct dtl *dtl) > spin_unlock(&dtl->lock); > > if (rc) { > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > kmem_cache_free(dtl_cache, buf); > } > > @@ -232,7 +232,7 @@ static void dtl_disable(struct dtl *dtl) > dtl->buf = NULL; > dtl->buf_entries = 0; > spin_unlock(&dtl->lock); > - read_unlock(&dtl_access_lock); > + up_read(&dtl_access_lock); > } > > /* file interface */ > diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c > index c1d8bee8f701..bb09990eec30 100644 > --- a/arch/powerpc/platforms/pseries/lpar.c > +++ b/arch/powerpc/platforms/pseries/lpar.c > @@ -169,7 +169,7 @@ struct vcpu_dispatch_data { > */ > #define NR_CPUS_H NR_CPUS > > -DEFINE_RWLOCK(dtl_access_lock); > +DECLARE_RWSEM(dtl_access_lock); > static DEFINE_PER_CPU(struct vcpu_dispatch_data, vcpu_disp_data); > static DEFINE_PER_CPU(u64, dtl_entry_ridx); > static DEFINE_PER_CPU(struct dtl_worker, dtl_workers); > @@ -463,7 +463,7 @@ static int dtl_worker_enable(unsigned long *time_limit) > { > int rc = 0, state; > > - if (!write_trylock(&dtl_access_lock)) { > + if (!down_write_trylock(&dtl_access_lock)) { > rc = -EBUSY; > goto out; > } > @@ -479,7 +479,7 @@ static int dtl_worker_enable(unsigned long *time_limit) > pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n"); > free_dtl_buffers(time_limit); > reset_global_dtl_mask(); > - write_unlock(&dtl_access_lock); > + up_write(&dtl_access_lock); > rc = -EINVAL; > goto out; > } > @@ -494,7 +494,7 @@ static void dtl_worker_disable(unsigned long *time_limit) > cpuhp_remove_state(dtl_worker_state); > free_dtl_buffers(time_limit); > reset_global_dtl_mask(); > - write_unlock(&dtl_access_lock); > + up_write(&dtl_access_lock); > } > > static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
diff --git a/arch/powerpc/include/asm/dtl.h b/arch/powerpc/include/asm/dtl.h index d6f43d149f8d..e21bac6c065c 100644 --- a/arch/powerpc/include/asm/dtl.h +++ b/arch/powerpc/include/asm/dtl.h @@ -1,6 +1,7 @@ #ifndef _ASM_POWERPC_DTL_H #define _ASM_POWERPC_DTL_H +#include <linux/rwsem.h> #include <asm/lppaca.h> #include <linux/spinlock_types.h> @@ -35,7 +36,7 @@ struct dtl_entry { #define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT) extern struct kmem_cache *dtl_cache; -extern rwlock_t dtl_access_lock; +extern struct rw_semaphore dtl_access_lock; extern void register_dtl_buffer(int cpu); extern void alloc_dtl_buffers(unsigned long *time_limit); diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 3f1cdccebc9c..ecc04ef8c53e 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -191,7 +191,7 @@ static int dtl_enable(struct dtl *dtl) return -EBUSY; /* ensure there are no other conflicting dtl users */ - if (!read_trylock(&dtl_access_lock)) + if (!down_read_trylock(&dtl_access_lock)) return -EBUSY; n_entries = dtl_buf_entries; @@ -199,7 +199,7 @@ static int dtl_enable(struct dtl *dtl) if (!buf) { printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", __func__, dtl->cpu); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); return -ENOMEM; } @@ -217,7 +217,7 @@ static int dtl_enable(struct dtl *dtl) spin_unlock(&dtl->lock); if (rc) { - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); kmem_cache_free(dtl_cache, buf); } @@ -232,7 +232,7 @@ static void dtl_disable(struct dtl *dtl) dtl->buf = NULL; dtl->buf_entries = 0; spin_unlock(&dtl->lock); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); } /* file interface */ diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index c1d8bee8f701..bb09990eec30 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -169,7 +169,7 @@ struct vcpu_dispatch_data { */ #define NR_CPUS_H NR_CPUS -DEFINE_RWLOCK(dtl_access_lock); +DECLARE_RWSEM(dtl_access_lock); static DEFINE_PER_CPU(struct vcpu_dispatch_data, vcpu_disp_data); static DEFINE_PER_CPU(u64, dtl_entry_ridx); static DEFINE_PER_CPU(struct dtl_worker, dtl_workers); @@ -463,7 +463,7 @@ static int dtl_worker_enable(unsigned long *time_limit) { int rc = 0, state; - if (!write_trylock(&dtl_access_lock)) { + if (!down_write_trylock(&dtl_access_lock)) { rc = -EBUSY; goto out; } @@ -479,7 +479,7 @@ static int dtl_worker_enable(unsigned long *time_limit) pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n"); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); rc = -EINVAL; goto out; } @@ -494,7 +494,7 @@ static void dtl_worker_disable(unsigned long *time_limit) cpuhp_remove_state(dtl_worker_state); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); } static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
The dtl_access_lock needs to be a rw_sempahore, a sleeping lock, because the code calls kmalloc() while holding it, which can sleep: # echo 1 > /proc/powerpc/vcpudispatch_stats BUG: sleeping function called from invalid context at include/linux/sched/mm.h:337 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 199, name: sh preempt_count: 1, expected: 0 3 locks held by sh/199: #0: c00000000a0743f8 (sb_writers#3){.+.+}-{0:0}, at: vfs_write+0x324/0x438 #1: c0000000028c7058 (dtl_enable_mutex){+.+.}-{3:3}, at: vcpudispatch_stats_write+0xd4/0x5f4 #2: c0000000028c70b8 (dtl_access_lock){+.+.}-{2:2}, at: vcpudispatch_stats_write+0x220/0x5f4 CPU: 0 PID: 199 Comm: sh Not tainted 6.10.0-rc4 #152 Hardware name: IBM pSeries (emulated by qemu) POWER9 (raw) 0x4e1202 0xf000005 of:SLOF,HEAD hv:linux,kvm pSeries Call Trace: dump_stack_lvl+0x130/0x148 (unreliable) __might_resched+0x174/0x410 kmem_cache_alloc_noprof+0x340/0x3d0 alloc_dtl_buffers+0x124/0x1ac vcpudispatch_stats_write+0x2a8/0x5f4 proc_reg_write+0xf4/0x150 vfs_write+0xfc/0x438 ksys_write+0x88/0x148 system_call_exception+0x1c4/0x5a0 system_call_common+0xf4/0x258 Fixes: 06220d78f24a ("powerpc/pseries: Introduce rwlock to gatekeep DTLB usage") Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> --- arch/powerpc/include/asm/dtl.h | 3 ++- arch/powerpc/platforms/pseries/dtl.c | 8 ++++---- arch/powerpc/platforms/pseries/lpar.c | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-)