On 8/11/20 6:20 PM, Nathan Lynch wrote: > The drmem lmb list can have hundreds of thousands of entries, and > unfortunately lookups take the form of linear searches. As long as > this is the case, traversals have the potential to monopolize the CPU > and provoke lockup reports, workqueue stalls, and the like unless > they explicitly yield. > > Rather than placing cond_resched() calls within various > for_each_drmem_lmb() loop blocks in the code, put it in the iteration > expression of the loop macro itself so users can't omit it. > > Call cond_resched() on every 20th element. Each iteration of the loop > in DLPAR code paths can involve around ten RTAS calls which can each > take up to 250us, so this ensures the check is performed at worst > every few milliseconds. > > Fixes: 6c6ea53725b3 ("powerpc/mm: Separate ibm, dynamic-memory data from DT > format") > Signed-off-by: Nathan Lynch <nath...@linux.ibm.com> > --- > arch/powerpc/include/asm/drmem.h | 18 +++++++++++++++++- > 1 file changed, 17 insertions(+), 1 deletion(-) > > Changes since v1: > * Add bounds assertions in drmem_lmb_next(). > * Call cond_resched() in the iterator on only every 20th element > instead of on every iteration, to reduce overhead in tight loops. > > diff --git a/arch/powerpc/include/asm/drmem.h > b/arch/powerpc/include/asm/drmem.h > index 17ccc6474ab6..583277e30dd2 100644 > --- a/arch/powerpc/include/asm/drmem.h > +++ b/arch/powerpc/include/asm/drmem.h > @@ -8,6 +8,9 @@ > #ifndef _ASM_POWERPC_LMB_H > #define _ASM_POWERPC_LMB_H > > +#include <linux/bug.h> > +#include <linux/sched.h> > + > struct drmem_lmb { > u64 base_addr; > u32 drc_index; > @@ -26,8 +29,21 @@ struct drmem_lmb_info { > > extern struct drmem_lmb_info *drmem_info; > > +static inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb) > +{ > + const unsigned int resched_interval = 20; > + > + BUG_ON(lmb < drmem_info->lmbs); > + BUG_ON(lmb >= drmem_info->lmbs + drmem_info->n_lmbs);
I think BUG_ON is a pretty big no-no these days unless there is no other option. -Tyrel > + > + if ((lmb - drmem_info->lmbs) % resched_interval == 0) > + cond_resched(); > + > + return ++lmb; > +} > + > #define for_each_drmem_lmb_in_range(lmb, start, end) \ > - for ((lmb) = (start); (lmb) < (end); (lmb)++) > + for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb)) > > #define for_each_drmem_lmb(lmb) \ > for_each_drmem_lmb_in_range((lmb), \ >