diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2020-03-20 19:04:01 +0100 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2020-03-20 19:04:01 +0100 |
commit | 0443a3044a15a8cb1fcca0997b637d5887909715 (patch) | |
tree | 34c57144b8fd90cc54836d588daf199de96e27cf | |
parent | a023c98f0d22c1f8f1723c4531b399500647a302 (diff) | |
download | linux-rt-5.4.26-rt17-patches.tar.gz |
[ANNOUNCE] v5.4.26-rt17v5.4.26-rt17-patches
Dear RT folks!
I'm pleased to announce the v5.4.26-rt17 patch set.
Changes since v5.4.26-rt16:
- Revert the "cross CPU pagevec" access with a static key switch. The
old behaviour has been almost fully restored: There is no cross CPU
access of the local_lock. Instead the workqueue is scheduled on
remote CPU like in the !RT case.
- Make the `sched_clock_timer' timer expire in hardirq. Patch by Ahmed
S. Darwish.
- The preempt-lazy code on 32-bit PowerPC used the wrong mask and
eventually crashed. Patch by Thomas Graziadei.
- Remove the warning with more than two waiters on completion which
was woken up via complete_all().
Known issues
- It has been pointed out that due to changes to the printk code the
internal buffer representation changed. This is only an issue if tools
like `crash' are used to extract the printk buffer from a kernel memory
image.
The delta patch against v5.4.26-rt16 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.4/incr/patch-5.4.26-rt16-rt17.patch.xz
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v5.4.26-rt17
The RT patch against v5.4.26 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.4/older/patch-5.4.26-rt17.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.4/older/patches-5.4.26-rt17.tar.xz
Sebastian
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
24 files changed, 339 insertions, 799 deletions
diff --git a/patches/0001-cgroup-Remove-css_rstat_flush.patch b/patches/0001-cgroup-Remove-css_rstat_flush.patch index 90beaeb143a9..f6af9f34efc3 100644 --- a/patches/0001-cgroup-Remove-css_rstat_flush.patch +++ b/patches/0001-cgroup-Remove-css_rstat_flush.patch @@ -54,7 +54,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> prev_cputime_init(&cgrp->prev_cputime); for_each_subsys(ss, ssid) -@@ -5014,12 +5013,6 @@ static void css_release_work_fn(struct w +@@ -5027,12 +5026,6 @@ static void css_release_work_fn(struct w list_del_rcu(&css->sibling); if (ss) { @@ -67,7 +67,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> cgroup_idr_replace(&ss->css_idr, NULL, css->id); if (ss->css_released) ss->css_released(css); -@@ -5081,7 +5074,6 @@ static void init_and_link_css(struct cgr +@@ -5094,7 +5087,6 @@ static void init_and_link_css(struct cgr css->id = -1; INIT_LIST_HEAD(&css->sibling); INIT_LIST_HEAD(&css->children); @@ -75,7 +75,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> css->serial_nr = css_serial_nr_next++; atomic_set(&css->online_cnt, 0); -@@ -5090,9 +5082,6 @@ static void init_and_link_css(struct cgr +@@ -5103,9 +5095,6 @@ static void init_and_link_css(struct cgr css_get(css->parent); } @@ -85,7 +85,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> BUG_ON(cgroup_css(cgrp, ss)); } -@@ -5194,7 +5183,6 @@ static struct cgroup_subsys_state *css_c +@@ -5207,7 +5196,6 @@ static struct cgroup_subsys_state *css_c err_list_del: list_del_rcu(&css->sibling); err_free_css: diff --git a/patches/0001-mm-page_alloc-Split-drain_local_pages.patch b/patches/0001-mm-page_alloc-Split-drain_local_pages.patch deleted file mode 100644 index 0c9dd861b826..000000000000 --- a/patches/0001-mm-page_alloc-Split-drain_local_pages.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Anna-Maria Gleixner <anna-maria@linutronix.de> -Date: Thu, 18 Apr 2019 11:09:04 +0200 -Subject: [PATCH 1/4] mm/page_alloc: Split drain_local_pages() - -Splitting the functionality of drain_local_pages() into a separate -function. This is a preparatory work for introducing the static key -dependend locking mechanism. - -No functional change. - -Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - include/linux/gfp.h | 1 + - mm/page_alloc.c | 13 +++++++++---- - 2 files changed, 10 insertions(+), 4 deletions(-) - ---- a/include/linux/gfp.h -+++ b/include/linux/gfp.h -@@ -580,6 +580,7 @@ extern void page_frag_free(void *addr); - void page_alloc_init(void); - void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp); - void drain_all_pages(struct zone *zone); -+void drain_cpu_pages(unsigned int cpu, struct zone *zone); - void drain_local_pages(struct zone *zone); - - void page_alloc_init_late(void); ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -2883,6 +2883,14 @@ static void drain_pages(unsigned int cpu - } - } - -+void drain_cpu_pages(unsigned int cpu, struct zone *zone) -+{ -+ if (zone) -+ drain_pages_zone(cpu, zone); -+ else -+ drain_pages(cpu); -+} -+ - /* - * Spill all of this CPU's per-cpu pages back into the buddy allocator. - * -@@ -2893,10 +2901,7 @@ void drain_local_pages(struct zone *zone - { - int cpu = smp_processor_id(); - -- if (zone) -- drain_pages_zone(cpu, zone); -- else -- drain_pages(cpu); -+ drain_cpu_pages(cpu, zone); - } - - static void drain_local_pages_wq(struct work_struct *work) diff --git a/patches/0001-workqueue-Don-t-assume-that-the-callback-has-interru.patch b/patches/0001-workqueue-Don-t-assume-that-the-callback-has-interru.patch index 2b62ed065b47..380bdd20b986 100644 --- a/patches/0001-workqueue-Don-t-assume-that-the-callback-has-interru.patch +++ b/patches/0001-workqueue-Don-t-assume-that-the-callback-has-interru.patch @@ -20,7 +20,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/kernel/workqueue.c +++ b/kernel/workqueue.c -@@ -1612,9 +1612,11 @@ EXPORT_SYMBOL_GPL(queue_work_node); +@@ -1614,9 +1614,11 @@ EXPORT_SYMBOL_GPL(queue_work_node); void delayed_work_timer_fn(struct timer_list *t) { struct delayed_work *dwork = from_timer(dwork, t, timer); diff --git a/patches/0002-cgroup-Consolidate-users-of-cgroup_rstat_lock.patch b/patches/0002-cgroup-Consolidate-users-of-cgroup_rstat_lock.patch index 6136ad721957..ffe82d00e40f 100644 --- a/patches/0002-cgroup-Consolidate-users-of-cgroup_rstat_lock.patch +++ b/patches/0002-cgroup-Consolidate-users-of-cgroup_rstat_lock.patch @@ -14,7 +14,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h -@@ -750,9 +750,6 @@ static inline void cgroup_path_from_kern +@@ -751,9 +751,6 @@ static inline void cgroup_path_from_kern */ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu); void cgroup_rstat_flush(struct cgroup *cgrp); diff --git a/patches/0002-mm-swap-Add-static-key-dependent-pagevec-locking.patch b/patches/0002-mm-swap-Add-static-key-dependent-pagevec-locking.patch deleted file mode 100644 index 4bb0d7ef15f7..000000000000 --- a/patches/0002-mm-swap-Add-static-key-dependent-pagevec-locking.patch +++ /dev/null @@ -1,418 +0,0 @@ -From: Thomas Gleixner <tglx@linutronix.de> -Date: Thu, 18 Apr 2019 11:09:05 +0200 -Subject: [PATCH 2/4] mm/swap: Add static key dependent pagevec locking - -The locking of struct pagevec is done by disabling preemption. In case the -struct has be accessed form interrupt context then interrupts are -disabled. This means the struct can only be accessed locally from the -CPU. There is also no lockdep coverage which would scream during if it -accessed from wrong context. - -Create struct swap_pagevec which contains of a pagevec member and a -spin_lock_t. Introduce a static key, which changes the locking behavior -only if the key is set in the following way: Before the struct is accessed -the spin_lock has to be acquired instead of using preempt_disable(). Since -the struct is used CPU-locally there is no spinning on the lock but the -lock is acquired immediately. If the struct is accessed from interrupt -context, spin_lock_irqsave() is used. - -No functional change yet because static key is not enabled. - -[anna-maria: introduce static key] -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> -Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - mm/compaction.c | 14 ++- - mm/internal.h | 2 - mm/swap.c | 202 +++++++++++++++++++++++++++++++++++++++++++++----------- - 3 files changed, 176 insertions(+), 42 deletions(-) - ---- a/mm/compaction.c -+++ b/mm/compaction.c -@@ -2244,10 +2244,16 @@ compact_zone(struct compact_control *cc, - block_start_pfn(cc->migrate_pfn, cc->order); - - if (last_migrated_pfn < current_block_start) { -- cpu = get_cpu(); -- lru_add_drain_cpu(cpu); -- drain_local_pages(cc->zone); -- put_cpu(); -+ if (static_branch_likely(&use_pvec_lock)) { -+ cpu = raw_smp_processor_id(); -+ lru_add_drain_cpu(cpu); -+ drain_cpu_pages(cpu, cc->zone); -+ } else { -+ cpu = get_cpu(); -+ lru_add_drain_cpu(cpu); -+ drain_local_pages(cc->zone); -+ put_cpu(); -+ } - /* No more flushing until we migrate again */ - last_migrated_pfn = 0; - } ---- a/mm/internal.h -+++ b/mm/internal.h -@@ -32,6 +32,8 @@ - /* Do not use these with a slab allocator */ - #define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK) - -+extern struct static_key_false use_pvec_lock; -+ - void page_writeback_init(void); - - vm_fault_t do_swap_page(struct vm_fault *vmf); ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -44,15 +44,108 @@ - /* How many pages do we try to swap or page in/out together? */ - int page_cluster; - --static DEFINE_PER_CPU(struct pagevec, lru_add_pvec); --static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs); --static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs); --static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs); --static DEFINE_PER_CPU(struct pagevec, lru_lazyfree_pvecs); -+DEFINE_STATIC_KEY_FALSE(use_pvec_lock); -+ -+struct swap_pagevec { -+ spinlock_t lock; -+ struct pagevec pvec; -+}; -+ -+#define DEFINE_PER_CPU_PAGEVEC(lvar) \ -+ DEFINE_PER_CPU(struct swap_pagevec, lvar) = { \ -+ .lock = __SPIN_LOCK_UNLOCKED((lvar).lock) } -+ -+static DEFINE_PER_CPU_PAGEVEC(lru_add_pvec); -+static DEFINE_PER_CPU_PAGEVEC(lru_rotate_pvecs); -+static DEFINE_PER_CPU_PAGEVEC(lru_deactivate_file_pvecs); -+static DEFINE_PER_CPU_PAGEVEC(lru_deactivate_pvecs); -+static DEFINE_PER_CPU_PAGEVEC(lru_lazyfree_pvecs); - #ifdef CONFIG_SMP --static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs); -+static DEFINE_PER_CPU_PAGEVEC(activate_page_pvecs); - #endif - -+static inline -+struct swap_pagevec *lock_swap_pvec(struct swap_pagevec __percpu *p) -+{ -+ struct swap_pagevec *swpvec; -+ -+ if (static_branch_likely(&use_pvec_lock)) { -+ swpvec = raw_cpu_ptr(p); -+ -+ spin_lock(&swpvec->lock); -+ } else { -+ swpvec = &get_cpu_var(*p); -+ } -+ return swpvec; -+} -+ -+static inline struct swap_pagevec * -+lock_swap_pvec_cpu(struct swap_pagevec __percpu *p, int cpu) -+{ -+ struct swap_pagevec *swpvec = per_cpu_ptr(p, cpu); -+ -+ if (static_branch_likely(&use_pvec_lock)) -+ spin_lock(&swpvec->lock); -+ -+ return swpvec; -+} -+ -+static inline struct swap_pagevec * -+lock_swap_pvec_irqsave(struct swap_pagevec __percpu *p, unsigned long *flags) -+{ -+ struct swap_pagevec *swpvec; -+ -+ if (static_branch_likely(&use_pvec_lock)) { -+ swpvec = raw_cpu_ptr(p); -+ -+ spin_lock_irqsave(&swpvec->lock, (*flags)); -+ } else { -+ local_irq_save(*flags); -+ -+ swpvec = this_cpu_ptr(p); -+ } -+ return swpvec; -+} -+ -+static inline struct swap_pagevec * -+lock_swap_pvec_cpu_irqsave(struct swap_pagevec __percpu *p, int cpu, -+ unsigned long *flags) -+{ -+ struct swap_pagevec *swpvec = per_cpu_ptr(p, cpu); -+ -+ if (static_branch_likely(&use_pvec_lock)) -+ spin_lock_irqsave(&swpvec->lock, *flags); -+ else -+ local_irq_save(*flags); -+ -+ return swpvec; -+} -+ -+static inline void unlock_swap_pvec(struct swap_pagevec *swpvec, -+ struct swap_pagevec __percpu *p) -+{ -+ if (static_branch_likely(&use_pvec_lock)) -+ spin_unlock(&swpvec->lock); -+ else -+ put_cpu_var(*p); -+ -+} -+ -+static inline void unlock_swap_pvec_cpu(struct swap_pagevec *swpvec) -+{ -+ if (static_branch_likely(&use_pvec_lock)) -+ spin_unlock(&swpvec->lock); -+} -+ -+static inline void -+unlock_swap_pvec_irqrestore(struct swap_pagevec *swpvec, unsigned long flags) -+{ -+ if (static_branch_likely(&use_pvec_lock)) -+ spin_unlock_irqrestore(&swpvec->lock, flags); -+ else -+ local_irq_restore(flags); -+} -+ - /* - * This path almost never happens for VM activity - pages are normally - * freed via pagevecs. But it gets used by networking. -@@ -250,15 +343,17 @@ void rotate_reclaimable_page(struct page - { - if (!PageLocked(page) && !PageDirty(page) && - !PageUnevictable(page) && PageLRU(page)) { -+ struct swap_pagevec *swpvec; - struct pagevec *pvec; - unsigned long flags; - - get_page(page); -- local_irq_save(flags); -- pvec = this_cpu_ptr(&lru_rotate_pvecs); -+ -+ swpvec = lock_swap_pvec_irqsave(&lru_rotate_pvecs, &flags); -+ pvec = &swpvec->pvec; - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_move_tail(pvec); -- local_irq_restore(flags); -+ unlock_swap_pvec_irqrestore(swpvec, flags); - } - } - -@@ -293,27 +388,32 @@ static void __activate_page(struct page - #ifdef CONFIG_SMP - static void activate_page_drain(int cpu) - { -- struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu); -+ struct swap_pagevec *swpvec = lock_swap_pvec_cpu(&activate_page_pvecs, cpu); -+ struct pagevec *pvec = &swpvec->pvec; - - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, __activate_page, NULL); -+ unlock_swap_pvec_cpu(swpvec); - } - - static bool need_activate_page_drain(int cpu) - { -- return pagevec_count(&per_cpu(activate_page_pvecs, cpu)) != 0; -+ return pagevec_count(per_cpu_ptr(&activate_page_pvecs.pvec, cpu)) != 0; - } - - void activate_page(struct page *page) - { - page = compound_head(page); - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { -- struct pagevec *pvec = &get_cpu_var(activate_page_pvecs); -+ struct swap_pagevec *swpvec; -+ struct pagevec *pvec; - - get_page(page); -+ swpvec = lock_swap_pvec(&activate_page_pvecs); -+ pvec = &swpvec->pvec; - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, __activate_page, NULL); -- put_cpu_var(activate_page_pvecs); -+ unlock_swap_pvec(swpvec, &activate_page_pvecs); - } - } - -@@ -335,7 +435,8 @@ void activate_page(struct page *page) - - static void __lru_cache_activate_page(struct page *page) - { -- struct pagevec *pvec = &get_cpu_var(lru_add_pvec); -+ struct swap_pagevec *swpvec = lock_swap_pvec(&lru_add_pvec); -+ struct pagevec *pvec = &swpvec->pvec; - int i; - - /* -@@ -357,7 +458,7 @@ static void __lru_cache_activate_page(st - } - } - -- put_cpu_var(lru_add_pvec); -+ unlock_swap_pvec(swpvec, &lru_add_pvec); - } - - /* -@@ -399,12 +500,13 @@ EXPORT_SYMBOL(mark_page_accessed); - - static void __lru_cache_add(struct page *page) - { -- struct pagevec *pvec = &get_cpu_var(lru_add_pvec); -+ struct swap_pagevec *swpvec = lock_swap_pvec(&lru_add_pvec); -+ struct pagevec *pvec = &swpvec->pvec; - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - __pagevec_lru_add(pvec); -- put_cpu_var(lru_add_pvec); -+ unlock_swap_pvec(swpvec, &lru_add_pvec); - } - - /** -@@ -588,32 +690,40 @@ static void lru_lazyfree_fn(struct page - */ - void lru_add_drain_cpu(int cpu) - { -- struct pagevec *pvec = &per_cpu(lru_add_pvec, cpu); -+ struct swap_pagevec *swpvec = lock_swap_pvec_cpu(&lru_add_pvec, cpu); -+ struct pagevec *pvec = &swpvec->pvec; -+ unsigned long flags; - - if (pagevec_count(pvec)) - __pagevec_lru_add(pvec); -+ unlock_swap_pvec_cpu(swpvec); - -- pvec = &per_cpu(lru_rotate_pvecs, cpu); -+ swpvec = lock_swap_pvec_cpu_irqsave(&lru_rotate_pvecs, cpu, &flags); -+ pvec = &swpvec->pvec; - if (pagevec_count(pvec)) { -- unsigned long flags; - - /* No harm done if a racing interrupt already did this */ -- local_irq_save(flags); - pagevec_move_tail(pvec); -- local_irq_restore(flags); - } -+ unlock_swap_pvec_irqrestore(swpvec, flags); - -- pvec = &per_cpu(lru_deactivate_file_pvecs, cpu); -+ swpvec = lock_swap_pvec_cpu(&lru_deactivate_file_pvecs, cpu); -+ pvec = &swpvec->pvec; - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL); -+ unlock_swap_pvec_cpu(swpvec); - -- pvec = &per_cpu(lru_deactivate_pvecs, cpu); -+ swpvec = lock_swap_pvec_cpu(&lru_deactivate_pvecs, cpu); -+ pvec = &swpvec->pvec; - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL); -+ unlock_swap_pvec_cpu(swpvec); - -- pvec = &per_cpu(lru_lazyfree_pvecs, cpu); -+ swpvec = lock_swap_pvec_cpu(&lru_lazyfree_pvecs, cpu); -+ pvec = &swpvec->pvec; - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, lru_lazyfree_fn, NULL); -+ unlock_swap_pvec_cpu(swpvec); - - activate_page_drain(cpu); - } -@@ -628,6 +738,9 @@ void lru_add_drain_cpu(int cpu) - */ - void deactivate_file_page(struct page *page) - { -+ struct swap_pagevec *swpvec; -+ struct pagevec *pvec; -+ - /* - * In a workload with many unevictable page such as mprotect, - * unevictable page deactivation for accelerating reclaim is pointless. -@@ -636,11 +749,12 @@ void deactivate_file_page(struct page *p - return; - - if (likely(get_page_unless_zero(page))) { -- struct pagevec *pvec = &get_cpu_var(lru_deactivate_file_pvecs); -+ swpvec = lock_swap_pvec(&lru_deactivate_file_pvecs); -+ pvec = &swpvec->pvec; - - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL); -- put_cpu_var(lru_deactivate_file_pvecs); -+ unlock_swap_pvec(swpvec, &lru_deactivate_file_pvecs); - } - } - -@@ -655,12 +769,16 @@ void deactivate_file_page(struct page *p - void deactivate_page(struct page *page) - { - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { -- struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs); -+ struct swap_pagevec *swpvec; -+ struct pagevec *pvec; -+ -+ swpvec = lock_swap_pvec(&lru_deactivate_pvecs); -+ pvec = &swpvec->pvec; - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL); -- put_cpu_var(lru_deactivate_pvecs); -+ unlock_swap_pvec(swpvec, &lru_deactivate_pvecs); - } - } - -@@ -673,21 +791,29 @@ void deactivate_page(struct page *page) - */ - void mark_page_lazyfree(struct page *page) - { -+ struct swap_pagevec *swpvec; -+ struct pagevec *pvec; -+ - if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) && - !PageSwapCache(page) && !PageUnevictable(page)) { -- struct pagevec *pvec = &get_cpu_var(lru_lazyfree_pvecs); -+ swpvec = lock_swap_pvec(&lru_lazyfree_pvecs); -+ pvec = &swpvec->pvec; - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, lru_lazyfree_fn, NULL); -- put_cpu_var(lru_lazyfree_pvecs); -+ unlock_swap_pvec(swpvec, &lru_lazyfree_pvecs); - } - } - - void lru_add_drain(void) - { -- lru_add_drain_cpu(get_cpu()); -- put_cpu(); -+ if (static_branch_likely(&use_pvec_lock)) { -+ lru_add_drain_cpu(raw_smp_processor_id()); -+ } else { -+ lru_add_drain_cpu(get_cpu()); -+ put_cpu(); -+ } - } - - #ifdef CONFIG_SMP -@@ -725,11 +851,11 @@ void lru_add_drain_all(void) - for_each_online_cpu(cpu) { - struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); - -- if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) || -- pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) || -- pagevec_count(&per_cpu(lru_deactivate_file_pvecs, cpu)) || -- pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) || -- pagevec_count(&per_cpu(lru_lazyfree_pvecs, cpu)) || -+ if (pagevec_count(&per_cpu(lru_add_pvec.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_rotate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_file_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_lazyfree_pvecs.pvec, cpu)) || - need_activate_page_drain(cpu)) { - INIT_WORK(work, lru_add_drain_per_cpu); - queue_work_on(cpu, mm_percpu_wq, work); diff --git a/patches/0003-mm-swap-Access-struct-pagevec-remotely.patch b/patches/0003-mm-swap-Access-struct-pagevec-remotely.patch deleted file mode 100644 index f0d209808e20..000000000000 --- a/patches/0003-mm-swap-Access-struct-pagevec-remotely.patch +++ /dev/null @@ -1,136 +0,0 @@ -From: Thomas Gleixner <tglx@linutronix.de> -Date: Thu, 18 Apr 2019 11:09:06 +0200 -Subject: [PATCH 3/4] mm/swap: Access struct pagevec remotely - -When the newly introduced static key would be enabled, struct pagevec is -locked during access. So it is possible to access it from a remote CPU. The -advantage is that the work can be done from the "requesting" CPU without -firing a worker on a remote CPU and waiting for it to complete the work. - -No functional change because static key is not enabled. - -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> -Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - mm/page_alloc.c | 19 ++++++++------ - mm/swap.c | 75 +++++++++++++++++++++++++++++++++----------------------- - 2 files changed, 57 insertions(+), 37 deletions(-) - ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -2988,15 +2988,20 @@ void drain_all_pages(struct zone *zone) - cpumask_clear_cpu(cpu, &cpus_with_pcps); - } - -- for_each_cpu(cpu, &cpus_with_pcps) { -- struct pcpu_drain *drain = per_cpu_ptr(&pcpu_drain, cpu); -+ if (static_branch_likely(&use_pvec_lock)) { -+ for_each_cpu(cpu, &cpus_with_pcps) -+ drain_cpu_pages(cpu, zone); -+ } else { -+ for_each_cpu(cpu, &cpus_with_pcps) { -+ struct pcpu_drain *drain = per_cpu_ptr(&pcpu_drain, cpu); - -- drain->zone = zone; -- INIT_WORK(&drain->work, drain_local_pages_wq); -- queue_work_on(cpu, mm_percpu_wq, &drain->work); -+ drain->zone = zone; -+ INIT_WORK(&drain->work, drain_local_pages_wq); -+ queue_work_on(cpu, mm_percpu_wq, &drain->work); -+ } -+ for_each_cpu(cpu, &cpus_with_pcps) -+ flush_work(&per_cpu_ptr(&pcpu_drain, cpu)->work); - } -- for_each_cpu(cpu, &cpus_with_pcps) -- flush_work(&per_cpu_ptr(&pcpu_drain, cpu)->work); - - mutex_unlock(&pcpu_drain_mutex); - } ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -834,39 +834,54 @@ static void lru_add_drain_per_cpu(struct - */ - void lru_add_drain_all(void) - { -- static DEFINE_MUTEX(lock); -- static struct cpumask has_work; -- int cpu; -- -- /* -- * Make sure nobody triggers this path before mm_percpu_wq is fully -- * initialized. -- */ -- if (WARN_ON(!mm_percpu_wq)) -- return; -- -- mutex_lock(&lock); -- cpumask_clear(&has_work); -- -- for_each_online_cpu(cpu) { -- struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); -- -- if (pagevec_count(&per_cpu(lru_add_pvec.pvec, cpu)) || -- pagevec_count(&per_cpu(lru_rotate_pvecs.pvec, cpu)) || -- pagevec_count(&per_cpu(lru_deactivate_file_pvecs.pvec, cpu)) || -- pagevec_count(&per_cpu(lru_deactivate_pvecs.pvec, cpu)) || -- pagevec_count(&per_cpu(lru_lazyfree_pvecs.pvec, cpu)) || -- need_activate_page_drain(cpu)) { -- INIT_WORK(work, lru_add_drain_per_cpu); -- queue_work_on(cpu, mm_percpu_wq, work); -- cpumask_set_cpu(cpu, &has_work); -+ if (static_branch_likely(&use_pvec_lock)) { -+ int cpu; -+ -+ for_each_online_cpu(cpu) { -+ if (pagevec_count(&per_cpu(lru_add_pvec.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_rotate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_file_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_lazyfree_pvecs.pvec, cpu)) || -+ need_activate_page_drain(cpu)) { -+ lru_add_drain_cpu(cpu); -+ } -+ } -+ } else { -+ static DEFINE_MUTEX(lock); -+ static struct cpumask has_work; -+ int cpu; -+ -+ /* -+ * Make sure nobody triggers this path before mm_percpu_wq -+ * is fully initialized. -+ */ -+ if (WARN_ON(!mm_percpu_wq)) -+ return; -+ -+ mutex_lock(&lock); -+ cpumask_clear(&has_work); -+ -+ for_each_online_cpu(cpu) { -+ struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); -+ -+ if (pagevec_count(&per_cpu(lru_add_pvec.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_rotate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_file_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_deactivate_pvecs.pvec, cpu)) || -+ pagevec_count(&per_cpu(lru_lazyfree_pvecs.pvec, cpu)) || -+ need_activate_page_drain(cpu)) { -+ INIT_WORK(work, lru_add_drain_per_cpu); -+ queue_work_on(cpu, mm_percpu_wq, work); -+ cpumask_set_cpu(cpu, &has_work); -+ } - } -- } - -- for_each_cpu(cpu, &has_work) -- flush_work(&per_cpu(lru_add_drain_work, cpu)); -+ for_each_cpu(cpu, &has_work) -+ flush_work(&per_cpu(lru_add_drain_work, cpu)); - -- mutex_unlock(&lock); -+ mutex_unlock(&lock); -+ } - } - #else - void lru_add_drain_all(void) diff --git a/patches/0003-workqueue-Use-swait-for-wq_manager_wait.patch b/patches/0003-workqueue-Use-swait-for-wq_manager_wait.patch index 245b75df6520..3f5cb468656e 100644 --- a/patches/0003-workqueue-Use-swait-for-wq_manager_wait.patch +++ b/patches/0003-workqueue-Use-swait-for-wq_manager_wait.patch @@ -33,7 +33,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> static LIST_HEAD(workqueues); /* PR: list of all workqueues */ static bool workqueue_freezing; /* PL: have wqs started freezing? */ -@@ -2144,7 +2145,7 @@ static bool manage_workers(struct worker +@@ -2146,7 +2147,7 @@ static bool manage_workers(struct worker pool->manager = NULL; pool->flags &= ~POOL_MANAGER_ACTIVE; @@ -42,7 +42,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return true; } -@@ -3545,7 +3546,7 @@ static void put_unbound_pool(struct work +@@ -3547,7 +3548,7 @@ static void put_unbound_pool(struct work * manager and @pool gets freed with the flag set. */ spin_lock_irq(&pool->lock); diff --git a/patches/0004-mm-swap-Enable-use_pvec_lock-nohz_full-dependent.patch b/patches/0004-mm-swap-Enable-use_pvec_lock-nohz_full-dependent.patch deleted file mode 100644 index 4ca49256f3ee..000000000000 --- a/patches/0004-mm-swap-Enable-use_pvec_lock-nohz_full-dependent.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Anna-Maria Gleixner <anna-maria@linutronix.de> -Date: Thu, 18 Apr 2019 11:09:07 +0200 -Subject: [PATCH 4/4] mm/swap: Enable "use_pvec_lock" nohz_full dependent - -When a system runs with CONFIG_NO_HZ_FULL enabled, the tick of CPUs listed -in 'nohz_full=' kernel command line parameter should be stopped whenever -possible. The tick stays longer stopped, when work for this CPU is handled -by another CPU. - -With the already introduced static key 'use_pvec_lock' there is the -possibility to prevent firing a worker for mm/swap work on a remote CPU -with a stopped tick. - -Therefore enabling the static key in case kernel command line parameter -'nohz_full=' setup was successful, which implies that CONFIG_NO_HZ_FULL is -set. - -Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - kernel/sched/isolation.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - ---- a/kernel/sched/isolation.c -+++ b/kernel/sched/isolation.c -@@ -8,6 +8,7 @@ - * - */ - #include "sched.h" -+#include "../../mm/internal.h" - - DEFINE_STATIC_KEY_FALSE(housekeeping_overridden); - EXPORT_SYMBOL_GPL(housekeeping_overridden); -@@ -139,10 +140,21 @@ static int __init housekeeping_setup(cha - static int __init housekeeping_nohz_full_setup(char *str) - { - unsigned int flags; -+ int ret; - - flags = HK_FLAG_TICK | HK_FLAG_WQ | HK_FLAG_TIMER | HK_FLAG_RCU | HK_FLAG_MISC; - -- return housekeeping_setup(str, flags); -+ ret = housekeeping_setup(str, flags); -+ -+ /* -+ * Protect struct pagevec with a lock instead using preemption disable; -+ * with lock protection, remote handling of events instead of queue -+ * work on remote cpu is default behavior. -+ */ -+ if (ret) -+ static_branch_enable(&use_pvec_lock); -+ -+ return ret; - } - __setup("nohz_full=", housekeeping_nohz_full_setup); - diff --git a/patches/0004-workqueue-Convert-the-locks-to-raw-type.patch b/patches/0004-workqueue-Convert-the-locks-to-raw-type.patch index 7558be608124..6b5588540883 100644 --- a/patches/0004-workqueue-Convert-the-locks-to-raw-type.patch +++ b/patches/0004-workqueue-Convert-the-locks-to-raw-type.patch @@ -156,7 +156,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, struct list_head *head, unsigned int extra_flags) -@@ -1436,7 +1436,7 @@ static void __queue_work(int cpu, struct +@@ -1438,7 +1438,7 @@ static void __queue_work(int cpu, struct if (last_pool && last_pool != pwq->pool) { struct worker *worker; @@ -165,7 +165,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> worker = find_worker_executing_work(last_pool, work); -@@ -1444,11 +1444,11 @@ static void __queue_work(int cpu, struct +@@ -1446,11 +1446,11 @@ static void __queue_work(int cpu, struct pwq = worker->current_pwq; } else { /* meh... not running there, queue here */ @@ -180,7 +180,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } /* -@@ -1461,7 +1461,7 @@ static void __queue_work(int cpu, struct +@@ -1463,7 +1463,7 @@ static void __queue_work(int cpu, struct */ if (unlikely(!pwq->refcnt)) { if (wq->flags & WQ_UNBOUND) { @@ -189,7 +189,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> cpu_relax(); goto retry; } -@@ -1493,7 +1493,7 @@ static void __queue_work(int cpu, struct +@@ -1495,7 +1495,7 @@ static void __queue_work(int cpu, struct insert_work(pwq, work, worklist, work_flags); out: @@ -198,7 +198,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> rcu_read_unlock(); } -@@ -1764,7 +1764,7 @@ EXPORT_SYMBOL(queue_rcu_work); +@@ -1766,7 +1766,7 @@ EXPORT_SYMBOL(queue_rcu_work); * necessary. * * LOCKING: @@ -207,7 +207,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void worker_enter_idle(struct worker *worker) { -@@ -1804,7 +1804,7 @@ static void worker_enter_idle(struct wor +@@ -1806,7 +1806,7 @@ static void worker_enter_idle(struct wor * @worker is leaving idle state. Update stats. * * LOCKING: @@ -216,7 +216,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void worker_leave_idle(struct worker *worker) { -@@ -1942,11 +1942,11 @@ static struct worker *create_worker(stru +@@ -1944,11 +1944,11 @@ static struct worker *create_worker(stru worker_attach_to_pool(worker, pool); /* start the newly created worker */ @@ -230,7 +230,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return worker; -@@ -1965,7 +1965,7 @@ static struct worker *create_worker(stru +@@ -1967,7 +1967,7 @@ static struct worker *create_worker(stru * be idle. * * CONTEXT: @@ -239,7 +239,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void destroy_worker(struct worker *worker) { -@@ -1991,7 +1991,7 @@ static void idle_worker_timeout(struct t +@@ -1993,7 +1993,7 @@ static void idle_worker_timeout(struct t { struct worker_pool *pool = from_timer(pool, t, idle_timer); @@ -248,7 +248,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> while (too_many_workers(pool)) { struct worker *worker; -@@ -2009,7 +2009,7 @@ static void idle_worker_timeout(struct t +@@ -2011,7 +2011,7 @@ static void idle_worker_timeout(struct t destroy_worker(worker); } @@ -257,7 +257,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } static void send_mayday(struct work_struct *work) -@@ -2040,8 +2040,8 @@ static void pool_mayday_timeout(struct t +@@ -2042,8 +2042,8 @@ static void pool_mayday_timeout(struct t struct worker_pool *pool = from_timer(pool, t, mayday_timer); struct work_struct *work; @@ -268,7 +268,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (need_to_create_worker(pool)) { /* -@@ -2054,8 +2054,8 @@ static void pool_mayday_timeout(struct t +@@ -2056,8 +2056,8 @@ static void pool_mayday_timeout(struct t send_mayday(work); } @@ -279,7 +279,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL); } -@@ -2074,7 +2074,7 @@ static void pool_mayday_timeout(struct t +@@ -2076,7 +2076,7 @@ static void pool_mayday_timeout(struct t * may_start_working() %true. * * LOCKING: @@ -288,7 +288,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * multiple times. Does GFP_KERNEL allocations. Called only from * manager. */ -@@ -2083,7 +2083,7 @@ static void maybe_create_worker(struct w +@@ -2085,7 +2085,7 @@ static void maybe_create_worker(struct w __acquires(&pool->lock) { restart: @@ -297,7 +297,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT); -@@ -2099,7 +2099,7 @@ static void maybe_create_worker(struct w +@@ -2101,7 +2101,7 @@ static void maybe_create_worker(struct w } del_timer_sync(&pool->mayday_timer); @@ -306,7 +306,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * This is necessary even after a new worker was just successfully * created as @pool->lock was dropped and the new worker might have -@@ -2122,7 +2122,7 @@ static void maybe_create_worker(struct w +@@ -2124,7 +2124,7 @@ static void maybe_create_worker(struct w * and may_start_working() is true. * * CONTEXT: @@ -315,7 +315,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * multiple times. Does GFP_KERNEL allocations. * * Return: -@@ -2161,7 +2161,7 @@ static bool manage_workers(struct worker +@@ -2163,7 +2163,7 @@ static bool manage_workers(struct worker * call this function to process a work. * * CONTEXT: @@ -324,7 +324,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void process_one_work(struct worker *worker, struct work_struct *work) __releases(&pool->lock) -@@ -2243,7 +2243,7 @@ static void process_one_work(struct work +@@ -2245,7 +2245,7 @@ static void process_one_work(struct work */ set_work_pool_and_clear_pending(work, pool->id); @@ -333,7 +333,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> lock_map_acquire(&pwq->wq->lockdep_map); lock_map_acquire(&lockdep_map); -@@ -2298,7 +2298,7 @@ static void process_one_work(struct work +@@ -2300,7 +2300,7 @@ static void process_one_work(struct work */ cond_resched(); @@ -342,7 +342,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* clear cpu intensive status */ if (unlikely(cpu_intensive)) -@@ -2324,7 +2324,7 @@ static void process_one_work(struct work +@@ -2326,7 +2326,7 @@ static void process_one_work(struct work * fetches a work from the top and executes it. * * CONTEXT: @@ -351,7 +351,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * multiple times. */ static void process_scheduled_works(struct worker *worker) -@@ -2366,11 +2366,11 @@ static int worker_thread(void *__worker) +@@ -2368,11 +2368,11 @@ static int worker_thread(void *__worker) /* tell the scheduler that this is a workqueue worker */ set_pf_worker(true); woke_up: @@ -365,7 +365,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> WARN_ON_ONCE(!list_empty(&worker->entry)); set_pf_worker(false); -@@ -2436,7 +2436,7 @@ static int worker_thread(void *__worker) +@@ -2438,7 +2438,7 @@ static int worker_thread(void *__worker) */ worker_enter_idle(worker); __set_current_state(TASK_IDLE); @@ -374,7 +374,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> schedule(); goto woke_up; } -@@ -2490,7 +2490,7 @@ static int rescuer_thread(void *__rescue +@@ -2492,7 +2492,7 @@ static int rescuer_thread(void *__rescue should_stop = kthread_should_stop(); /* see whether any pwq is asking for help */ @@ -383,7 +383,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> while (!list_empty(&wq->maydays)) { struct pool_workqueue *pwq = list_first_entry(&wq->maydays, -@@ -2502,11 +2502,11 @@ static int rescuer_thread(void *__rescue +@@ -2504,11 +2504,11 @@ static int rescuer_thread(void *__rescue __set_current_state(TASK_RUNNING); list_del_init(&pwq->mayday_node); @@ -397,7 +397,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Slurp in all works issued via this workqueue and -@@ -2535,7 +2535,7 @@ static int rescuer_thread(void *__rescue +@@ -2537,7 +2537,7 @@ static int rescuer_thread(void *__rescue * incur MAYDAY_INTERVAL delay inbetween. */ if (need_to_create_worker(pool)) { @@ -406,7 +406,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Queue iff we aren't racing destruction * and somebody else hasn't queued it already. -@@ -2544,7 +2544,7 @@ static int rescuer_thread(void *__rescue +@@ -2546,7 +2546,7 @@ static int rescuer_thread(void *__rescue get_pwq(pwq); list_add_tail(&pwq->mayday_node, &wq->maydays); } @@ -415,7 +415,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } } -@@ -2562,14 +2562,14 @@ static int rescuer_thread(void *__rescue +@@ -2564,14 +2564,14 @@ static int rescuer_thread(void *__rescue if (need_more_worker(pool)) wake_up_worker(pool); @@ -433,7 +433,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (should_stop) { __set_current_state(TASK_RUNNING); -@@ -2649,7 +2649,7 @@ static void wq_barrier_func(struct work_ +@@ -2651,7 +2651,7 @@ static void wq_barrier_func(struct work_ * underneath us, so we can't reliably determine pwq from @target. * * CONTEXT: @@ -442,7 +442,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> */ static void insert_wq_barrier(struct pool_workqueue *pwq, struct wq_barrier *barr, -@@ -2736,7 +2736,7 @@ static bool flush_workqueue_prep_pwqs(st +@@ -2738,7 +2738,7 @@ static bool flush_workqueue_prep_pwqs(st for_each_pwq(pwq, wq) { struct worker_pool *pool = pwq->pool; @@ -451,7 +451,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (flush_color >= 0) { WARN_ON_ONCE(pwq->flush_color != -1); -@@ -2753,7 +2753,7 @@ static bool flush_workqueue_prep_pwqs(st +@@ -2755,7 +2755,7 @@ static bool flush_workqueue_prep_pwqs(st pwq->work_color = work_color; } @@ -460,7 +460,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } if (flush_color >= 0 && atomic_dec_and_test(&wq->nr_pwqs_to_flush)) -@@ -2953,9 +2953,9 @@ void drain_workqueue(struct workqueue_st +@@ -2955,9 +2955,9 @@ void drain_workqueue(struct workqueue_st for_each_pwq(pwq, wq) { bool drained; @@ -472,7 +472,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (drained) continue; -@@ -2991,7 +2991,7 @@ static bool start_flush_work(struct work +@@ -2993,7 +2993,7 @@ static bool start_flush_work(struct work return false; } @@ -481,7 +481,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* see the comment in try_to_grab_pending() with the same code */ pwq = get_work_pwq(work); if (pwq) { -@@ -3007,7 +3007,7 @@ static bool start_flush_work(struct work +@@ -3009,7 +3009,7 @@ static bool start_flush_work(struct work check_flush_dependency(pwq->wq, work); insert_wq_barrier(pwq, barr, work, worker); @@ -490,7 +490,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Force a lock recursion deadlock when using flush_work() inside a -@@ -3026,7 +3026,7 @@ static bool start_flush_work(struct work +@@ -3028,7 +3028,7 @@ static bool start_flush_work(struct work rcu_read_unlock(); return true; already_gone: @@ -499,7 +499,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> rcu_read_unlock(); return false; } -@@ -3419,7 +3419,7 @@ static bool wqattrs_equal(const struct w +@@ -3421,7 +3421,7 @@ static bool wqattrs_equal(const struct w */ static int init_worker_pool(struct worker_pool *pool) { @@ -508,7 +508,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> pool->id = -1; pool->cpu = -1; pool->node = NUMA_NO_NODE; -@@ -3545,7 +3545,7 @@ static void put_unbound_pool(struct work +@@ -3547,7 +3547,7 @@ static void put_unbound_pool(struct work * @pool's workers from blocking on attach_mutex. We're the last * manager and @pool gets freed with the flag set. */ @@ -517,7 +517,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> swait_event_lock_irq(wq_manager_wait, !(pool->flags & POOL_MANAGER_ACTIVE), pool->lock); pool->flags |= POOL_MANAGER_ACTIVE; -@@ -3553,7 +3553,7 @@ static void put_unbound_pool(struct work +@@ -3555,7 +3555,7 @@ static void put_unbound_pool(struct work while ((worker = first_idle_worker(pool))) destroy_worker(worker); WARN_ON(pool->nr_workers || pool->nr_idle); @@ -526,7 +526,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> mutex_lock(&wq_pool_attach_mutex); if (!list_empty(&pool->workers)) -@@ -3709,7 +3709,7 @@ static void pwq_adjust_max_active(struct +@@ -3711,7 +3711,7 @@ static void pwq_adjust_max_active(struct return; /* this function can be called during early boot w/ irq disabled */ @@ -535,7 +535,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * During [un]freezing, the caller is responsible for ensuring that -@@ -3732,7 +3732,7 @@ static void pwq_adjust_max_active(struct +@@ -3734,7 +3734,7 @@ static void pwq_adjust_max_active(struct pwq->max_active = 0; } @@ -544,7 +544,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } /* initialize newly alloced @pwq which is associated with @wq and @pool */ -@@ -4134,9 +4134,9 @@ static void wq_update_unbound_numa(struc +@@ -4136,9 +4136,9 @@ static void wq_update_unbound_numa(struc use_dfl_pwq: mutex_lock(&wq->mutex); @@ -556,7 +556,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> old_pwq = numa_pwq_tbl_install(wq, node, wq->dfl_pwq); out_unlock: mutex_unlock(&wq->mutex); -@@ -4349,9 +4349,9 @@ void destroy_workqueue(struct workqueue_ +@@ -4351,9 +4351,9 @@ void destroy_workqueue(struct workqueue_ struct worker *rescuer = wq->rescuer; /* this prevents new queueing */ @@ -568,7 +568,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* rescuer will empty maydays list before exiting */ kthread_stop(rescuer->task); -@@ -4547,10 +4547,10 @@ unsigned int work_busy(struct work_struc +@@ -4549,10 +4549,10 @@ unsigned int work_busy(struct work_struc rcu_read_lock(); pool = get_work_pool(work); if (pool) { @@ -581,7 +581,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } rcu_read_unlock(); -@@ -4757,10 +4757,10 @@ void show_workqueue_state(void) +@@ -4759,10 +4759,10 @@ void show_workqueue_state(void) pr_info("workqueue %s: flags=0x%x\n", wq->name, wq->flags); for_each_pwq(pwq, wq) { @@ -594,7 +594,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * We could be printing a lot from atomic context, e.g. * sysrq-t -> show_workqueue_state(). Avoid triggering -@@ -4774,7 +4774,7 @@ void show_workqueue_state(void) +@@ -4776,7 +4776,7 @@ void show_workqueue_state(void) struct worker *worker; bool first = true; @@ -603,7 +603,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (pool->nr_workers == pool->nr_idle) goto next_pool; -@@ -4793,7 +4793,7 @@ void show_workqueue_state(void) +@@ -4795,7 +4795,7 @@ void show_workqueue_state(void) } pr_cont("\n"); next_pool: @@ -612,7 +612,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * We could be printing a lot from atomic context, e.g. * sysrq-t -> show_workqueue_state(). Avoid triggering -@@ -4823,7 +4823,7 @@ void wq_worker_comm(char *buf, size_t si +@@ -4825,7 +4825,7 @@ void wq_worker_comm(char *buf, size_t si struct worker_pool *pool = worker->pool; if (pool) { @@ -621,7 +621,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * ->desc tracks information (wq name or * set_worker_desc()) for the latest execution. If -@@ -4837,7 +4837,7 @@ void wq_worker_comm(char *buf, size_t si +@@ -4839,7 +4839,7 @@ void wq_worker_comm(char *buf, size_t si scnprintf(buf + off, size - off, "-%s", worker->desc); } @@ -630,7 +630,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } } -@@ -4868,7 +4868,7 @@ static void unbind_workers(int cpu) +@@ -4870,7 +4870,7 @@ static void unbind_workers(int cpu) for_each_cpu_worker_pool(pool, cpu) { mutex_lock(&wq_pool_attach_mutex); @@ -639,7 +639,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * We've blocked all attach/detach operations. Make all workers -@@ -4882,7 +4882,7 @@ static void unbind_workers(int cpu) +@@ -4884,7 +4884,7 @@ static void unbind_workers(int cpu) pool->flags |= POOL_DISASSOCIATED; @@ -648,7 +648,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> mutex_unlock(&wq_pool_attach_mutex); /* -@@ -4908,9 +4908,9 @@ static void unbind_workers(int cpu) +@@ -4910,9 +4910,9 @@ static void unbind_workers(int cpu) * worker blocking could lead to lengthy stalls. Kick off * unbound chain execution of currently pending work items. */ @@ -660,7 +660,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } } -@@ -4937,7 +4937,7 @@ static void rebind_workers(struct worker +@@ -4939,7 +4939,7 @@ static void rebind_workers(struct worker WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask) < 0); @@ -669,7 +669,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> pool->flags &= ~POOL_DISASSOCIATED; -@@ -4976,7 +4976,7 @@ static void rebind_workers(struct worker +@@ -4978,7 +4978,7 @@ static void rebind_workers(struct worker WRITE_ONCE(worker->flags, worker_flags); } diff --git a/patches/Use-CONFIG_PREEMPTION.patch b/patches/Use-CONFIG_PREEMPTION.patch index 0a1f2725cd16..87c720d91853 100644 --- a/patches/Use-CONFIG_PREEMPTION.patch +++ b/patches/Use-CONFIG_PREEMPTION.patch @@ -1423,7 +1423,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> #endif --- a/kernel/workqueue.c +++ b/kernel/workqueue.c -@@ -2286,7 +2286,7 @@ static void process_one_work(struct work +@@ -2288,7 +2288,7 @@ static void process_one_work(struct work } /* diff --git a/patches/completion-use-simple-wait-queues.patch b/patches/completion-use-simple-wait-queues.patch index 527b9b2e36cc..dd333b1e7c67 100644 --- a/patches/completion-use-simple-wait-queues.patch +++ b/patches/completion-use-simple-wait-queues.patch @@ -53,7 +53,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> default: --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c -@@ -1717,7 +1717,7 @@ static void ffs_data_put(struct ffs_data +@@ -1718,7 +1718,7 @@ static void ffs_data_put(struct ffs_data pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || diff --git a/patches/dma-buf-Use-seqlock_t-instread-disabling-preemption.patch b/patches/dma-buf-Use-seqlock_t-instread-disabling-preemption.patch index 7386859768b8..a3df0fc2220b 100644 --- a/patches/dma-buf-Use-seqlock_t-instread-disabling-preemption.patch +++ b/patches/dma-buf-Use-seqlock_t-instread-disabling-preemption.patch @@ -20,7 +20,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c -@@ -214,7 +214,7 @@ static __poll_t dma_buf_poll(struct file +@@ -215,7 +215,7 @@ static __poll_t dma_buf_poll(struct file return 0; retry: @@ -29,7 +29,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> rcu_read_lock(); fobj = rcu_dereference(resv->fence); -@@ -223,7 +223,7 @@ static __poll_t dma_buf_poll(struct file +@@ -224,7 +224,7 @@ static __poll_t dma_buf_poll(struct file else shared_count = 0; fence_excl = rcu_dereference(resv->fence_excl); @@ -38,7 +38,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> rcu_read_unlock(); goto retry; } -@@ -1189,12 +1189,12 @@ static int dma_buf_debug_show(struct seq +@@ -1190,12 +1190,12 @@ static int dma_buf_debug_show(struct seq robj = buf_obj->resv; while (true) { diff --git a/patches/localversion.patch b/patches/localversion.patch index 0cccc7790a5d..3dc62b40b5be 100644 --- a/patches/localversion.patch +++ b/patches/localversion.patch @@ -10,4 +10,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- /dev/null +++ b/localversion-rt @@ -0,0 +1 @@ -+-rt16 ++-rt17 diff --git a/patches/mm-Warn-on-memory-allocation-in-non-preemptible-cont.patch b/patches/mm-Warn-on-memory-allocation-in-non-preemptible-cont.patch index 93cf8c31e73a..ffcb8b9dbfcf 100644 --- a/patches/mm-Warn-on-memory-allocation-in-non-preemptible-cont.patch +++ b/patches/mm-Warn-on-memory-allocation-in-non-preemptible-cont.patch @@ -14,6 +14,7 @@ Add a warning on RT if a memory allocation was attempted in not preemptible region. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Reviewed-by: Daniel Bristot de Oliveira <bristot@redhat.com> --- mm/slub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/patches/mm-convert-swap-to-percpu-locked.patch b/patches/mm-convert-swap-to-percpu-locked.patch index 35cc49769821..71725de9c3b5 100644 --- a/patches/mm-convert-swap-to-percpu-locked.patch +++ b/patches/mm-convert-swap-to-percpu-locked.patch @@ -25,7 +25,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> #include <asm/page.h> struct notifier_block; -@@ -329,6 +330,7 @@ extern unsigned long nr_free_pagecache_p +@@ -328,6 +329,7 @@ extern unsigned long nr_free_pagecache_p /* linux/mm/swap.c */ @@ -35,7 +35,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> extern void lru_cache_add_file(struct page *page); --- a/mm/compaction.c +++ b/mm/compaction.c -@@ -2240,10 +2240,12 @@ compact_zone(struct compact_control *cc, +@@ -2244,10 +2244,12 @@ compact_zone(struct compact_control *cc, block_start_pfn(cc->migrate_pfn, cc->order); if (last_migrated_pfn < current_block_start) { @@ -52,7 +52,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7572,8 +7572,9 @@ void __init free_area_init(unsigned long +@@ -7676,8 +7676,9 @@ void __init free_area_init(unsigned long static int page_alloc_cpu_dead(unsigned int cpu) { @@ -73,7 +73,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> #include <linux/hugetlb.h> #include <linux/page_idle.h> -@@ -51,6 +52,8 @@ static DEFINE_PER_CPU(struct pagevec, lr +@@ -52,6 +53,8 @@ static DEFINE_PER_CPU(struct pagevec, lr #ifdef CONFIG_SMP static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs); #endif @@ -82,7 +82,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /* * This path almost never happens for VM activity - pages are normally -@@ -253,11 +256,11 @@ void rotate_reclaimable_page(struct page +@@ -254,11 +257,11 @@ void rotate_reclaimable_page(struct page unsigned long flags; get_page(page); @@ -96,7 +96,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } } -@@ -307,12 +310,13 @@ void activate_page(struct page *page) +@@ -308,12 +311,13 @@ void activate_page(struct page *page) { page = compound_head(page); if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { @@ -112,7 +112,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } } -@@ -334,7 +338,7 @@ void activate_page(struct page *page) +@@ -335,7 +339,7 @@ void activate_page(struct page *page) static void __lru_cache_activate_page(struct page *page) { @@ -121,7 +121,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> int i; /* -@@ -356,7 +360,7 @@ static void __lru_cache_activate_page(st +@@ -357,7 +361,7 @@ static void __lru_cache_activate_page(st } } @@ -130,7 +130,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } /* -@@ -398,12 +402,12 @@ EXPORT_SYMBOL(mark_page_accessed); +@@ -399,12 +403,12 @@ EXPORT_SYMBOL(mark_page_accessed); static void __lru_cache_add(struct page *page) { @@ -145,7 +145,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } /** -@@ -581,9 +585,9 @@ void lru_add_drain_cpu(int cpu) +@@ -598,9 +602,9 @@ void lru_add_drain_cpu(int cpu) unsigned long flags; /* No harm done if a racing interrupt already did this */ @@ -157,7 +157,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } pvec = &per_cpu(lru_deactivate_file_pvecs, cpu); -@@ -615,11 +619,12 @@ void deactivate_file_page(struct page *p +@@ -636,11 +640,12 @@ void deactivate_file_page(struct page *p return; if (likely(get_page_unless_zero(page))) { @@ -172,7 +172,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> } } -@@ -634,19 +639,20 @@ void mark_page_lazyfree(struct page *pag +@@ -675,19 +680,20 @@ void mark_page_lazyfree(struct page *pag { if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page) && !PageUnevictable(page)) { diff --git a/patches/mm-memcontrol-Move-misplaced-local_unlock_irqrestore.patch b/patches/mm-memcontrol-Move-misplaced-local_unlock_irqrestore.patch index 3f64e1197d1b..d55cfd4c3043 100644 --- a/patches/mm-memcontrol-Move-misplaced-local_unlock_irqrestore.patch +++ b/patches/mm-memcontrol-Move-misplaced-local_unlock_irqrestore.patch @@ -17,7 +17,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -7027,10 +7027,10 @@ void mem_cgroup_swapout(struct page *pag +@@ -7017,10 +7017,10 @@ void mem_cgroup_swapout(struct page *pag mem_cgroup_charge_statistics(memcg, page, PageTransHuge(page), -nr_entries); memcg_check_events(memcg, page); diff --git a/patches/mm-memcontrol-do_not_disable_irq.patch b/patches/mm-memcontrol-do_not_disable_irq.patch index 16e762228089..097f6726c8b1 100644 --- a/patches/mm-memcontrol-do_not_disable_irq.patch +++ b/patches/mm-memcontrol-do_not_disable_irq.patch @@ -88,7 +88,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key); -@@ -6971,6 +6974,7 @@ void mem_cgroup_swapout(struct page *pag +@@ -6961,6 +6964,7 @@ void mem_cgroup_swapout(struct page *pag struct mem_cgroup *memcg, *swap_memcg; unsigned int nr_entries; unsigned short oldid; @@ -96,7 +96,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> VM_BUG_ON_PAGE(PageLRU(page), page); VM_BUG_ON_PAGE(page_count(page), page); -@@ -7016,13 +7020,17 @@ void mem_cgroup_swapout(struct page *pag +@@ -7006,13 +7010,17 @@ void mem_cgroup_swapout(struct page *pag * important here to have the interrupts disabled because it is the * only synchronisation we have for updating the per-CPU variables. */ diff --git a/patches/mm-page_alloc-Use-migrate_disable-in-drain_local_pa.patch b/patches/mm-page_alloc-Use-migrate_disable-in-drain_local_pa.patch new file mode 100644 index 000000000000..2ba50c9f9c24 --- /dev/null +++ b/patches/mm-page_alloc-Use-migrate_disable-in-drain_local_pa.patch @@ -0,0 +1,34 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Fri, 20 Mar 2020 16:19:51 +0100 +Subject: [PATCH] mm/page_alloc: Use migrate_disable() in + drain_local_pages_wq() + +The drain_local_pages_wq() uses preempt_disable() to ensure that there +will be no CPU migration while drain_local_pages() is invoked which +might happen if the CPU is going down. +drain_local_pages() acquires a sleeping lock on RT which can not be +acquired with disabled preemption. + +Use migrate_disable() instead of preempt_disable(): On RT it ensures +that the CPU won't go down and on !RT it is replaced with +preempt_disable(). + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + mm/page_alloc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -2912,9 +2912,9 @@ static void drain_local_pages_wq(struct + * cpu which is allright but we also have to make sure to not move to + * a different one. + */ +- preempt_disable(); ++ migrate_disable(); + drain_local_pages(drain->zone); +- preempt_enable(); ++ migrate_enable(); + } + + /* diff --git a/patches/mm-perform-lru_add_drain_all-remotely.patch b/patches/mm-perform-lru_add_drain_all-remotely.patch index 8b50fcc8cf21..0cfb2aadb930 100644 --- a/patches/mm-perform-lru_add_drain_all-remotely.patch +++ b/patches/mm-perform-lru_add_drain_all-remotely.patch @@ -24,7 +24,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/mm/swap.c +++ b/mm/swap.c -@@ -585,9 +585,15 @@ void lru_add_drain_cpu(int cpu) +@@ -602,9 +602,15 @@ void lru_add_drain_cpu(int cpu) unsigned long flags; /* No harm done if a racing interrupt already did this */ @@ -40,7 +40,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } pvec = &per_cpu(lru_deactivate_file_pvecs, cpu); -@@ -657,6 +663,16 @@ void lru_add_drain(void) +@@ -698,6 +704,16 @@ void lru_add_drain(void) #ifdef CONFIG_SMP @@ -57,7 +57,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work); static void lru_add_drain_per_cpu(struct work_struct *dummy) -@@ -664,6 +680,16 @@ static void lru_add_drain_per_cpu(struct +@@ -705,6 +721,16 @@ static void lru_add_drain_per_cpu(struct lru_add_drain(); } @@ -74,7 +74,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Doesn't need any cpu hotplug locking because we do rely on per-cpu * kworkers being shut down before our page_alloc_cpu_dead callback is -@@ -688,21 +714,19 @@ void lru_add_drain_all(void) +@@ -729,22 +755,20 @@ void lru_add_drain_all(void) cpumask_clear(&has_work); for_each_online_cpu(cpu) { @@ -83,6 +83,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) || pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) || pagevec_count(&per_cpu(lru_deactivate_file_pvecs, cpu)) || + pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) || pagevec_count(&per_cpu(lru_lazyfree_pvecs, cpu)) || - need_activate_page_drain(cpu)) { - INIT_WORK(work, lru_add_drain_per_cpu); diff --git a/patches/mm-swap-Enable-use-pvec-lock-on-RT.patch b/patches/mm-swap-Enable-use-pvec-lock-on-RT.patch deleted file mode 100644 index 90c04567ee02..000000000000 --- a/patches/mm-swap-Enable-use-pvec-lock-on-RT.patch +++ /dev/null @@ -1,41 +0,0 @@ -From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> -Date: Mon, 12 Aug 2019 11:20:44 +0200 -Subject: [PATCH] mm/swap: Enable use pvec lock on RT - -On RT we also need to avoid preempt disable/IRQ-off regions so have to enable -the locking while accessing pvecs. - -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - mm/internal.h | 4 ++++ - mm/swap.c | 4 ++++ - 2 files changed, 8 insertions(+) - ---- a/mm/internal.h -+++ b/mm/internal.h -@@ -32,7 +32,11 @@ - /* Do not use these with a slab allocator */ - #define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK) - -+#ifdef CONFIG_PREEMPT_RT -+extern struct static_key_true use_pvec_lock; -+#else - extern struct static_key_false use_pvec_lock; -+#endif - - void page_writeback_init(void); - ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -44,7 +44,11 @@ - /* How many pages do we try to swap or page in/out together? */ - int page_cluster; - -+#ifdef CONFIG_PREEMPT_RT -+DEFINE_STATIC_KEY_TRUE(use_pvec_lock); -+#else - DEFINE_STATIC_KEY_FALSE(use_pvec_lock); -+#endif - - struct swap_pagevec { - spinlock_t lock; diff --git a/patches/powerpc-Fix-lazy-preemption-for-powerpc-32bit.patch b/patches/powerpc-Fix-lazy-preemption-for-powerpc-32bit.patch new file mode 100644 index 000000000000..de534c7211af --- /dev/null +++ b/patches/powerpc-Fix-lazy-preemption-for-powerpc-32bit.patch @@ -0,0 +1,34 @@ +From: Thomas Graziadei <thomas.graziadei@omicronenergy.com> +Date: Wed, 18 Mar 2020 21:26:40 +0100 +Subject: [PATCH] powerpc: Fix lazy preemption for powerpc 32bit + +The 32bit powerpc assembler implementation of the lazy preemption +set the _TIF_PERSYSCALL_MASK on the low word. This could lead to +modprobe segfaults and a kernel panic - not syncing: Attempt to +kill init! issue. + +Fixed by shifting the mask by 16 bit using andis and lis. + +Signed-off-by: Thomas Graziadei <thomas.graziadei@omicronenergy.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/powerpc/kernel/entry_32.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/kernel/entry_32.S ++++ b/arch/powerpc/kernel/entry_32.S +@@ -533,12 +533,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRE + + 1: stw r6,RESULT(r1) /* Save result */ + stw r3,GPR3(r1) /* Update return value */ +-2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)@h ++2: andis. r0,r9,(_TIF_PERSYSCALL_MASK)@h + beq 4f + + /* Clear per-syscall TIF flags if any are set. */ + +- li r11,_TIF_PERSYSCALL_MASK@h ++ lis r11,(_TIF_PERSYSCALL_MASK)@h + addi r12,r2,TI_FLAGS + 3: lwarx r8,0,r12 + andc r8,r8,r11 diff --git a/patches/series b/patches/series index 58ea97ab810a..07da648a4c55 100644 --- a/patches/series +++ b/patches/series @@ -35,6 +35,8 @@ net-sched-dev_deactivate_many-use-msleep-1-instead-o.patch mm-vmalloc-remove-preempt_disable-enable-when-doing-.patch # 9090825fa99740f0c794f94b9cbd57ad79101228 KVM-arm-arm64-Let-the-timer-expire-in-hardirq-contex.patch +# 2c8bd58812ee3dbf0d78b566822f7eacd34bdd7b (tip) +time-sched_clock-Expire-timer-in-hardirq-context.patch ############################################################ # POSTED by others @@ -256,13 +258,9 @@ oleg-signal-rt-fix.patch mm-page_alloc-rt-friendly-per-cpu-pages.patch # MM SWAP -# mm-convert-swap-to-percpu-locked.patch -# mm-perform-lru_add_drain_all-remotely.patch -0001-mm-page_alloc-Split-drain_local_pages.patch -0002-mm-swap-Add-static-key-dependent-pagevec-locking.patch -0003-mm-swap-Access-struct-pagevec-remotely.patch -0004-mm-swap-Enable-use_pvec_lock-nohz_full-dependent.patch -mm-swap-Enable-use-pvec-lock-on-RT.patch +mm-convert-swap-to-percpu-locked.patch +mm-perform-lru_add_drain_all-remotely.patch +mm-page_alloc-Use-migrate_disable-in-drain_local_pa.patch # PREEMPT NORT preempt-nort-rt-variants.patch @@ -293,6 +291,7 @@ x86-kvm-require-const-tsc-for-rt.patch pci-switchtec-Don-t-use-completion-s-wait-queue.patch wait.h-include-atomic.h.patch completion-use-simple-wait-queues.patch +swait-Remove-the-warning-with-more-than-two-waiters.patch # HRTIMERS # Check whether schedule_hrtimeout() could be hard always @@ -510,6 +509,7 @@ preempt-lazy-support.patch x86-preempt-lazy.patch arm-preempt-lazy-support.patch powerpc-preempt-lazy-support.patch +powerpc-Fix-lazy-preemption-for-powerpc-32bit.patch arch-arm64-Add-lazy-preempt-support.patch tracing-make-preempt_lazy-and-migrate_disable-counte.patch diff --git a/patches/swait-Remove-the-warning-with-more-than-two-waiters.patch b/patches/swait-Remove-the-warning-with-more-than-two-waiters.patch new file mode 100644 index 000000000000..67726cb612c8 --- /dev/null +++ b/patches/swait-Remove-the-warning-with-more-than-two-waiters.patch @@ -0,0 +1,122 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Fri, 20 Mar 2020 13:28:35 +0100 +Subject: [PATCH] swait: Remove the warning with more than two waiters + +The warning was introduced to find callers of complete_all() having +multiple waiters enqueued. As completa_all() wakes all waiters with +disabled interrupts it may lead visibile latency spikes with a larger +amount of waiters. + +Since the warning was introduced, most of the feedback was in the +"setup/configure" phase which is nothing that would disturb the RT +workload because it is not yet active. +There were reports regarding the crypto code which may wake multiple +waiters if all of them request an algorithm which requires a module to +be loaded first. If this really become a problem during runtime it +should be investigated then. + +Remove the warning if more than two waiters are worken up via the +complete_all() interface. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + include/linux/suspend.h | 6 ------ + kernel/power/hibernate.c | 7 ------- + kernel/power/suspend.c | 4 ---- + kernel/sched/swait.c | 5 ----- + 4 files changed, 22 deletions(-) + +--- a/include/linux/suspend.h ++++ b/include/linux/suspend.h +@@ -197,12 +197,6 @@ struct platform_s2idle_ops { + void (*end)(void); + }; + +-#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION) +-extern bool pm_in_action; +-#else +-# define pm_in_action false +-#endif +- + #ifdef CONFIG_SUSPEND + extern suspend_state_t mem_sleep_current; + extern suspend_state_t mem_sleep_default; +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -689,10 +689,6 @@ static int load_image_and_restore(void) + return error; + } + +-#ifndef CONFIG_SUSPEND +-bool pm_in_action; +-#endif +- + /** + * hibernate - Carry out system hibernation, including saving the image. + */ +@@ -706,8 +702,6 @@ int hibernate(void) + return -EPERM; + } + +- pm_in_action = true; +- + lock_system_sleep(); + /* The snapshot device should not be opened while we're running */ + if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { +@@ -784,7 +778,6 @@ int hibernate(void) + atomic_inc(&snapshot_device_available); + Unlock: + unlock_system_sleep(); +- pm_in_action = false; + pr_info("hibernation exit\n"); + + return error; +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -595,8 +595,6 @@ static int enter_state(suspend_state_t s + return error; + } + +-bool pm_in_action; +- + /** + * pm_suspend - Externally visible function for suspending the system. + * @state: System sleep state to enter. +@@ -611,7 +609,6 @@ int pm_suspend(suspend_state_t state) + if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) + return -EINVAL; + +- pm_in_action = true; + pr_info("suspend entry (%s)\n", mem_sleep_labels[state]); + error = enter_state(state); + if (error) { +@@ -621,7 +618,6 @@ int pm_suspend(suspend_state_t state) + suspend_stats.success++; + } + pr_info("suspend exit\n"); +- pm_in_action = false; + return error; + } + EXPORT_SYMBOL(pm_suspend); +--- a/kernel/sched/swait.c ++++ b/kernel/sched/swait.c +@@ -35,7 +35,6 @@ EXPORT_SYMBOL(swake_up_locked); + void swake_up_all_locked(struct swait_queue_head *q) + { + struct swait_queue *curr; +- int wakes = 0; + + while (!list_empty(&q->task_list)) { + +@@ -43,11 +42,7 @@ void swake_up_all_locked(struct swait_qu + task_list); + wake_up_process(curr->task); + list_del_init(&curr->task_list); +- wakes++; + } +- if (pm_in_action) +- return; +- WARN(wakes > 2, "complete_all() with %d waiters\n", wakes); + } + EXPORT_SYMBOL(swake_up_all_locked); + diff --git a/patches/time-sched_clock-Expire-timer-in-hardirq-context.patch b/patches/time-sched_clock-Expire-timer-in-hardirq-context.patch new file mode 100644 index 000000000000..75d291a1b999 --- /dev/null +++ b/patches/time-sched_clock-Expire-timer-in-hardirq-context.patch @@ -0,0 +1,55 @@ +From: "Ahmed S. Darwish" <a.darwish@linutronix.de> +Date: Mon, 9 Mar 2020 18:15:29 +0000 +Subject: [PATCH] time/sched_clock: Expire timer in hardirq context + +To minimize latency, PREEMPT_RT kernels expires hrtimers in preemptible +softirq context by default. This can be overriden by marking the timer's +expiry with HRTIMER_MODE_HARD. + +sched_clock_timer is missing this annotation: if its callback is preempted +and the duration of the preemption exceeds the wrap around time of the +underlying clocksource, sched clock will get out of sync. + +Mark the sched_clock_timer for expiry in hard interrupt context. + +Signed-off-by: Ahmed S. Darwish <a.darwish@linutronix.de> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Link: https://lkml.kernel.org/r/20200309181529.26558-1-a.darwish@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + kernel/time/sched_clock.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/kernel/time/sched_clock.c ++++ b/kernel/time/sched_clock.c +@@ -207,7 +207,8 @@ sched_clock_register(u64 (*read)(void), + + if (sched_clock_timer.function != NULL) { + /* update timeout for clock wrap */ +- hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); ++ hrtimer_start(&sched_clock_timer, cd.wrap_kt, ++ HRTIMER_MODE_REL_HARD); + } + + r = rate; +@@ -251,9 +252,9 @@ void __init generic_sched_clock_init(voi + * Start the timer to keep sched_clock() properly updated and + * sets the initial epoch. + */ +- hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); + sched_clock_timer.function = sched_clock_poll; +- hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); ++ hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); + } + + /* +@@ -290,7 +291,7 @@ void sched_clock_resume(void) + struct clock_read_data *rd = &cd.read_data[0]; + + rd->epoch_cyc = cd.actual_read_sched_clock(); +- hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); ++ hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); + rd->read_sched_clock = cd.actual_read_sched_clock; + } + |