mm: thp: fix MADV_DONTNEED vs migrate_misplaced_transhuge_page race condition
Subsystems (2)
Sasha Levin
maintainerPATCH 1/45 mm: thp: fix MADV_DONTNEED vs migrate_misplaced_transhuge_page race condition
From: Andrea Arcangeli <[email protected]>
[ Upstream commit d7c3393413fe7e7dc54498ea200ea94742d61e18 ]
Patch series "migrate_misplaced_transhuge_page race conditions".
Aaron found a new instance of the THP MADV_DONTNEED race against pmdp_clear_flush* variants, that was apparently left unfixed.
While looking into the race found by Aaron, I may have found two more issues in migrate_misplaced_transhuge_page.
These race conditions would not cause kernel instability, but they'd corrupt userland data or leave data non zero after MADV_DONTNEED.
I did only minor testing, and I don't expect to be able to reproduce this (especially the lack of ->invalidate_range before migrate_page_copy, requires the latest iommu hardware or infiniband to reproduce). The last patch is noop for x86 and it needs further review from maintainers of archs that implement flush_cache_range() (not in CC yet).
To avoid confusion, it's not the first patch that introduces the bug fixed in the second patch, even before removing the pmdp_huge_clear_flush_notify, that _notify suffix was called after migrate_page_copy already run.
This patch (of 3):
This is a corollary of ced108037c2aa ("thp: fix MADV_DONTNEED vs. numa balancing race"), 58ceeb6bec8 ("thp: fix MADV_DONTNEED vs. MADV_FREE race") and 5b7abeae3af8c ("thp: fix MADV_DONTNEED vs clear soft dirty race).
When the above three fixes where posted Dave asked
https://lkml.kernel.org/r/[email protected]
but apparently this was missed.
The pmdp_clear_flush* in migrate_misplaced_transhuge_page() was introduced in a54a407fbf7 ("mm: Close races between THP migration and PMD numa clearing").
The important part of such commit is only the part where the page lock is not released until the first do_huge_pmd_numa_page() finished disarming the pagenuma/protnone.
The addition of pmdp_clear_flush() wasn't beneficial to such commit and there's no commentary about such an addition either.
I guess the pmdp_clear_flush() in such commit was added just in case for safety, but it ended up introducing the MADV_DONTNEED race condition found by Aaron.
At that point in time nobody thought of such kind of MADV_DONTNEED race conditions yet (they were fixed later) so the code may have looked more robust by adding the pmdp_clear_flush().
This specific race condition won't destabilize the kernel, but it can confuse userland because after MADV_DONTNEED the memory won't be zeroed out.
This also optimizes the code and removes a superfluous TLB flush.
--- mm/migrate.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
mm/migrate.c +18 -7
@@ -2086,15 +2086,26 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, entry =maybe_pmd_mkwrite (pmd_mkdirty (entry), vma);/* -* Clear the old entry under pagetable lock and establish the new PTE. -* Any parallel GUP will either observe the old page blocking on the -* page lock, block on the page table lock or observe the new page. -* The SetPageUptodate on the new page and page_add_new_anon_rmap -* guarantee the copy is visible before the pagetable update. +* Overwrite the old entry under pagetable lock and establish +* the new PTE. Any parallel GUP will either observe the old +* page blocking on the page lock, block on the page table +* lock or observe the new page. The SetPageUptodate on the +* new page and page_add_new_anon_rmap guarantee the copy is +* visible before the pagetable update. */ flush_cache_range (vma, mmun_start, mmun_end);page_add_anon_rmap (new_page, vma, mmun_start, true); -pmdp_huge_clear_flush_notify (vma, mmun_start, pmd); +/* +* At this point the pmd is numa/protnone (i.e. non present) and the TLB +* has already been flushed globally. So no TLB can be currently +* caching this non present pmd mapping. There's no need to clear the +* pmd before doing set_pmd_at(), nor to flush the TLB after +* set_pmd_at(). Clearing the pmd here would introduce a race +* condition against MADV_DONTNEED, because MADV_DONTNEED only holds the +* mmap_sem for reading. If the pmd is set to NULL at any given time, +* MADV_DONTNEED won't wait on the pmd lock and it'll skip clearing this +* pmd. +*/ set_pmd_at (mm, mmun_start, pmd, entry);update_mmu_cache_pmd (vma, address, &entry);
@@ -2108,7 +2119,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,* No need to double call mmu_notifier->invalidate_range() callback as * the above pmdp_huge_clear_flush_notify() did already call it. */ -mmu_notifier_invalidate_range_only_end (mm, mmun_start, mmun_end); +mmu_notifier_invalidate_range_end (mm, mmun_start, mmun_end);/* Take an "isolate" reference and put new page on the LRU. */ get_page (new_page);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 2/45 mm: thp: fix mmu_notifier in migrate_misplaced_transhuge_page()
From: Andrea Arcangeli <[email protected]>
[ Upstream commit 7066f0f933a1fd707bb38781866657769cff7efc ]
change_huge_pmd() after arming the numa/protnone pmd doesn't flush the TLB right away. do_huge_pmd_numa_page() flushes the TLB before calling migrate_misplaced_transhuge_page(). By the time do_huge_pmd_numa_page() runs some CPU could still access the page through the TLB.
change_huge_pmd() before arming the numa/protnone transhuge pmd calls mmu_notifier_invalidate_range_start(). So there's no need of mmu_notifier_invalidate_range_start()/mmu_notifier_invalidate_range_only_end() sequence in migrate_misplaced_transhuge_page() too, because by the time migrate_misplaced_transhuge_page() runs, the pmd mapping has already been invalidated in the secondary MMUs. It has to or if a secondary MMU can still write to the page, the migrate_page_copy() would lose data.
However an explicit mmu_notifier_invalidate_range() is needed before migrate_misplaced_transhuge_page() starts copying the data of the transhuge page or the below can happen for MMU notifier users sharing the primary MMU pagetables and only implementing ->invalidate_range:
CPU0 CPU1 GPU sharing linux pagetables using
only ->invalidate_range
----------- ------------ ---------
GPU secondary MMU writes to the page mapped by the transhuge pmdchange_pmd_range()
mmu..._range_start()
->invalidate_range_start() noopchange_huge_pmd()set_pmd_at(numa/protnone)pmd_unlock()
do_huge_pmd_numa_page()
CPU TLB flush globally (1)
CPU cannot write to page migrate_misplaced_transhuge_page()
GPU writes to the page...
migrate_page_copy()
...GPU stops writing to the page
CPU TLB flush (2)
mmu..._range_end() (3)
->invalidate_range_stop() noop
->invalidate_range()
GPU secondary MMU is invalidated and cannot write to the page anymore (too late)
Just like we need a CPU TLB flush (1) because the TLB flush (2) arrives too late, we also need a mmu_notifier_invalidate_range() before calling migrate_misplaced_transhuge_page(), because the ->invalidate_range() in
(3) also arrives too late.
This requirement is the result of the lazy optimization in change_huge_pmd() that releases the pmd_lock without first flushing the TLB and without first calling mmu_notifier_invalidate_range().
Even converting the removed mmu_notifier_invalidate_range_only_end() into a mmu_notifier_invalidate_range_end() would not have been enough to fix this, because it run after migrate_page_copy().
After the hugepage data copy is done migrate_misplaced_transhuge_page() can proceed and call set_pmd_at without having to flush the TLB nor any secondary MMUs because the secondary MMU invalidate, just like the CPU TLB flush, has to happen before the migrate_page_copy() is called or it would be a bug in the first place (and it was for drivers using ->invalidate_range()).
KVM is unaffected because it doesn't implement ->invalidate_range().
The standard PAGE_SIZEd migrate_misplaced_page is less accelerated and uses the generic migrate_pages which transitions the pte from numa/protnone to a migration entry in try_to_unmap_one() and flushes TLBs and all mmu notifiers there before copying the page.
--- mm/huge_memory.c | 14 +++++++++++++- mm/migrate.c | 19 ++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-)
mm/huge_memory.c +13 -1
@@ -1560,8 +1560,20 @@ int do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t pmd)* We are not sure a pending tlb flush here is for a huge page * mapping or not. Hence use the tlb range variant */ -if (mm_tlb_flush_pending (vma->vm_mm)) +if (mm_tlb_flush_pending (vma->vm_mm)) {flush_tlb_range (vma, haddr, haddr +HPAGE_PMD_SIZE ); +/* +* change_huge_pmd() released the pmd lock before +* invalidating the secondary MMUs sharing the primary +* MMU pagetables (with ->invalidate_range()). The +* mmu_notifier_invalidate_range_end() (which +* internally calls ->invalidate_range()) in +* change_pmd_range() will run after us, so we can't +* rely on it here and we need an explicit invalidate. +*/ +mmu_notifier_invalidate_range (vma->vm_mm, haddr, + haddr +HPAGE_PMD_SIZE ); + }/* * Migrate the THP to the requested node, returns with page unlocked
mm/migrate.c +6 -13
@@ -2022,8 +2022,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,int isolated =0 ;struct page *new_page =NULL ;int page_lru =page_is_file_cache (page); -unsigned long mmun_start = address &HPAGE_PMD_MASK ; -unsigned long mmun_end = mmun_start +HPAGE_PMD_SIZE ; +unsigned long start = address &HPAGE_PMD_MASK ; +unsigned long end = start +HPAGE_PMD_SIZE ;/* * Rate-limit the amount of data that is being migrated to a node.
@@ -2058,11 +2058,9 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,WARN_ON (PageLRU (new_page));/* Recheck the target PMD */ -mmu_notifier_invalidate_range_start (mm, mmun_start, mmun_end); ptl =pmd_lock (mm, pmd);if (unlikely (!pmd_same (*pmd, entry) || !page_ref_freeze (page,2 ))) {spin_unlock (ptl); -mmu_notifier_invalidate_range_end (mm, mmun_start, mmun_end);/* Reverse changes made by migrate_page_copy() */ if (TestClearPageActive (new_page))
@@ -2093,8 +2091,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,* new page and page_add_new_anon_rmap guarantee the copy is * visible before the pagetable update. */ -flush_cache_range (vma, mmun_start, mmun_end); -page_add_anon_rmap (new_page, vma, mmun_start, true); +flush_cache_range (vma, start, end); +page_add_anon_rmap (new_page, vma, start, true);/* * At this point the pmd is numa/protnone (i.e. non present) and the TLB * has already been flushed globally. So no TLB can be currently
@@ -2106,7 +2104,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,* MADV_DONTNEED won't wait on the pmd lock and it'll skip clearing this * pmd. */ -set_pmd_at (mm, mmun_start, pmd, entry); +set_pmd_at (mm, start, pmd, entry);update_mmu_cache_pmd (vma, address, &entry);page_ref_unfreeze (page,2 );
@@ -2115,11 +2113,6 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,set_page_owner_migrate_reason (new_page,MR_NUMA_MISPLACED );spin_unlock (ptl); -/* -* No need to double call mmu_notifier->invalidate_range() callback as -* the above pmdp_huge_clear_flush_notify() did already call it. -*/ -mmu_notifier_invalidate_range_end (mm, mmun_start, mmun_end);/* Take an "isolate" reference and put new page on the LRU. */ get_page (new_page);
@@ -2144,7 +2137,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, ptl =pmd_lock (mm, pmd);if (pmd_same (*pmd, entry)) { entry =pmd_modify (entry, vma->vm_page_prot); -set_pmd_at (mm, mmun_start, pmd, entry); +set_pmd_at (mm, start, pmd, entry);update_mmu_cache_pmd (vma, address, &entry); }spin_unlock (ptl);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 3/45 mm: calculate deferred pages after skipping mirrored memory
In reply to Sasha LevinFrom: Pavel Tatashin <[email protected]>
[ Upstream commit d3035be4ce2345d98633a45f93a74e526e94b802 ]
update_defer_init() should be called only when struct page is about to be initialized. Because it counts number of initialized struct pages, but there we may skip struct pages if there is some mirrored memory.
So move, update_defer_init() after checking for mirrored memory.
Also, rename update_defer_init() to defer_init() and reverse the return boolean to emphasize that this is a boolean function, that tells that the reset of memmap initialization should be deferred.
Make this function self-contained: do not pass number of already initialized pages in this zone by using static counters.
I found this bug by reading the code. The effect is that fewer than expected struct pages are initialized early in boot, and it is possible that in some corner cases we may fail to boot when mirrored pages are used. The deferred on demand code should somewhat mitigate this. But this still brings some inconsistencies compared to when booting without mirrored pages, so it is better to fix.
--- mm/page_alloc.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-)
mm/page_alloc.c +25 -20
@@ -306,24 +306,33 @@ static inline bool __meminit early_page_uninitialised(unsigned long pfn) }/* -* Returns false when the remaining initialisation should be deferred until +* Returns true when the remaining initialisation should be deferred until * later in the boot cycle when it can be parallelised. */ -static inline bool update_defer_init (pg_data_t *pgdat, -unsigned long pfn,unsigned long zone_end, -unsigned long *nr_initialised) +static bool __meminit +defer_init (int nid,unsigned long pfn,unsigned long end_pfn) { +static unsigned long prev_end_pfn, nr_initialised; + +/* +* prev_end_pfn static that contains the end of previous zone +* No need to protect because called very early in boot before smp_init. +*/ +if (prev_end_pfn != end_pfn) { + prev_end_pfn = end_pfn; + nr_initialised =0 ; + } +/* Always populate low zones for address-constrained allocations */ -if (zone_end <pgdat_end_pfn (pgdat)) -return true; - (*nr_initialised)++; -if ((*nr_initialised > pgdat->static_init_pgcnt) && - (pfn & (PAGES_PER_SECTION -1 )) ==0 ) { - pgdat->first_deferred_pfn = pfn; +if (end_pfn <pgdat_end_pfn (NODE_DATA (nid)))return false; + nr_initialised++; +if ((nr_initialised >NODE_DATA (nid)->static_init_pgcnt) && + (pfn & (PAGES_PER_SECTION -1 )) ==0 ) { +NODE_DATA (nid)->first_deferred_pfn = pfn; +return true; } - -return true; +return false; }#else static inline bool early_page_uninitialised (unsigned long pfn)
@@ -331,11 +340,9 @@ static inline bool early_page_uninitialised(unsigned long pfn) return false; } -static inline bool update_defer_init (pg_data_t *pgdat, -unsigned long pfn,unsigned long zone_end, -unsigned long *nr_initialised) +static inline bool defer_init (int nid,unsigned long pfn,unsigned long end_pfn) { -return true; +return false; }#endif
@@ -5462,9 +5469,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, struct vmem_altmap *altmap) {unsigned long end_pfn = start_pfn + size; -pg_data_t *pgdat =NODE_DATA (nid);unsigned long pfn; -unsigned long nr_initialised =0 ;struct page *page;#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP struct memblock_region *r =NULL , *tmp;
@@ -5492,8 +5497,6 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,continue ;if (!early_pfn_in_nid (pfn, nid))continue ; -if (!update_defer_init (pgdat, pfn, end_pfn, &nr_initialised)) -break ;#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP /*
@@ -5516,6 +5519,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, } }#endif +if (defer_init (nid, pfn, end_pfn)) +break ; not_early: page =pfn_to_page (pfn);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 4/45 mm/vmstat.c: assert that vmstat_text is in sync with stat_items_size
In reply to Sasha LevinFrom: Jann Horn <[email protected]>
[ Upstream commit f0ecf25a093fc0589f0a6bc4c1ea068bbb67d220 ]
Having two gigantic arrays that must manually be kept in sync, including ifdefs, isn't exactly robust. To make it easier to catch such issues in the future, add a BUILD_BUG_ON().
--- mm/vmstat.c | 2 ++ 1 file changed, 2 insertions(+)
mm/vmstat.c +2 -0
@@ -1663,6 +1663,8 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos) stat_items_size +=sizeof (struct vm_event_state );#endif +BUILD_BUG_ON (stat_items_size != +ARRAY_SIZE (vmstat_text) *sizeof (unsigned long )); v =kmalloc (stat_items_size,GFP_KERNEL ); m->private = v;if (!v)
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 5/45 userfaultfd: allow get_mempolicy(MPOL_F_NODE|MPOL_F_ADDR) to trigger userfaults
In reply to Sasha LevinFrom: Andrea Arcangeli <[email protected]>
[ Upstream commit 3b9aadf7278d16d7bed4d5d808501065f70898d8 ]
get_mempolicy(MPOL_F_NODE|MPOL_F_ADDR) called a get_user_pages that would not be waiting for userfaults before failing and it would hit on a SIGBUS instead. Using get_user_pages_locked/unlocked instead will allow get_mempolicy to allow userfaults to resolve the fault and fill the hole, before grabbing the node id of the page.
If the user calls get_mempolicy() with MPOL_F_ADDR | MPOL_F_NODE for an address inside an area managed by uffd and there is no page at that address, the page allocation from within get_mempolicy() will fail because get_user_pages() does not allow for page fault retry required for uffd; the user will get SIGBUS.
With this patch, the page fault will be resolved by the uffd and the get_mempolicy() will continue normally.
Background:
Via code review, previously the syscall would have returned -EFAULT (vm_fault_to_errno), now it will block and wait for an userfault (if it's waken before the fault is resolved it'll still -EFAULT).
This way get_mempolicy will give a chance to an "unaware" app to be compliant with userfaults.
The reason this visible change is that becoming "userfault compliant" cannot regress anything: all other syscalls including read(2)/write(2) had to become "userfault compliant" long time ago (that's one of the things userfaultfd can do that PROT_NONE and trapping segfaults can't).
So this is just one more syscall that become "userfault compliant" like all other major ones already were.
This has been happening on virtio-bridge dpdk process which just called get_mempolicy on the guest space post live migration, but before the memory had a chance to be migrated to destination.
I didn't run an strace to be able to show the -EFAULT going away, but I've the confirmation of the below debug aid information (only visible with CONFIG_DEBUG_VM=y) going away with the patch:
[20116.371461] FAULT_FLAG_ALLOW_RETRY missing 0
[20116.371464] CPU: 1 PID: 13381 Comm: vhost-events Not tainted 4.17.12-200.fc28.x86_64 #1
[20116.371465] Hardware name: LENOVO 20FAS2BN0A/20FAS2BN0A, BIOS N1CET54W (1.22 ) 02/10/2017
[20116.371466] Call Trace:
[20116.371473] dump_stack+0x5c/0x80
[20116.371476] handle_userfault.cold.37+0x1b/0x22
[20116.371479] ? remove_wait_queue+0x20/0x60
[20116.371481] ? poll_freewait+0x45/0xa0
[20116.371483] ? do_sys_poll+0x31c/0x520
[20116.371485] ? radix_tree_lookup_slot+0x1e/0x50
[20116.371488] shmem_getpage_gfp+0xce7/0xe50
[20116.371491] ? page_add_file_rmap+0x1a/0x2c0
[20116.371493] shmem_fault+0x78/0x1e0
[20116.371495] ? filemap_map_pages+0x3a1/0x450
[20116.371498] __do_fault+0x1f/0xc0
[20116.371500] __handle_mm_fault+0xe2e/0x12f0
[20116.371502] handle_mm_fault+0xda/0x200
[20116.371504] __get_user_pages+0x238/0x790
[20116.371506] get_user_pages+0x3e/0x50
[20116.371510] kernel_get_mempolicy+0x40b/0x700
[20116.371512] ? vfs_write+0x170/0x1a0
[20116.371515] __x64_sys_get_mempolicy+0x21/0x30
[20116.371517] do_syscall_64+0x5b/0x160
[20116.371520] entry_SYSCALL_64_after_hwframe+0x44/0xa9The above harmless debug message (not a kernel crash, just a dump_stack()) is shown with CONFIG_DEBUG_VM=y to more quickly identify and improve kernel spots that may have to become "userfaultfd compliant" like this one (without having to run an strace and search for syscall misbehavior). Spots like the above are more closer to a kernel bug for the non-cooperative usages that Mike focuses on, than for for dpdk qemu-cooperative usages that reproduced it, but it's still nicer to get this fixed for dpdk too.
The part of the patch that caused me to think is only the implementation issue of mpol_get, but it looks like it should work safe no matter the kind of mempolicy structure that is (the default static policy also starts at 1 so it'll go to 2 and back to 1 without crashing everything at 0).
[[email protected]: changelog addition]
http://lkml.kernel.org/r/20180904073718.GA26916@rapoport-lnx
--- mm/mempolicy.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
mm/mempolicy.c +19 -5
@@ -797,16 +797,19 @@ static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes) } } -static int lookup_node (unsigned long addr) +static int lookup_node (struct mm_struct *mm,unsigned long addr) {struct page *p;int err; - err =get_user_pages (addr &PAGE_MASK ,1 ,0 , &p,NULL ); +int locked =1 ; + err =get_user_pages_locked (addr &PAGE_MASK ,1 ,0 , &p, &locked);if (err >=0 ) { err =page_to_nid (p);put_page (p); } +if (locked) +up_read (&mm->mmap_sem);return err; }
@@ -817,7 +820,7 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,int err;struct mm_struct *mm = current->mm;struct vm_area_struct *vma =NULL ; -struct mempolicy *pol = current->mempolicy; +struct mempolicy *pol = current->mempolicy, *pol_refcount =NULL ;if (flags & ~(unsigned long )(MPOL_F_NODE |MPOL_F_ADDR |MPOL_F_MEMS_ALLOWED ))
@@ -857,7 +860,16 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,if (flags &MPOL_F_NODE ) {if (flags &MPOL_F_ADDR ) { - err =lookup_node (addr); +/* +* Take a refcount on the mpol, lookup_node() +* wil drop the mmap_sem, so after calling +* lookup_node() only "pol" remains valid, "vma" +* is stale. +*/ + pol_refcount = pol; + vma =NULL ; +mpol_get (pol); + err =lookup_node (mm, addr);if (err <0 ) goto out; *policy = err;
@@ -892,7 +904,9 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, out:mpol_cond_put (pol);if (vma) -up_read (¤t->mm->mmap_sem); +up_read (&mm->mmap_sem); +if (pol_refcount) +mpol_put (pol_refcount);return err; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 6/45 mm: don't miss the last page because of round-off error
In reply to Sasha LevinFrom: Roman Gushchin <[email protected]>
[ Upstream commit 68600f623d69da428c6163275f97ca126e1a8ec5 ]
I've noticed, that dying memory cgroups are often pinned in memory by a single pagecache page. Even under moderate memory pressure they sometimes stayed in such state for a long time. That looked strange.
My investigation showed that the problem is caused by applying the LRU pressure balancing math:
scan = div64_u64(scan * fraction[lru], denominator),
where
denominator = fraction[anon] + fraction[file] + 1.
Because fraction[lru] is always less than denominator, if the initial scan size is 1, the result is always 0.
This means the last page is not scanned and has
no chances to be reclaimed.
Fix this by rounding up the result of the division.
In practice this change significantly improves the speed of dying cgroups reclaim.
--- include/linux/math64.h | 3 +++ mm/vmscan.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-)
include/linux/math64.h +3 -0
@@ -281,4 +281,7 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) }#endif /* mul_u64_u32_div */ +#define DIV64_U64_ROUND_UP (ll, d) \ + ({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); }) +#endif /* _LINUX_MATH64_H */
mm/vmscan.c +4 -2
@@ -2298,9 +2298,11 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,/* * Scan types proportional to swappiness and * their relative recent reclaim efficiency. +* Make sure we don't miss the last page +* because of a round-off error. */ - scan =div64_u64 (scan * fraction[file], - denominator); + scan =DIV64_U64_ROUND_UP (scan * fraction[file], + denominator);break ;case SCAN_FILE :case SCAN_ANON :
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 7/45 mm: don't warn about large allocations for slab
In reply to Sasha LevinFrom: Dmitry Vyukov <[email protected]>
[ Upstream commit 61448479a9f2c954cde0cfe778cb6bec5d0a748d ]
Slub does not call kmalloc_slab() for sizes > KMALLOC_MAX_CACHE_SIZE, instead it falls back to kmalloc_large().
For slab KMALLOC_MAX_CACHE_SIZE == KMALLOC_MAX_SIZE and it calls kmalloc_slab() for all allocations relying on NULL return value for over-sized allocations.
This inconsistency leads to unwanted warnings from kmalloc_slab() for over-sized allocations for slab. Returning NULL for failed allocations is the expected behavior.
Make slub and slab code consistent by checking size > KMALLOC_MAX_CACHE_SIZE in slab before calling kmalloc_slab().
While we are here also fix the check in kmalloc_slab(). We should check against KMALLOC_MAX_CACHE_SIZE rather than KMALLOC_MAX_SIZE. It all kinda worked because for slab the constants are the same, and slub always checks the size against KMALLOC_MAX_CACHE_SIZE before kmalloc_slab(). But if we get there with size > KMALLOC_MAX_CACHE_SIZE anyhow bad things will happen. For example, in case of a newly introduced bug in slub code.
Also move the check in kmalloc_slab() from function entry to the size > 192 case. This partially compensates for the additional check in slab code and makes slub code a bit faster (at least theoretically).
Also drop __GFP_NOWARN in the warning check. This warning means a bug in slab code itself, user-passed flags have nothing to do with it.
Nothing of this affects slob.
--- mm/slab.c | 4 ++++ mm/slab_common.c | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-)
mm/slab.c +4 -0
@@ -3675,6 +3675,8 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)struct kmem_cache *cachep;void *ret; +if (unlikely (size >KMALLOC_MAX_CACHE_SIZE )) +return NULL ; cachep =kmalloc_slab (size, flags);if (unlikely (ZERO_OR_NULL_PTR (cachep)))return cachep;
@@ -3710,6 +3712,8 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,struct kmem_cache *cachep;void *ret; +if (unlikely (size >KMALLOC_MAX_CACHE_SIZE )) +return NULL ; cachep =kmalloc_slab (size, flags);if (unlikely (ZERO_OR_NULL_PTR (cachep)))return cachep;
mm/slab_common.c +6 -6
@@ -1027,18 +1027,18 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags) {unsigned int index; -if (unlikely (size >KMALLOC_MAX_SIZE )) { -WARN_ON_ONCE (!(flags & __GFP_NOWARN)); -return NULL ; - } -if (size <=192 ) {if (!size)return ZERO_SIZE_PTR ; index = size_index[size_index_elem (size)]; - }else + }else { +if (unlikely (size >KMALLOC_MAX_CACHE_SIZE )) { +WARN_ON (1 ); +return NULL ; + } index =fls (size -1 ); + }#ifdef CONFIG_ZONE_DMA if (unlikely ((flags &GFP_DMA )))
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 8/45 powerpc/traps: restore recoverability of machine_check interrupts
In reply to Sasha LevinFrom: Christophe Leroy <[email protected]>
[ Upstream commit daf00ae71dad8aa05965713c62558aeebf2df48e ]
commit b96672dd840f ("powerpc: Machine check interrupt is a non- maskable interrupt") added a call to nmi_enter() at the beginning of machine check restart exception handler. Due to that, in_interrupt() always returns true regardless of the state before entering the exception, and die() panics even when the system was not already in interrupt.
This patch calls nmi_exit() before calling die() in order to restore the interrupt state we had before calling nmi_enter()
--- arch/powerpc/kernel/traps.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
arch/powerpc/kernel/traps.c +7 -2
@@ -736,12 +736,17 @@ void machine_check_exception(struct pt_regs *regs)if (check_io_access (regs)) goto bail; -die ("Machine check" , regs,SIGBUS ); -/* Must die if the interrupt is not recoverable */ if (!(regs->msr &MSR_RI ))nmi_panic (regs,"Unrecoverable Machine check" ); +if (!nested) +nmi_exit (); + +die ("Machine check" , regs,SIGBUS ); + +return ; + bail:if (!nested)nmi_exit ();
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 9/45 powerpc/64/module: REL32 relocation range check
In reply to Sasha LevinFrom: Nicholas Piggin <[email protected]>
[ Upstream commit b851ba02a6f3075f0f99c60c4bc30a4af80cf428 ]
The recent module relocation overflow crash demonstrated that we have no range checking on REL32 relative relocations. This patch implements a basic check, the same kernel that previously oopsed and rebooted now continues with some of these errors when loading the module:
module_64: x_tables: REL32 527703503449812 out of range!
Possibly other relocations (ADDR32, REL16, TOC16, etc.) should also have overflow checks.
--- arch/powerpc/kernel/module_64.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
arch/powerpc/kernel/module_64.c +8 -1
@@ -685,7 +685,14 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,case R_PPC64_REL32 :/* 32 bits relative (used by relative exception tables) */ - *(u32 *)location = value - (unsigned long )location; +/* Convert value to relative */ + value -= (unsigned long )location; +if (value +0x80000000 >0xffffffff ) { +pr_err ("%s: REL32 %li out of range!\n" , + me->name, (long int )value); +return -ENOEXEC ; + } + *(u32 *)location = value;break ;case R_PPC64_TOCSAVE :
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 10/45 powerpc/mm: Fix page table dump to work on Radix
In reply to Sasha LevinFrom: Michael Ellerman <[email protected]>
[ Upstream commit 0d923962ab69c27cca664a2d535e90ef655110ca ]
When we're running on Book3S with the Radix MMU enabled the page table dump currently prints the wrong addresses because it uses the wrong start address.
Fix it to use PAGE_OFFSET rather than KERN_VIRT_START.
--- arch/powerpc/mm/dump_linuxpagetables.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/powerpc/mm/dump_linuxpagetables.c +9 -3
@@ -418,12 +418,13 @@ static void walk_pagetables(struct pg_state *st)unsigned int i;unsigned long addr; + addr = st->start_address; +/* * Traverse the linux pagetable structure and dump pages that are in * the hash pagetable. */ -for (i =0 ; i <PTRS_PER_PGD ; i++, pgd++) { - addr =KERN_VIRT_START + i *PGDIR_SIZE ; +for (i =0 ; i <PTRS_PER_PGD ; i++, pgd++, addr +=PGDIR_SIZE ) {if (!pgd_none (*pgd) && !pgd_huge (*pgd))/* pgd exists */ walk_pud (st, pgd, addr);
@@ -472,9 +473,14 @@ static int ptdump_show(struct seq_file *m, void *v) {struct pg_state st = { .seq = m, - .start_address =KERN_VIRT_START , .marker = address_markers, }; + +if (radix_enabled ()) + st.start_address =PAGE_OFFSET ; +else + st.start_address =KERN_VIRT_START ; +/* Traverse kernel page tables */ walk_pagetables (&st);note_page (&st,0 ,0 ,0 );
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 11/45 powerpc/mm: fix always true/false warning in slice.c
In reply to Sasha LevinFrom: Christophe Leroy <[email protected]>
[ Upstream commit 37e9c674e7e6f445e12cb1151017bd4bacdd1e2d ]
This patch fixes the following warnings (obtained with make W=1).
arch/powerpc/mm/slice.c: In function 'slice_range_to_mask':arch/powerpc/mm/slice.c:73:12: error: comparison is always true due to limited range of data type [-Werror=type-limits]
if (start < SLICE_LOW_TOP) {
^
arch/powerpc/mm/slice.c:81:20: error: comparison is always false due to limited range of data type [-Werror=type-limits]
if ((start + len) > SLICE_LOW_TOP) {
^
arch/powerpc/mm/slice.c: In function 'slice_mask_for_free':
arch/powerpc/mm/slice.c:136:17: error: comparison is always true due to limited range of data type [-Werror=type-limits]
if (high_limit <= SLICE_LOW_TOP)
^
arch/powerpc/mm/slice.c: In function 'slice_check_range_fits':
arch/powerpc/mm/slice.c:185:12: error: comparison is always true due to limited range of data type [-Werror=type-limits]
if (start < SLICE_LOW_TOP) {
^
arch/powerpc/mm/slice.c:195:39: error: comparison is always false due to limited range of data type [-Werror=type-limits]
if (SLICE_NUM_HIGH && ((start + len) > SLICE_LOW_TOP)) {
^
arch/powerpc/mm/slice.c: In function 'slice_scan_available':
arch/powerpc/mm/slice.c:306:11: error: comparison is always true due to limited range of data type [-Werror=type-limits]
if (addr < SLICE_LOW_TOP) {
^
arch/powerpc/mm/slice.c: In function 'get_slice_psize':
arch/powerpc/mm/slice.c:709:11: error: comparison is always true due to limited range of data type [-Werror=type-limits]
if (addr < SLICE_LOW_TOP) {
^--- arch/powerpc/mm/slice.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
arch/powerpc/mm/slice.c +14 -7
@@ -61,6 +61,13 @@ static void slice_print_mask(const char *label, const struct slice_mask *mask) {#endif +static inline bool slice_addr_is_low (unsigned long addr) +{ +u64 tmp = (u64 )addr; + +return tmp <SLICE_LOW_TOP ; +} +static void slice_range_to_mask (unsigned long start,unsigned long len,struct slice_mask *ret) {
@@ -70,7 +77,7 @@ static void slice_range_to_mask(unsigned long start, unsigned long len,if (SLICE_NUM_HIGH )bitmap_zero (ret->high_slices,SLICE_NUM_HIGH ); -if (start <SLICE_LOW_TOP ) { +if (slice_addr_is_low (start)) {unsigned long mend =min (end, (unsigned long )(SLICE_LOW_TOP -1 ));
@@ -78,7 +85,7 @@ static void slice_range_to_mask(unsigned long start, unsigned long len, - (1u <<GET_LOW_SLICE_INDEX (start)); } -if ((start + len) >SLICE_LOW_TOP ) { +if (SLICE_NUM_HIGH && !slice_addr_is_low (end)) {unsigned long start_index =GET_HIGH_SLICE_INDEX (start);unsigned long align_end =ALIGN (end, (1UL <<SLICE_HIGH_SHIFT ));unsigned long count =GET_HIGH_SLICE_INDEX (align_end) - start_index;
@@ -133,7 +140,7 @@ static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret,if (!slice_low_has_vma (mm, i)) ret->low_slices |=1u << i; -if (high_limit <=SLICE_LOW_TOP ) +if (slice_addr_is_low (high_limit -1 ))return ;for (i =0 ; i <GET_HIGH_SLICE_INDEX (high_limit); i++)
@@ -182,7 +189,7 @@ static bool slice_check_range_fits(struct mm_struct *mm,unsigned long end = start + len -1 ;u64 low_slices =0 ; -if (start <SLICE_LOW_TOP ) { +if (slice_addr_is_low (start)) {unsigned long mend =min (end, (unsigned long )(SLICE_LOW_TOP -1 ));
@@ -192,7 +199,7 @@ static bool slice_check_range_fits(struct mm_struct *mm,if ((low_slices & available->low_slices) != low_slices)return false; -if (SLICE_NUM_HIGH && ((start + len) >SLICE_LOW_TOP )) { +if (SLICE_NUM_HIGH && !slice_addr_is_low (end)) {unsigned long start_index =GET_HIGH_SLICE_INDEX (start);unsigned long align_end =ALIGN (end, (1UL <<SLICE_HIGH_SHIFT ));unsigned long count =GET_HIGH_SLICE_INDEX (align_end) - start_index;
@@ -303,7 +310,7 @@ static bool slice_scan_available(unsigned long addr, int end, unsigned long *boundary_addr) { unsigned long slice; -if (addr <SLICE_LOW_TOP ) { +if (slice_addr_is_low (addr)) { slice =GET_LOW_SLICE_INDEX (addr); *boundary_addr = (slice + end) <<SLICE_LOW_SHIFT ;return !!(available->low_slices & (1u << slice));
@@ -706,7 +713,7 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)VM_BUG_ON (radix_enabled ()); -if (addr <SLICE_LOW_TOP ) { +if (slice_addr_is_low (addr)) { psizes = mm->context.low_slices_psize; index =GET_LOW_SLICE_INDEX (addr); }else {
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 12/45 drm/amd/display: fix bug of accessing invalid memory
In reply to Sasha LevinFrom: Su Sung Chung <[email protected]>
[ Upstream commit 43c3ff27a47d83d153c4adc088243ba594582bf5 ]
[Why]
A loop inside of build_evenly_distributed_points function that traverse through the array of points become an infinite loop when m_GammaUpdates does not get assigned to any value.
[How]
In DMColor, clear m_gammaIsValid bit just before writting all Zeromem for m_GammaUpdates, to prevent calling build_evenly_distributed_points before m_GammaUpdates gets assigned to some value.
--- drivers/gpu/drm/amd/display/modules/color/color_gamma.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/modules/color/color_gamma.c +6 -2
@@ -968,10 +968,14 @@ static void build_evenly_distributed_points( struct dividers dividers) {struct gamma_pixel *p = points; -struct gamma_pixel *p_last = p + numberof_points -1 ; +struct gamma_pixel *p_last;uint32_t i =0 ; +// This function should not gets called with 0 as a parameter +ASSERT (numberof_points >0 ); + p_last = p + numberof_points -1 ; + do { struct fixed31_32 value = dc_fixpt_from_fraction(i, numberof_points - 1);
@@ -982,7 +986,7 @@ static void build_evenly_distributed_points( ++p; ++i; - }while (i != numberof_points); + }while (i < numberof_points); p->r =dc_fixpt_div (p_last->r, dividers.divider1); p->g =dc_fixpt_div (p_last->g, dividers.divider1);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 13/45 Input: wm97xx-ts - fix exit path
In reply to Sasha LevinFrom: Randy Dunlap <[email protected]>
[ Upstream commit a3f7c3fcf60868c1e90671df5d0cf9be5900a09b ]
Loading then unloading wm97xx-ts.ko when CONFIG_AC97_BUS=m causes a WARNING: from drivers/base/driver.c:
Unexpected driver unregister!
WARNING: CPU: 0 PID: 1709 at ../drivers/base/driver.c:193 driver_unregister+0x30/0x40
Fix this by only calling driver_unregister() with the same condition that driver_register() is called.
--- drivers/input/touchscreen/wm97xx-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/input/touchscreen/wm97xx-core.c +2 -1
@@ -929,7 +929,8 @@ static int __init wm97xx_init(void) static void __exit wm97xx_exit(void) { -driver_unregister (&wm97xx_driver); +if (IS_BUILTIN (CONFIG_AC97_BUS )) +driver_unregister (&wm97xx_driver);platform_driver_unregister (&wm97xx_mfd_driver); }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 14/45 powerpc/Makefile: Fix PPC_BOOK3S_64 ASFLAGS
In reply to Sasha LevinFrom: Joel Stanley <[email protected]>
[ Upstream commit 960e30029863db95ec79a71009272d4661db5991 ]
Ever since commit 15a3204d24a3 ("powerpc/64s: Set assembler machine type to POWER4") we force -mpower4 to be passed to the assembler irrespective of the CFLAGS used (for Book3s 64).
When building a powerpc64 kernel with clang, clang will not add -many to the assembler flags, so any instructions that the compiler has generated that are not available on power4 will cause an error:
/usr/bin/as -a64 -mppc64 -mlittle-endian -mpower8 \ -I ./arch/powerpc/include -I ./arch/powerpc/include/generated \ -I ./include -I ./arch/powerpc/include/uapi \ -I ./arch/powerpc/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi -I arch/powerpc -I arch/powerpc \ -maltivec -mpower4 -o init/do_mounts.o /tmp/do_mounts-3b0a3d.s /tmp/do_mounts-51ce54.s:748: Error: unrecognized opcode: `isel'
GCC does include -many, so the GCC driven gas call will succeed:
as -v -I ./arch/powerpc/include -I ./arch/powerpc/include/generated -I ./include -I ./arch/powerpc/include/uapi
-I ./arch/powerpc/include/generated/uapi -I ./include/uapi -I ./include/generated/uapi -I arch/powerpc -I arch/powerpc
-a64 -mpower8 -many -mlittle -maltivec -mpower4 -o init/do_mounts.o
Note that isel is power7 and above for IBM CPUs. GCC only generates it for Power9 and above, but the above test was run against the clang generated assembly.
Peter Bergner explains:
When using -many -mpower4, gas will first try and find a matching power4 mnemonic and failing that, it will then allow any valid mnemonic that gas knows about. GCC's use of -many predates me though.
IIRC, Alan looked at trying to remove it, but I forget why he didn't. Could be either a gcc or gas issue at the time. I'm not sure whether issue still exists or not. He and I have modified how gas works internally a fair amount since he tried removing gcc use of -many.
I will also note that when using -many, gas will choose the first mnemonic that matches in the mnemonic table and we have (mostly) sorted the table so that server mnemonics show up earlier in the table than other mnemonics, so they'll be seen/chosen first.
By explicitly setting -many we can build with Clang and GCC while retaining the -mpower4 option.
--- arch/powerpc/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/powerpc/Makefile +5 -1
@@ -244,7 +244,11 @@ cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) cpu-as-$(CONFIG_E200) += -Wa,-me200 cpu-as-$(CONFIG_E500) += -Wa,-me500 -cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4 + +# When using '-many -mpower4' gas will first try and find a matching power4 +# mnemonic and failing that it will allow any valid mnemonic that GAS knows +# about. GCC will pass -many to GAS when assembling, clang does not. +cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4 -Wa,-many cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc) KBUILD_AFLAGS += $(cpu-as-y)
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 15/45 powerpc/eeh: Fix possible null deref in eeh_dump_dev_log()
In reply to Sasha LevinFrom: Sam Bobroff <[email protected]>
[ Upstream commit f9bc28aedfb5bbd572d2d365f3095c1becd7209b ]
If an error occurs during an unplug operation, it's possible for eeh_dump_dev_log() to be called when edev->pdn is null, which currently leads to dereferencing a null pointer.
Handle this by skipping the error log for those devices.
--- arch/powerpc/kernel/eeh.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/powerpc/kernel/eeh.c +5 -0
@@ -169,6 +169,11 @@ static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len)int n =0 , l =0 ;char buffer[128 ]; +if (!pdn) { +pr_warn ("EEH: Note: No error log for absent device.\n" ); +return 0 ; + } + n +=scnprintf (buf+n, len-n,"%04x:%02x:%02x.%01x\n" , pdn->phb->global_number, pdn->busno,PCI_SLOT (pdn->devfn),PCI_FUNC (pdn->devfn));
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 16/45 tty: check name length in tty_find_polling_driver()
In reply to Sasha LevinFrom: Miles Chen <[email protected]>
[ Upstream commit 33a1a7be198657c8ca26ad406c4d2a89b7162bcc ]
The issue is found by a fuzzing test.
If tty_find_polling_driver() recevies an incorrect input such as ',,' or '0b', the len becomes 0 and strncmp() always return 0. In this case, a null p->ops->poll_init() is called and it causes a kernel panic.
Fix this by checking name length against zero in tty_find_polling_driver().
$echo ,, > /sys/module/kgdboc/parameters/kgdboc
[ 20.804451] WARNING: CPU: 1 PID: 104 at drivers/tty/serial/serial_core.c:457 uart_get_baud_rate+0xe8/0x190 [ 20.804917] Modules linked in: [ 20.805317] CPU: 1 PID: 104 Comm: sh Not tainted 4.19.0-rc7ajb #8 [ 20.805469] Hardware name: linux,dummy-virt (DT) [ 20.805732] pstate: 20000005 (nzCv daif -PAN -UAO) [ 20.805895] pc : uart_get_baud_rate+0xe8/0x190 [ 20.806042] lr : uart_get_baud_rate+0xc0/0x190 [ 20.806476] sp : ffffffc06acff940 [ 20.806676] x29: ffffffc06acff940 x28: 0000000000002580 [ 20.806977] x27: 0000000000009600 x26: 0000000000009600 [ 20.807231] x25: ffffffc06acffad0 x24: 00000000ffffeff0 [ 20.807576] x23: 0000000000000001 x22: 0000000000000000 [ 20.807807] x21: 0000000000000001 x20: 0000000000000000 [ 20.808049] x19: ffffffc06acffac8 x18: 0000000000000000 [ 20.808277] x17: 0000000000000000 x16: 0000000000000000 [ 20.808520] x15: ffffffffffffffff x14: ffffffff00000000 [ 20.808757] x13: ffffffffffffffff x12: 0000000000000001 [ 20.809011] x11: 0101010101010101 x10: ffffff880d59ff5f [ 20.809292] x9 : ffffff880d59ff5e x8 : ffffffc06acffaf3 [ 20.809549] x7 : 0000000000000000 x6 : ffffff880d59ff5f [ 20.809803] x5 : 0000000080008001 x4 : 0000000000000003 [ 20.810056] x3 : ffffff900853e6b4 x2 : dfffff9000000000 [ 20.810693] x1 : ffffffc06acffad0 x0 : 0000000000000cb0 [ 20.811005] Call trace: [ 20.811214] uart_get_baud_rate+0xe8/0x190 [ 20.811479] serial8250_do_set_termios+0xe0/0x6f4 [ 20.811719] serial8250_set_termios+0x48/0x54 [ 20.811928] uart_set_options+0x138/0x1bc [ 20.812129] uart_poll_init+0x114/0x16c [ 20.812330] tty_find_polling_driver+0x158/0x200 [ 20.812545] configure_kgdboc+0xbc/0x1bc [ 20.812745] param_set_kgdboc_var+0xb8/0x150 [ 20.812960] param_attr_store+0xbc/0x150 [ 20.813160] module_attr_store+0x40/0x58 [ 20.813364] sysfs_kf_write+0x8c/0xa8 [ 20.813563] kernfs_fop_write+0x154/0x290 [ 20.813764] vfs_write+0xf0/0x278 [ 20.813951] __arm64_sys_write+0x84/0xf4 [ 20.814400] el0_svc_common+0xf4/0x1dc [ 20.814616] el0_svc_handler+0x98/0xbc [ 20.814804] el0_svc+0x8/0xc [ 20.822005] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 20.826913] Mem abort info: [ 20.827103] ESR = 0x84000006 [ 20.827352] Exception class = IABT (current EL), IL = 16 bits [ 20.827655] SET = 0, FnV = 0 [ 20.827855] EA = 0, S1PTW = 0 [ 20.828135] user pgtable: 4k pages, 39-bit VAs, pgdp = (____ptrval____) [ 20.828484] [0000000000000000] pgd=00000000aadee003, pud=00000000aadee003, pmd=0000000000000000 [ 20.829195] Internal error: Oops: 84000006 [#1] SMP [ 20.829564] Modules linked in: [ 20.829890] CPU: 1 PID: 104 Comm: sh Tainted: G W 4.19.0-rc7ajb #8 [ 20.830545] Hardware name: linux,dummy-virt (DT) [ 20.830829] pstate: 60000085 (nZCv daIf -PAN -UAO) [ 20.831174] pc : (null) [ 20.831457] lr : serial8250_do_set_termios+0x358/0x6f4 [ 20.831727] sp : ffffffc06acff9b0 [ 20.831936] x29: ffffffc06acff9b0 x28: ffffff9008d7c000 [ 20.832267] x27: ffffff900969e16f x26: 0000000000000000 [ 20.832589] x25: ffffff900969dfb0 x24: 0000000000000000 [ 20.832906] x23: ffffffc06acffad0 x22: ffffff900969e160 [ 20.833232] x21: 0000000000000000 x20: ffffffc06acffac8 [ 20.833559] x19: ffffff900969df90 x18: 0000000000000000 [ 20.833878] x17: 0000000000000000 x16: 0000000000000000 [ 20.834491] x15: ffffffffffffffff x14: ffffffff00000000 [ 20.834821] x13: ffffffffffffffff x12: 0000000000000001 [ 20.835143] x11: 0101010101010101 x10: ffffff880d59ff5f [ 20.835467] x9 : ffffff880d59ff5e x8 : ffffffc06acffaf3 [ 20.835790] x7 : 0000000000000000 x6 : ffffff880d59ff5f [ 20.836111] x5 : c06419717c314100 x4 : 0000000000000007 [ 20.836419] x3 : 0000000000000000 x2 : 0000000000000000 [ 20.836732] x1 : 0000000000000001 x0 : ffffff900969df90 [ 20.837100] Process sh (pid: 104, stack limit = 0x(____ptrval____)) [ 20.837396] Call trace: [ 20.837566] (null) [ 20.837816] serial8250_set_termios+0x48/0x54 [ 20.838089] uart_set_options+0x138/0x1bc [ 20.838570] uart_poll_init+0x114/0x16c [ 20.838834] tty_find_polling_driver+0x158/0x200 [ 20.839119] configure_kgdboc+0xbc/0x1bc [ 20.839380] param_set_kgdboc_var+0xb8/0x150 [ 20.839658] param_attr_store+0xbc/0x150 [ 20.839920] module_attr_store+0x40/0x58 [ 20.840183] sysfs_kf_write+0x8c/0xa8 [ 20.840183] sysfs_kf_write+0x8c/0xa8 [ 20.840440] kernfs_fop_write+0x154/0x290 [ 20.840702] vfs_write+0xf0/0x278 [ 20.840942] __arm64_sys_write+0x84/0xf4 [ 20.841209] el0_svc_common+0xf4/0x1dc [ 20.841471] el0_svc_handler+0x98/0xbc [ 20.841713] el0_svc+0x8/0xc [ 20.842057] Code: bad PC value [ 20.842764] ---[ end trace a8835d7de79aaadf ]--- [ 20.843134] Kernel panic - not syncing: Fatal exception [ 20.843515] SMP: stopping secondary CPUs [ 20.844289] Kernel Offset: disabled [ 20.844634] CPU features: 0x0,21806002 [ 20.844857] Memory Limit: none [ 20.845172] ---[ end Kernel panic - not syncing: Fatal exception ]---
--- drivers/tty/tty_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/tty_io.c +1 -1
@@ -408,7 +408,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)mutex_lock (&tty_mutex);/* Search through the tty devices to look for a match */ list_for_each_entry (p, &tty_drivers, tty_drivers) { -if (strncmp (name, p->name, len) !=0 ) +if (!len ||strncmp (name, p->name, len) !=0 )continue ; stp = str;if (*stp ==',' )
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 17/45 tracing/kprobes: Check the probe on unloaded module correctly
In reply to Sasha LevinFrom: Masami Hiramatsu <[email protected]>
[ Upstream commit 59158ec4aef7d44be51a6f3e7e17fc64c32604eb ]
Current kprobe event doesn't checks correctly whether the given event is on unloaded module or not. It just checks the event has ":" in the name.
That is not enough because if we define a probe on non-exist symbol on loaded module, it allows to define that (with warning message)
To ensure it correctly, this searches the module name on loaded module list and only if there is not, it allows to define it. (this event will be available when the target module is loaded)
--- kernel/trace/trace_kprobe.c | 39 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-)
kernel/trace/trace_kprobe.c +26 -13
@@ -71,9 +71,23 @@ static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk,return strncmp (mod->name, name, len) ==0 && name[len] ==':' ; } -static nokprobe_inline bool trace_kprobe_is_on_module(struct trace_kprobe *tk) +static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk) { -return !!strchr (trace_kprobe_symbol (tk),':' ); +char *p; +bool ret; + +if (!tk->symbol) +return false; + p =strchr (tk->symbol,':' ); +if (!p) +return true; + *p ='\0' ; +mutex_lock (&module_mutex); + ret = !!find_module (tk->symbol); +mutex_unlock (&module_mutex); + *p =':' ; + +return ret; }static nokprobe_inline unsigned long trace_kprobe_nhit (struct trace_kprobe *tk)
@@ -520,19 +534,13 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)else ret =register_kprobe (&tk->rp.kp); -if (ret ==0 ) +if (ret ==0 ) { tk->tp.flags |=TP_FLAG_REGISTERED ; -else { -if (ret == -ENOENT &&trace_kprobe_is_on_module (tk)) { -pr_warn ("This probe might be able to register after target module is loaded. Continue.\n" ); - ret =0 ; - }else if (ret == -EILSEQ ) { -pr_warn ("Probing address(0x%p) is not an instruction boundary.\n" , - tk->rp.kp.addr); - ret = -EINVAL ; - } + }else if (ret == -EILSEQ ) { +pr_warn ("Probing address(0x%p) is not an instruction boundary.\n" , + tk->rp.kp.addr); + ret = -EINVAL ; } -return ret; }
@@ -595,6 +603,11 @@ static int register_trace_kprobe(struct trace_kprobe *tk)/* Register k*probe */ ret =__register_trace_kprobe (tk); +if (ret == -ENOENT && !trace_kprobe_module_exist (tk)) { +pr_warn ("This probe might be able to register after target module is loaded. Continue.\n" ); + ret =0 ; + } +if (ret <0 )unregister_kprobe_event (tk);else
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 18/45 drm/amdgpu/powerplay: fix missing break in switch statements
In reply to Sasha LevinFrom: Colin Ian King <[email protected]>
[ Upstream commit 14b284832e7dea6f54f0adfd7bed105548b94e57 ]
There are several switch statements that are missing break statements. Add missing breaks to handle any fall-throughs corner cases.
Detected by CoverityScan, CID#1457175 ("Missing break in switch")
--- drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 2 ++ drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | 2 ++ drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c | 2 ++ drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c | 2 ++ drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c | 2 ++ 5 files changed, 10 insertions(+)
drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +2 -0
@@ -2303,11 +2303,13 @@ static uint32_t ci_get_offsetof(uint32_t type, uint32_t member)case DRAM_LOG_BUFF_SIZE :return offsetof(SMU7_SoftRegisters , DRAM_LOG_BUFF_SIZE); } +break ;case SMU_Discrete_DpmTable:switch (member) {case LowSclkInterruptThreshold:return offsetof(SMU7_Discrete_DpmTable , LowSclkInterruptT); } +break ; }pr_debug ("can't get the offset of type %x member %x\n" , type, member);return 0 ;
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +2 -0
@@ -2372,6 +2372,7 @@ static uint32_t fiji_get_offsetof(uint32_t type, uint32_t member)case DRAM_LOG_BUFF_SIZE :return offsetof(SMU73_SoftRegisters , DRAM_LOG_BUFF_SIZE); } +break ;case SMU_Discrete_DpmTable:switch (member) {case UvdBootLevel:
@@ -2383,6 +2384,7 @@ static uint32_t fiji_get_offsetof(uint32_t type, uint32_t member)case LowSclkInterruptThreshold:return offsetof(SMU73_Discrete_DpmTable , LowSclkInterruptThreshold); } +break ; }pr_warn ("can't get the offset of type %x member %x\n" , type, member);return 0 ;
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +2 -0
@@ -2246,11 +2246,13 @@ static uint32_t iceland_get_offsetof(uint32_t type, uint32_t member)case DRAM_LOG_BUFF_SIZE :return offsetof(SMU71_SoftRegisters , DRAM_LOG_BUFF_SIZE); } +break ;case SMU_Discrete_DpmTable:switch (member) {case LowSclkInterruptThreshold:return offsetof(SMU71_Discrete_DpmTable , LowSclkInterruptThreshold); } +break ; }pr_warn ("can't get the offset of type %x member %x\n" , type, member);return 0 ;
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +2 -0
@@ -2667,6 +2667,7 @@ static uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)case DRAM_LOG_BUFF_SIZE :return offsetof(SMU72_SoftRegisters , DRAM_LOG_BUFF_SIZE); } +break ;case SMU_Discrete_DpmTable:switch (member) {case UvdBootLevel:
@@ -2678,6 +2679,7 @@ static uint32_t tonga_get_offsetof(uint32_t type, uint32_t member)case LowSclkInterruptThreshold:return offsetof(SMU72_Discrete_DpmTable , LowSclkInterruptThreshold); } +break ; }pr_warn ("can't get the offset of type %x member %x\n" , type, member);return 0 ;
drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +2 -0
@@ -2267,6 +2267,7 @@ static uint32_t vegam_get_offsetof(uint32_t type, uint32_t member)case DRAM_LOG_BUFF_SIZE :return offsetof(SMU75_SoftRegisters , DRAM_LOG_BUFF_SIZE); } +break ;case SMU_Discrete_DpmTable:switch (member) {case UvdBootLevel:
@@ -2278,6 +2279,7 @@ static uint32_t vegam_get_offsetof(uint32_t type, uint32_t member)case LowSclkInterruptThreshold:return offsetof(SMU75_Discrete_DpmTable , LowSclkInterruptThreshold); } +break ; }pr_warn ("can't get the offset of type %x member %x\n" , type, member);return 0 ;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 19/45 ARM: imx_v6_v7_defconfig: Select CONFIG_TMPFS_POSIX_ACL
In reply to Sasha LevinFrom: Fabio Estevam <[email protected]>
[ Upstream commit 35d3cbe84544da74e39e1cec01374092467e3119 ]
Andreas Müller reports:
"Fixes:
| Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[220]: Failed to apply ACL on /dev/v4l-subdev0: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[224]: Failed to apply ACL on /dev/v4l-subdev1: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[215]: Failed to apply ACL on /dev/v4l-subdev10: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[228]: Failed to apply ACL on /dev/v4l-subdev2: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[232]: Failed to apply ACL on /dev/v4l-subdev5: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[217]: Failed to apply ACL on /dev/v4l-subdev11: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[214]: Failed to apply ACL on /dev/dri/card1: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[216]: Failed to apply ACL on /dev/v4l-subdev8: Operation not supported | Sep 04 09:05:10 imx6qdl-variscite-som systemd-udevd[226]: Failed to apply ACL on /dev/v4l-subdev9: Operation not supported
and nasty follow-ups: Starting weston from sddm as unpriviledged user fails with some hints on missing access rights."
Select the CONFIG_TMPFS_POSIX_ACL option to fix these issues.
--- arch/arm/configs/imx_v6_v7_defconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/configs/imx_v6_v7_defconfig +1 -0
@@ -406,6 +406,7 @@ CONFIG_ZISOFS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 20/45 powerpc/nohash: fix undefined behaviour when testing page size support
In reply to Sasha LevinFrom: Daniel Axtens <[email protected]>
[ Upstream commit f5e284803a7206d43e26f9ffcae5de9626d95e37 ]
When enumerating page size definitions to check hardware support, we construct a constant which is (1U << (def->shift - 10)).
However, the array of page size definitions is only initalised for various MMU_PAGE_* constants, so it contains a number of 0-initialised elements with def->shift == 0. This means we end up shifting by a very large number, which gives the following UBSan splat:
================================================================================
UBSAN: Undefined behaviour in /home/dja/dev/linux/linux/arch/powerpc/mm/tlb_nohash.c:506:21 shift exponent 4294967286 is too large for 32-bit type 'unsigned int' CPU: 0 PID: 0 Comm: swapper Not tainted 4.19.0-rc3-00045-ga604f927b012-dirty #6 Call Trace: [c00000000101bc20] [c000000000a13d54] .dump_stack+0xa8/0xec (unreliable) [c00000000101bcb0] [c0000000004f20a8] .ubsan_epilogue+0x18/0x64 [c00000000101bd30] [c0000000004f2b10] .__ubsan_handle_shift_out_of_bounds+0x110/0x1a4 [c00000000101be20] [c000000000d21760] .early_init_mmu+0x1b4/0x5a0 [c00000000101bf10] [c000000000d1ba28] .early_setup+0x100/0x130 [c00000000101bf90] [c000000000000528] start_here_multiplatform+0x68/0x80 ================================================================================
Fix this by first checking if the element exists (shift != 0) before constructing the constant.
--- arch/powerpc/mm/tlb_nohash.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/mm/tlb_nohash.c +3 -0
@@ -503,6 +503,9 @@ static void setup_page_sizes(void)for (psize =0 ; psize <MMU_PAGE_COUNT ; ++psize) {struct mmu_psize_def *def = &mmu_psize_defs[psize]; +if (!def->shift) +continue ; +if (tlb1ps & (1U << (def->shift -10 ))) { def->flags |=MMU_PAGE_SIZE_DIRECT ;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 21/45 powerpc/mm: Don't report hugepage tables as memory leaks when using kmemleak
In reply to Sasha LevinFrom: Christophe Leroy <[email protected]>
[ Upstream commit 803d690e68f0c5230183f1a42c7d50a41d16e380 ]
When a process allocates a hugepage, the following leak is reported by kmemleak. This is a false positive which is due to the pointer to the table being stored in the PGD as physical memory address and not virtual memory pointer.
unreferenced object 0xc30f8200 (size 512):
comm "mmap", pid 374, jiffies 4872494 (age 627.630s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<e32b68da>] huge_pte_alloc+0xdc/0x1f8
[<9e0df1e1>] hugetlb_fault+0x560/0x8f8
[<7938ec6c>] follow_hugetlb_page+0x14c/0x44c
[<afbdb405>] __get_user_pages+0x1c4/0x3dc
[<b8fd7cd9>] __mm_populate+0xac/0x140
[<3215421e>] vm_mmap_pgoff+0xb4/0xb8
[<c148db69>] ksys_mmap_pgoff+0xcc/0x1fc
[<4fcd760f>] ret_from_syscall+0x0/0x38See commit a984506c542e2 ("powerpc/mm: Don't report PUDs as memory leaks when using kmemleak") for detailed explanation.
To fix that, this patch tells kmemleak to ignore the allocated hugepage table.
--- arch/powerpc/mm/hugetlbpage.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/mm/hugetlbpage.c +3 -0
@@ -19,6 +19,7 @@#include <linux/moduleparam.h> #include <linux/swap.h> #include <linux/swapops.h> +#include <linux/kmemleak.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/tlb.h>
@@ -112,6 +113,8 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,for (i = i -1 ; i >=0 ; i--, hpdp--) *hpdp =__hugepd (0 );kmem_cache_free (cachep, new); + }else { +kmemleak_ignore (new); }spin_unlock (ptl);return 0 ;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 22/45 watchdog: lantiq: update register names to better match spec
In reply to Sasha LevinFrom: Hauke Mehrtens <[email protected]>
[ Upstream commit 1f59f8aff98f200af7a6882184add7b85f5da741 ]
Some of the names of the bits were confusing to me.
Now the bits share the same prefix as the register they are set on.
The LTQ_WDT_CR_PWL register (bits 26:25) is the pre warning limit and it does not turn anything on. It has 4 possible divers 1/2, 1/4, 1/8 and 1/16, this drivers only uses 1/16.
The LTQ_WDT_CR_CLKDIV register bits(25:24) is only configuring a clock divers and do not turn any thing on too, all possible values are valid dividers.
Using the LTQ_WDT_SR prefix is also wrong these bits are used in the LTQ_WDT_CR registers, SR is the status register which is read only.
This uses GENMASK where it is a mask and it uses shifts when a value is written to some bits.
--- drivers/watchdog/lantiq_wdt.c | 36 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-)
drivers/watchdog/lantiq_wdt.c +19 -17
@@ -13,6 +13,7 @@#include <linux/module.h> #include <linux/fs.h> #include <linux/miscdevice.h> +#include <linux/bitops.h> #include <linux/watchdog.h> #include <linux/of_platform.h> #include <linux/uaccess.h>
@@ -40,18 +41,19 @@* essentially the following two magic passwords need to be written to allow * IO access to the WDT core */ -#define LTQ_WDT_PW1 0x00BE0000 -#define LTQ_WDT_PW2 0x00DC0000 +#define LTQ_WDT_CR_PW1 0x00BE0000 +#define LTQ_WDT_CR_PW2 0x00DC0000 + +#define LTQ_WDT_CR 0x0/* watchdog control register */ +#define LTQ_WDT_CR_GEN BIT(31)/* enable bit */ +/* Pre-warning limit set to 1/16 of max WDT period */ +#define LTQ_WDT_CR_PWL (0x3 << 26) +/* set clock divider to 0x40000 */ +#define LTQ_WDT_CR_CLKDIV (0x3 << 24) +#define LTQ_WDT_CR_PW_MASK GENMASK(23, 16)/* Password field */ +#define LTQ_WDT_CR_MAX_TIMEOUT ((1 << 16) - 1)/* The reload field is 16 bit */ -#define LTQ_WDT_CR 0x0/* watchdog control register */ -#define LTQ_WDT_SR 0x8/* watchdog status register */ - -#define LTQ_WDT_SR_EN (0x1 << 31)/* enable bit */ -#define LTQ_WDT_SR_PWD (0x3 << 26)/* turn on power */ -#define LTQ_WDT_SR_CLKDIV (0x3 << 24)/* turn on clock and set */ -/* divider to 0x40000 */ #define LTQ_WDT_DIVIDER 0x40000 -#define LTQ_MAX_TIMEOUT ((1 << 16) - 1)/* the reload field is 16 bit */ static bool nowayout =WATCHDOG_NOWAYOUT ;
@@ -68,26 +70,26 @@ ltq_wdt_enable(void) {unsigned long int timeout = ltq_wdt_timeout * (ltq_io_region_clk_rate /LTQ_WDT_DIVIDER ) +0x1000 ; -if (timeout >LTQ_MAX_TIMEOUT ) - timeout =LTQ_MAX_TIMEOUT ; +if (timeout >LTQ_WDT_CR_MAX_TIMEOUT ) + timeout =LTQ_WDT_CR_MAX_TIMEOUT ;/* write the first password magic */ -ltq_w32 (LTQ_WDT_PW1 , ltq_wdt_membase +LTQ_WDT_CR ); +ltq_w32 (LTQ_WDT_CR_PW1 , ltq_wdt_membase +LTQ_WDT_CR );/* write the second magic plus the configuration and new timeout */ -ltq_w32 (LTQ_WDT_SR_EN |LTQ_WDT_SR_PWD |LTQ_WDT_SR_CLKDIV | -LTQ_WDT_PW2 | timeout, ltq_wdt_membase +LTQ_WDT_CR ); +ltq_w32 (LTQ_WDT_CR_GEN |LTQ_WDT_CR_PWL |LTQ_WDT_CR_CLKDIV | +LTQ_WDT_CR_PW2 | timeout, ltq_wdt_membase +LTQ_WDT_CR ); }static void ltq_wdt_disable (void ) {/* write the first password magic */ -ltq_w32 (LTQ_WDT_PW1 , ltq_wdt_membase +LTQ_WDT_CR ); +ltq_w32 (LTQ_WDT_CR_PW1 , ltq_wdt_membase +LTQ_WDT_CR );/* * write the second password magic with no config * this turns the watchdog off */ -ltq_w32 (LTQ_WDT_PW2 , ltq_wdt_membase +LTQ_WDT_CR ); +ltq_w32 (LTQ_WDT_CR_PW2 , ltq_wdt_membase +LTQ_WDT_CR ); } static ssize_t
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 23/45 drm/omap: fix memory barrier bug in DMM driver
In reply to Sasha LevinFrom: Tomi Valkeinen <[email protected]>
[ Upstream commit 538f66ba204944470a653a4cccc5f8befdf97c22 ]
A DMM timeout "timed out waiting for done" has been observed on DRA7 devices. The timeout happens rarely, and only when the system is under heavy load.
Debugging showed that the timeout can be made to happen much more frequently by optimizing the DMM driver, so that there's almost no code between writing the last DMM descriptors to RAM, and writing to DMM register which starts the DMM transaction.
The current theory is that a wmb() does not properly ensure that the data written to RAM is observable by all the components in the system.
This DMM timeout has caused interesting (and rare) bugs as the error handling was not functioning properly (the error handling has been fixed in previous commits):
* If a DMM timeout happened when a GEM buffer was being pinned for display on the screen, a timeout error would be shown, but the driver would continue programming DSS HW with broken buffer, leading to SYNCLOST floods and possible crashes.
* If a DMM timeout happened when other user (say, video decoder) was pinning a GEM buffer, a timeout would be shown but if the user handled the error properly, no other issues followed.
* If a DMM timeout happened when a GEM buffer was being released, the driver does not even notice the error, leading to crashes or hang later.
This patch adds wmb() and readl() calls after the last bit is written to RAM, which should ensure that the execution proceeds only after the data is actually in RAM, and thus observable by DMM.
The read-back should not be needed. Further study is required to understand if DMM is somehow special case and read-back is ok, or if DRA7's memory barriers do not work correctly.
--- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +11 -0
@@ -285,6 +285,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) } txn->last_pat->next_pa =0 ; +/* ensure that the written descriptors are visible to DMM */ +wmb (); + +/* +* NOTE: the wmb() above should be enough, but there seems to be a bug +* in OMAP's memory barrier implementation, which in some rare cases may +* cause the writes not to be observable after wmb(). +*/ + +/* read back to ensure the data is in RAM */ +readl (&txn->last_pat->next_pa);/* write to PAT_DESCR to clear out any pending transaction */ dmm_write (dmm,0x0 , reg[PAT_DESCR ][engine->id]);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 24/45 iio: adc: at91: fix wrong channel number in triggered buffer mode
In reply to Sasha LevinFrom: Eugen Hristev <[email protected]>
[ Upstream commit aea835f2dc8a682942b859179c49ad1841a6c8b9 ]
When channels are registered, the hardware channel number is not the actual iio channel number.
This is because the driver is probed with a certain number of accessible channels. Some pins are routed and some not, depending on the description of the board in the DT.
Because of that, channels 0,1,2,3 can correspond to hardware channels 2,3,4,5 for example.
In the buffered triggered case, we need to do the translation accordingly. Fixed the channel number to stop reading the wrong channel.
--- drivers/iio/adc/at91_adc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iio/adc/at91_adc.c +3 -1
@@ -248,12 +248,14 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)struct iio_poll_func *pf = p;struct iio_dev *idev = pf->indio_dev;struct at91_adc_state *st =iio_priv (idev); +struct iio_chan_spec const *chan;int i, j =0 ;for (i =0 ; i < idev->masklength; i++) {if (!test_bit (i, idev->active_scan_mask))continue ; - st->buffer[j] =at91_adc_readl (st,AT91_ADC_CHAN (st, i)); + chan = idev->channels + i; + st->buffer[j] =at91_adc_readl (st,AT91_ADC_CHAN (st, chan->channel)); j++; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 25/45 iio: adc: at91: fix acking DRDY irq on simple conversions
In reply to Sasha LevinFrom: Eugen Hristev <[email protected]>
[ Upstream commit bc1b45326223e7e890053cf6266357adfa61942d ]
When doing simple conversions, the driver did not acknowledge the DRDY irq. If this irq status is not acked, it will be left pending, and as soon as a trigger is enabled, the irq handler will be called, it doesn't know why this status has occurred because no channel is pending, and then it will go int a irq loop and board will hang.
To avoid this situation, read the LCDR after a raw conversion is done.
--- drivers/iio/adc/at91_adc.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/adc/at91_adc.c +2 -0
@@ -281,6 +281,8 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)iio_trigger_poll (idev->trig); }else { st->last_value =at91_adc_readl (st,AT91_ADC_CHAN (st, st->chnb)); +/* Needed to ACK the DRDY interruption */ +at91_adc_readl (st,AT91_ADC_LCDR ); st->done = true;wake_up_interruptible (&st->wq_data_avail); }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 26/45 drm/amd/display: fix gamma not being applied
In reply to Sasha LevinFrom: SivapiriyanKumarasamy <[email protected]>
[ Upstream commit 30049754ab7c4b6148dd3cd64af7d54850604582 ]
[WHY]
Previously night light forced a full update by
applying a transfer function update regardless of if it was changed. This logic was removed,
Now gamma surface updates are only applied when there is also a plane info update, this does not work in cases such as using the night light slider.
[HOW]
When moving the night light slider we will perform a full update if the gamma has changed and there is a surface, even when the surface has not changed. Also get stream updates in setgamma prior to update planes and stream.
--- drivers/gpu/drm/amd/display/dc/core/dc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc.c +14 -5
@@ -1045,9 +1045,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa*/ update_flags->bits.bpp_change =1 ; -if (u->gamma &&dce_use_lut (u->plane_info->format)) - update_flags->bits.gamma_change =1 ; -if (memcmp (&u->plane_info->tiling_info, &u->surface->tiling_info,sizeof (union dc_tiling_info )) !=0 ) { update_flags->bits.swizzle_change =1 ;
@@ -1064,7 +1061,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfaif (update_flags->bits.rotation_change || update_flags->bits.stereo_format_change || update_flags->bits.pixel_format_change - || update_flags->bits.gamma_change || update_flags->bits.bpp_change || update_flags->bits.bandwidth_change || update_flags->bits.output_tf_change)
@@ -1154,13 +1150,26 @@ static enum surface_update_type det_surface_update(const struct dc *dc,if (u->coeff_reduction_factor) update_flags->bits.coeff_reduction_change =1 ; +if (u->gamma) { +enum surface_pixel_format format =SURFACE_PIXEL_FORMAT_GRPH_BEGIN ; + +if (u->plane_info) + format = u->plane_info->format; +else if (u->surface) + format = u->surface->format; + +if (dce_use_lut (format)) + update_flags->bits.gamma_change =1 ; + } +if (update_flags->bits.in_transfer_func_change) { type =UPDATE_TYPE_MED ;elevate_update_type (&overall_type, type); }if (update_flags->bits.input_csc_change - || update_flags->bits.coeff_reduction_change) { + || update_flags->bits.coeff_reduction_change + || update_flags->bits.gamma_change) { type =UPDATE_TYPE_FULL ;elevate_update_type (&overall_type, type); }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 27/45 drm/hisilicon: hibmc: Do not carry error code in HiBMC framebuffer pointer
In reply to Sasha LevinFrom: John Garry <[email protected]>
[ Upstream commit 331d880b35a76b5de0eec8cbcecbf615d758a5f9 ]
In hibmc_drm_fb_create(), when the call to hibmc_framebuffer_init() fails with error, do not store the error code in the HiBMC device frame-buffer pointer, as this will be later checked for non-zero value in hibmc_fbdev_destroy() when our intention is to check for a valid function pointer.
This fixes the following crash:
[ 9.699791] Unable to handle kernel NULL pointer dereference at virtual address 000000000000001a [ 9.708672] Mem abort info: [ 9.711489] ESR = 0x96000004 [ 9.714570] Exception class = DABT (current EL), IL = 32 bits [ 9.720551] SET = 0, FnV = 0 [ 9.723631] EA = 0, S1PTW = 0 [ 9.726799] Data abort info: [ 9.729702] ISV = 0, ISS = 0x00000004 [ 9.733573] CM = 0, WnR = 0 [ 9.736566] [000000000000001a] user address but active_mm is swapper [ 9.742987] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 9.748614] Modules linked in: [ 9.751694] CPU: 16 PID: 293 Comm: kworker/16:1 Tainted: G W 4.19.0-rc4-next-20180920-00001-g9b0012c #322 [ 9.762681] Hardware name: Huawei Taishan 2280 /D05, BIOS Hisilicon D05 IT21 Nemo 2.0 RC0 04/18/2018 [ 9.771915] Workqueue: events work_for_cpu_fn [ 9.776312] pstate: 60000005 (nZCv daif -PAN -UAO) [ 9.781150] pc : drm_mode_object_put+0x0/0x20 [ 9.785547] lr : hibmc_fbdev_fini+0x40/0x58 [ 9.789767] sp : ffff00000af1bcf0 [ 9.793108] x29: ffff00000af1bcf0 x28: 0000000000000000 [ 9.798473] x27: 0000000000000000 x26: ffff000008f66630 [ 9.803838] x25: 0000000000000000 x24: ffff0000095abb98 [ 9.809203] x23: ffff8017db92fe00 x22: ffff8017d2b13000 [ 9.814568] x21: ffffffffffffffea x20: ffff8017d2f80018 [ 9.819933] x19: ffff8017d28a0018 x18: ffffffffffffffff [ 9.825297] x17: 0000000000000000 x16: 0000000000000000 [ 9.830662] x15: ffff0000092296c8 x14: ffff00008939970f [ 9.836026] x13: ffff00000939971d x12: ffff000009229940 [ 9.841391] x11: ffff0000085f8fc0 x10: ffff00000af1b9a0 [ 9.846756] x9 : 000000000000000d x8 : 6620657a696c6169 [ 9.852121] x7 : ffff8017d3340580 x6 : ffff8017d4168000 [ 9.857486] x5 : 0000000000000000 x4 : ffff8017db92fb20 [ 9.862850] x3 : 0000000000002690 x2 : ffff8017d3340480 [ 9.868214] x1 : 0000000000000028 x0 : 0000000000000002 [ 9.873580] Process kworker/16:1 (pid: 293, stack limit = 0x(____ptrval____)) [ 9.880788] Call trace: [ 9.883252] drm_mode_object_put+0x0/0x20 [ 9.887297] hibmc_unload+0x1c/0x80 [ 9.890815] hibmc_pci_probe+0x170/0x3c8 [ 9.894773] local_pci_probe+0x3c/0xb0 [ 9.898555] work_for_cpu_fn+0x18/0x28 [ 9.902337] process_one_work+0x1e0/0x318 [ 9.906382] worker_thread+0x228/0x450 [ 9.910164] kthread+0x128/0x130 [ 9.913418] ret_from_fork+0x10/0x18 [ 9.917024] Code: a94153f3 a8c27bfd d65f03c0 d503201f (f9400c01) [ 9.923180] ---[ end trace 2695ffa0af5be375 ]---
--- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +1 -0
@@ -122,6 +122,7 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, hi_fbdev->fb =hibmc_framebuffer_init (priv->dev, &mode_cmd, gobj);if (IS_ERR (hi_fbdev->fb)) { ret =PTR_ERR (hi_fbdev->fb); + hi_fbdev->fb =NULL ;DRM_ERROR ("failed to initialize framebuffer: %d\n" , ret); goto out_release_fbi; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 28/45 media: pci: cx23885: handle adding to list failure
In reply to Sasha LevinFrom: Nicholas Mc Guire <[email protected]>
[ Upstream commit c5d59528e24ad22500347b199d52b9368e686a42 ]
altera_hw_filt_init() which calls append_internal() assumes that the node was successfully linked in while in fact it can silently fail. So the call-site needs to set return to -ENOMEM on append_internal() returning NULL and exit through the err path.
--- drivers/media/pci/cx23885/altera-ci.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/media/pci/cx23885/altera-ci.c +10 -0
@@ -665,6 +665,10 @@ static int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) } temp_int =append_internal (inter); +if (!temp_int) { + ret = -ENOMEM ; + goto err; + } inter->filts_used =1 ; inter->dev = config->dev; inter->fpga_rw = config->fpga_rw;
@@ -699,6 +703,7 @@ static int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) __func__, ret);kfree (pid_filt); +kfree (inter);return ret; }
@@ -733,6 +738,10 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr) } temp_int =append_internal (inter); +if (!temp_int) { + ret = -ENOMEM ; + goto err; + } inter->cis_used =1 ; inter->dev = config->dev; inter->fpga_rw = config->fpga_rw;
@@ -801,6 +810,7 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr)ci_dbg_print ("%s: Cannot initialize CI: Error %d.\n" , __func__, ret);kfree (state); +kfree (inter);return ret; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 29/45 media: coda: don't overwrite h.264 profile_idc on decoder instance
In reply to Sasha LevinFrom: Lucas Stach <[email protected]>
[ Upstream commit 1f32061e843205f6fe8404d5100d5adcec334e75 ]
On a decoder instance, after the profile has been parsed from the stream __v4l2_ctrl_s_ctrl() is called to notify userspace about changes in the read-only profile control. This ends up calling back into the CODA driver where a missing check on the s_ctrl caused the profile information that has just been parsed from the stream to be overwritten with the default baseline profile.
Later on the driver fails to enable frame reordering, based on the wrong profile information.
profile/level controls)
--- drivers/media/platform/coda/coda-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/coda/coda-common.c +2 -1
@@ -1719,7 +1719,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)break ;case V4L2_CID_MPEG_VIDEO_H264_PROFILE :/* TODO: switch between baseline and constrained baseline */ - ctx->params.h264_profile_idc =66 ; +if (ctx->inst_type ==CODA_INST_ENCODER ) + ctx->params.h264_profile_idc =66 ;break ;case V4L2_CID_MPEG_VIDEO_H264_LEVEL :/* nothing to do, this is set by the encoder */
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 30/45 iio: adc: imx25-gcq: Fix leak of device_node in mx25_gcq_setup_cfgs()
In reply to Sasha LevinFrom: Alexey Khoroshilov <[email protected]>
[ Upstream commit d3fa21c73c391975488818b085b894c2980ea052 ]
Leaving for_each_child_of_node loop we should release child device node, if it is not stored for future use.
Found by Linux Driver Verification project (linuxtesting.org).
JC: I'm not sending this as a quick fix as it's been wrong for years, but good to pick up for stable after the merge window.
--- drivers/iio/adc/fsl-imx25-gcq.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/iio/adc/fsl-imx25-gcq.c +6 -0
@@ -209,12 +209,14 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, ret =of_property_read_u32 (child,"reg" , ®);if (ret) {dev_err (dev,"Failed to get reg property\n" ); +of_node_put (child);return ret; }if (reg >=MX25_NUM_CFGS ) {dev_err (dev,"reg value is greater than the number of available configuration registers\n" ); +of_node_put (child);return -EINVAL ; }
@@ -228,6 +230,7 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,if (IS_ERR (priv->vref[refp])) {dev_err (dev,"Error, trying to use external voltage reference without a vref-%s regulator." , mx25_gcq_refp_names[refp]); +of_node_put (child);return PTR_ERR (priv->vref[refp]); } priv->channel_vref_mv[reg] =
@@ -240,6 +243,7 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,break ;default :dev_err (dev,"Invalid positive reference %d\n" , refp); +of_node_put (child);return -EINVAL ; }
@@ -254,10 +258,12 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,if ((refp &MX25_ADCQ_CFG_REFP_MASK ) != refp) {dev_err (dev,"Invalid fsl,adc-refp property value\n" ); +of_node_put (child);return -EINVAL ; }if ((refn &MX25_ADCQ_CFG_REFN_MASK ) != refn) {dev_err (dev,"Invalid fsl,adc-refn property value\n" ); +of_node_put (child);return -EINVAL ; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 31/45 MIPS: kexec: Mark CPU offline before disabling local IRQ
In reply to Sasha LevinFrom: Dengcheng Zhu <[email protected]>
[ Upstream commit dc57aaf95a516f70e2d527d8287a0332c481a226 ]
After changing CPU online status, it will not be sent any IPIs such as in __flush_cache_all() on software coherency systems. Do this before disabling local IRQ.
Patchwork: https://patchwork.linux-mips.org/patch/20571/
--- arch/mips/kernel/crash.c | 3 +++ arch/mips/kernel/machine_kexec.c | 3 +++ 2 files changed, 6 insertions(+)
arch/mips/kernel/crash.c +3 -0
@@ -36,6 +36,9 @@ static void crash_shutdown_secondary(void *passed_regs)if (!cpu_online (cpu))return ; +/* We won't be sent IPIs any more. */ +set_cpu_online (cpu, false); +local_irq_disable ();if (!cpumask_test_cpu (cpu, &cpus_in_crash))crash_save_cpu (regs, cpu);
arch/mips/kernel/machine_kexec.c +3 -0
@@ -118,6 +118,9 @@ machine_kexec(struct kimage *image) *ptr = (unsigned long )phys_to_virt (*ptr); } +/* Mark offline BEFORE disabling local irq. */ +set_cpu_online (smp_processor_id (), false); +/* * we do not want to be bothered. */
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 32/45 powerpc/boot: Ensure _zimage_start is a weak symbol
In reply to Sasha LevinFrom: Joel Stanley <[email protected]>
[ Upstream commit ee9d21b3b3583712029a0db65a4b7c081d08d3b3 ]
When building with clang crt0's _zimage_start is not marked weak, which breaks the build when linking the kernel image:
$ objdump -t arch/powerpc/boot/crt0.o |grep _zimage_start$ 0000000000000058 g .text 0000000000000000 _zimage_start
ld: arch/powerpc/boot/wrapper.a(crt0.o): in function '_zimage_start':
(.text+0x58): multiple definition of '_zimage_start'; arch/powerpc/boot/pseries-head.o:(.text+0x0): first defined here
Clang requires the .weak directive to appear after the symbol is declared. The binutils manual says:
This directive sets the weak attribute on the comma separated list of symbol names. If the symbols do not already exist, they will be created.
So it appears this is different with clang. The only reference I could see for this was an OpenBSD mailing list post[1].
Changing it to be after the declaration fixes building with Clang, and still works with GCC.
$ objdump -t arch/powerpc/boot/crt0.o |grep _zimage_start$ 0000000000000058 w .text 0000000000000000 _zimage_start
Reported to clang as https://bugs.llvm.org/show_bug.cgi?id=38921
[1] https://groups.google.com/forum/#!topic/fa.openbsd.tech/PAgKKen2YCY
--- arch/powerpc/boot/crt0.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/powerpc/boot/crt0.S +3 -1
@@ -47,8 +47,10 @@ p_end: .long _end p_pstack: .long _platform_stack_top #endif - .weak _zimage_start .globl _zimage_start + /* Clang appears to require the .weak directive to be after the symbol + * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921 */ + .weak _zimage_start _zimage_start: .globl _zimage_start_lib _zimage_start_lib:
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 33/45 powerpc/memtrace: Remove memory in chunks
In reply to Sasha LevinFrom: Rashmica Gupta <[email protected]>
[ Upstream commit 3f7daf3d7582dc6628ac40a9045dd1bbd80c5f35 ]
When hot-removing memory release_mem_region_adjustable() splits iomem resources if they are not the exact size of the memory being hot-deleted. Adding this memory back to the kernel adds a new resource.
Eg a node has memory 0x0 - 0xfffffffff. Hot-removing 1GB from 0xf40000000 results in the single resource 0x0-0xfffffffff being split into two resources: 0x0-0xf3fffffff and 0xf80000000-0xfffffffff.
When we hot-add the memory back we now have three resources:
0x0-0xf3fffffff, 0xf40000000-0xf7fffffff, and 0xf80000000-0xfffffffff.
This is an issue if we try to remove some memory that overlaps resources. Eg when trying to remove 2GB at address 0xf40000000, release_mem_region_adjustable() fails as it expects the chunk of memory to be within the boundaries of a single resource. We then get the
warning: "Unable to release resource" and attempting to use memtrace again gives us this error: "bash: echo: write error: Resource temporarily unavailable"
This patch makes memtrace remove memory in chunks that are always the same size from an address that is always equal to end_of_memory - n*size, for some n. So hotremoving and hotadding memory of different sizes will now not attempt to remove memory that spans multiple resources.
--- arch/powerpc/platforms/powernv/memtrace.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
arch/powerpc/platforms/powernv/memtrace.c +16 -5
@@ -119,17 +119,15 @@ static bool memtrace_offline_pages(u32 nid, u64 start_pfn, u64 nr_pages)walk_memory_range (start_pfn, end_pfn, (void *)MEM_OFFLINE , change_memblock_state); -lock_device_hotplug (); -remove_memory (nid, start_pfn <<PAGE_SHIFT , nr_pages <<PAGE_SHIFT ); -unlock_device_hotplug ();return true; }static u64 memtrace_alloc_node (u32 nid,u64 size) { -u64 start_pfn, end_pfn, nr_pages; +u64 start_pfn, end_pfn, nr_pages, pfn;u64 base_pfn; +u64 bytes =memory_block_size_bytes ();if (!node_spanned_pages (nid))return 0 ;
@@ -142,8 +140,21 @@ static u64 memtrace_alloc_node(u32 nid, u64 size) end_pfn =round_down (end_pfn - nr_pages, nr_pages);for (base_pfn = end_pfn; base_pfn > start_pfn; base_pfn -= nr_pages) { -if (memtrace_offline_pages (nid, base_pfn, nr_pages) == true) +if (memtrace_offline_pages (nid, base_pfn, nr_pages) == true) { +/* +* Remove memory in memory block size chunks so that +* iomem resources are always split to the same size and +* we never try to remove memory that spans two iomem +* resources. +*/ +lock_device_hotplug (); + end_pfn = base_pfn + nr_pages; +for (pfn = base_pfn; pfn < end_pfn; pfn += bytes>>PAGE_SHIFT ) { +remove_memory (nid, pfn <<PAGE_SHIFT , bytes); + } +unlock_device_hotplug ();return base_pfn <<PAGE_SHIFT ; + } }return 0 ;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 34/45 MIPS/PCI: Call pcie_bus_configure_settings() to set MPS/MRRS
In reply to Sasha LevinFrom: Huacai Chen <[email protected]>
[ Upstream commit 2794f688b2c336e0da85e9f91fed33febbd9f54a ]
Call pcie_bus_configure_settings() on MIPS, like for other platforms. The function pcie_bus_configure_settings() makes sure the MPS (Max Payload Size) across the bus is uniform and provides the ability to tune the MRSS (Max Read Request Size) and MPS (Max Payload Size) to higher performance values. Some devices will not operate properly if these aren't set correctly because the firmware doesn't always do it.
Patchwork: https://patchwork.linux-mips.org/patch/20649/
--- arch/mips/pci/pci-legacy.c | 4 ++++ 1 file changed, 4 insertions(+)
arch/mips/pci/pci-legacy.c +4 -0
@@ -127,8 +127,12 @@ static void pcibios_scanbus(struct pci_controller *hose)if (pci_has_flag (PCI_PROBE_ONLY )) {pci_bus_claim_resources (bus); }else { +struct pci_bus *child; +pci_bus_size_bridges (bus);pci_bus_assign_resources (bus); +list_for_each_entry (child, &bus->children, node) +pcie_bus_configure_settings (child); }pci_bus_add_devices (bus); }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 35/45 sc16is7xx: Fix for multi-channel stall
In reply to Sasha LevinFrom: Phil Elwell <[email protected]>
[ Upstream commit 8344498721059754e09d30fe255a12dab8fb03ef ]
The SC16IS752 is a dual-channel device. The two channels are largely independent, but the IRQ signals are wired together as an open-drain, active low signal which will be driven low while either of the channels requires attention, which can be for significant periods of time until operations complete and the interrupt can be acknowledged. In that respect it is should be treated as a true level-sensitive IRQ.
The kernel, however, needs to be able to exit interrupt context in order to use I2C or SPI to access the device registers (which may involve sleeping). Therefore the interrupt needs to be masked out or paused in some way.
The usual way to manage sleeping from within an interrupt handler is to use a threaded interrupt handler - a regular interrupt routine does the minimum amount of work needed to triage the interrupt before waking the interrupt service thread. If the threaded IRQ is marked as IRQF_ONESHOT the kernel will automatically mask out the interrupt until the thread runs to completion. The sc16is7xx driver used to use a threaded IRQ, but a patch switched to using a kthread_worker in order to set realtime priorities on the handler thread and for other optimisations. The end result is non-threaded IRQ that schedules some work then returns IRQ_HANDLED, making the kernel think that all IRQ processing has completed.
The work-around to prevent a constant stream of interrupts is to mark the interrupt as edge-sensitive rather than level-sensitive, but interpreting an active-low source as a falling-edge source requires care to prevent a total cessation of interrupts. Whereas an edge-triggering source will generate a new edge for every interrupt condition a level-triggering source will keep the signal at the interrupting level until it no longer requires attention; in other words, the host won't see another edge until all interrupt conditions are cleared. It is therefore vital that the interrupt handler does not exit with an outstanding interrupt condition, otherwise the kernel will not receive another interrupt unless some other operation causes the interrupt state on the device to be cleared.
The existing sc16is7xx driver has a very simple interrupt "thread" (kthread_work job) that processes interrupts on each channel in turn until there are no more. If both channels are active and the first channel starts interrupting while the handler for the second channel is running then it will not be detected and an IRQ stall ensues. This could be handled easily if there was a shared IRQ status register, or a convenient way to determine if the IRQ had been deasserted for any length of time, but both appear to be lacking.
Avoid this problem (or at least make it much less likely to happen) by reducing the granularity of per-channel interrupt processing to one condition per iteration, only exiting the overall loop when both channels are no longer interrupting.
--- drivers/tty/serial/sc16is7xx.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/tty/serial/sc16is7xx.c +13 -6
@@ -657,7 +657,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)uart_write_wakeup (port); } -static void sc16is7xx_port_irq (struct sc16is7xx_port *s,int portno) +static bool sc16is7xx_port_irq (struct sc16is7xx_port *s,int portno) {struct uart_port *port = &s->p[portno].port;
@@ -666,7 +666,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) iir =sc16is7xx_port_read (port,SC16IS7XX_IIR_REG );if (iir &SC16IS7XX_IIR_NO_INT_BIT ) -break ; +return false; iir &=SC16IS7XX_IIR_ID_MASK ;
@@ -688,16 +688,23 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) port->line, iir);break ; } - }while (1 ); + }while (0 ); +return true; }static void sc16is7xx_ist (struct kthread_work *ws) {struct sc16is7xx_port *s =to_sc16is7xx_port (ws, irq_work); -int i; -for (i =0 ; i < s->devtype->nr_uart; ++i) -sc16is7xx_port_irq (s, i); +while (1 ) { +bool keep_polling = false; +int i; + +for (i =0 ; i < s->devtype->nr_uart; ++i) + keep_polling |=sc16is7xx_port_irq (s, i); +if (!keep_polling) +break ; + } }static irqreturn_t sc16is7xx_irq (int irq,void *dev_id)
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 36/45 media: tvp5150: fix width alignment during set_selection()
In reply to Sasha LevinFrom: Marco Felsch <[email protected]>
[ Upstream commit bd24db04101f45a9c1d874fe21b0c7eab7bcadec ]
The driver ignored the width alignment which exists due to the UYVY colorspace format. Fix the width alignment and make use of the the provided v4l2 helper function to set the width, height and all alignments in one.
--- drivers/media/i2c/tvp5150.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/media/i2c/tvp5150.c +9 -5
@@ -901,9 +901,6 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,/* tvp5150 has some special limits */ rect.left =clamp (rect.left,0 ,TVP5150_MAX_CROP_LEFT ); - rect.width = clamp_t(unsigned int, rect.width, -TVP5150_H_MAX -TVP5150_MAX_CROP_LEFT - rect.left, -TVP5150_H_MAX - rect.left); rect.top =clamp (rect.top,0 ,TVP5150_MAX_CROP_TOP );/* Calculate height based on current standard */
@@ -917,9 +914,16 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,else hmax =TVP5150_V_MAX_OTHERS ; - rect.height = clamp_t(unsigned int, rect.height, +/* +* alignments: +* - width = 2 due to UYVY colorspace +* - height, image = no special alignment +*/ +v4l_bound_align_image (&rect.width, +TVP5150_H_MAX -TVP5150_MAX_CROP_LEFT - rect.left, +TVP5150_H_MAX - rect.left,1 , &rect.height, hmax -TVP5150_MAX_CROP_TOP - rect.top, - hmax - rect.top); + hmax - rect.top,0 ,0 );tvp5150_write (sd,TVP5150_VERT_BLANKING_START , rect.top); tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 37/45 powerpc/selftests: Wait all threads to join
In reply to Sasha LevinFrom: Breno Leitao <[email protected]>
[ Upstream commit 693b31b2fc1636f0aa7af53136d3b49f6ad9ff39 ]
Test tm-tmspr might exit before all threads stop executing, because it just waits for the very last thread to join before proceeding/exiting.
This patch makes sure that all threads that were created will join before proceeding/exiting.
This patch also guarantees that the amount of threads being created is equal to thread_num.
--- tools/testing/selftests/powerpc/tm/tm-tmspr.c | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-)
tools/testing/selftests/powerpc/tm/tm-tmspr.c +17 -10
@@ -98,7 +98,7 @@ void texasr(void *in)int test_tmspr () { -pthread_t thread; +pthread_t *thread;int thread_num;unsigned long i;
@@ -107,21 +107,28 @@ int test_tmspr()/* To cause some context switching */ thread_num =10 *sysconf (_SC_NPROCESSORS_ONLN); + thread =malloc (thread_num *sizeof (pthread_t)); +if (thread ==NULL ) +return EXIT_FAILURE ; +/* Test TFIAR and TFHAR */ -for (i =0 ; i < thread_num ; i +=2 ){ -if (pthread_create (&thread,NULL , (void *)tfiar_tfhar, (void *)i)) +for (i =0 ; i < thread_num; i +=2 ) { +if (pthread_create (&thread[i],NULL , (void *)tfiar_tfhar, + (void *)i))return EXIT_FAILURE ; } -if (pthread_join (thread,NULL ) !=0 ) -return EXIT_FAILURE ; -/* Test TEXASR */ -for (i =0 ; i < thread_num ; i++){ -if (pthread_create (&thread,NULL , (void *)texasr, (void *)i)) +for (i =1 ; i < thread_num; i +=2 ) { +if (pthread_create (&thread[i],NULL , (void *)texasr, (void *)i))return EXIT_FAILURE ; } -if (pthread_join (thread,NULL ) !=0 ) -return EXIT_FAILURE ; + +for (i =0 ; i < thread_num; i++) { +if (pthread_join (thread[i],NULL ) !=0 ) +return EXIT_FAILURE ; + } + +free (thread);if (passed)return 0 ;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 38/45 staging:iio:ad7606: fix voltage scales
In reply to Sasha LevinFrom: Alexandru Ardelean <[email protected]>
[ Upstream commit 4ee033301c898dd0835d035d0e0eb768a3d35da1 ]
Fixes commit 17be2a2905a6ec9aa27cd59521495e2f490d2af0 ("staging: iio:
ad7606: replace range/range_available with corresponding scale").
The AD7606 devices don't have a 2.5V voltage range, they have 5V & 10V voltage range, which is selectable via the gpio_range descriptor.
The scales also seem to have been miscomputed, because when they were applied to the raw values, the results differ from the expected values. After checking the ADC transfer function in the datasheet, these were re-computed.
--- drivers/staging/iio/adc/ad7606.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/staging/iio/adc/ad7606.c +5 -2
@@ -26,9 +26,12 @@#include "ad7606.h" -/* Scales are computed as 2.5/2**16 and 5/2**16 respectively */ +/* +* Scales are computed as 5000/32768 and 10000/32768 respectively, +* so that when applied to the raw values they provide mV values +*/ static const unsigned int scale_avail[2 ][2 ] = { - {0 ,38147 }, {0 ,76294 } + {0 ,152588 }, {0 ,305176 } };static int ad7606_reset (struct ad7606_state *st)
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 39/45 drm: rcar-du: Update Gen3 output limitations
In reply to Sasha LevinFrom: Kieran Bingham <[email protected]>
[ Upstream commit 2a3181d9cfd6d5aa48f8527708d0c32072072cef ]
The R-Car Gen3 DU utilises the VSP1 hardware for memory access. The limits on the RPF and WPF in this pipeline are 8190x8190.
Update the supported maximum sizes accordingly.
--- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/gpu/drm/rcar-du/rcar_du_kms.c +12 -2
@@ -516,12 +516,22 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) dev->mode_config.min_width =0 ; dev->mode_config.min_height =0 ; - dev->mode_config.max_width =4095 ; - dev->mode_config.max_height =2047 ; dev->mode_config.normalize_zpos = true; dev->mode_config.funcs = &rcar_du_mode_config_funcs; dev->mode_config.helper_private = &rcar_du_mode_config_helper; +if (rcdu->info->gen <3 ) { + dev->mode_config.max_width =4095 ; + dev->mode_config.max_height =2047 ; + }else { +/* +* The Gen3 DU uses the VSP1 for memory access, and is limited +* to frame sizes of 8190x8190. +*/ + dev->mode_config.max_width =8190 ; + dev->mode_config.max_height =8190 ; + } + rcdu->num_crtcs =hweight8 (rcdu->info->channels_mask); ret =rcar_du_properties_init (rcdu);
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 40/45 drm/amdgpu: Fix SDMA TO after GPU reset v3
In reply to Sasha LevinFrom: Andrey Grodzovsky <[email protected]>
[ Upstream commit d8de8260a45aae8f74af77eae9a162bdc0ed48d2 ]
After GPU reset amdgpu_vm_clear_bo triggers VM flush but job->vm_pd_addr is not set causing SDMA TO.
v2:
Per advise by Christian König avoid flushing VM for jobs where job->vm_pd_addr wasn't explicitly set.
v3:
Shortcut vm_flush_needed early.
Fixes cbd5285 drm/amdgpu: move setting the GART addr into TTM.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +1 -0
@@ -62,6 +62,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs,amdgpu_sync_create (&(*job)->sync);amdgpu_sync_create (&(*job)->sched_sync); (*job)->vram_lost_counter =atomic_read (&adev->vram_lost_counter); + (*job)->vm_pd_addr =AMDGPU_BO_INVALID_OFFSET ;return 0 ; }
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +2 -1
@@ -631,7 +631,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_ } gds_switch_needed &= !!ring->funcs->emit_gds_switch; - vm_flush_needed &= !!ring->funcs->emit_vm_flush; + vm_flush_needed &= !!ring->funcs->emit_vm_flush && + job->vm_pd_addr !=AMDGPU_BO_INVALID_OFFSET ; pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && ring->funcs->emit_wreg;
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 41/45 staging: most: video: fix registration of an empty comp core_component
In reply to Sasha LevinFrom: Colin Ian King <[email protected]>
[ Upstream commit 1f447e51c0b9e8beeec0917ea5f51930f55e17c9 ]
Currently we have structrues comp (which is empty) and comp_info being used to register and deregister the component. This mismatch in naming occurred from a previous commit that renamed aim_info to comp. Fix this to use consistent component naming in line with most/net, most/sound etc.
This fixes the message two issues, one with a null empty name when loading the module:
[ 1485.269515] most_core: registered new core component (null)
and an Oops when removing the module:
[ 1485.277971] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 [ 1485.278648] PGD 0 P4D 0 [ 1485.279253] Oops: 0002 [#2] SMP PTI [ 1485.279847] CPU: 1 PID: 32629 Comm: modprobe Tainted: P D WC OE 4.18.0-8-generic #9 [ 1485.280442] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015 [ 1485.281040] RIP: 0010:most_deregister_component+0x3c/0x70 [most_core]
.. etc
--- drivers/staging/most/video/video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/most/video/video.c +2 -2
@@ -530,7 +530,7 @@ static int comp_disconnect_channel(struct most_interface *iface,return 0 ; } -static struct core_component comp_info = { +static struct core_component comp = { .name ="video" , .probe_channel = comp_probe_channel, .disconnect_channel = comp_disconnect_channel,
@@ -565,7 +565,7 @@ static void __exit comp_exit(void) }spin_unlock_irq (&list_lock); -most_deregister_component (&comp_info); +most_deregister_component (&comp);BUG_ON (!list_empty (&video_devices)); }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 42/45 9p locks: fix glock.client_id leak in do_lock
In reply to Sasha LevinFrom: Dominique Martinet <[email protected]>
[ Upstream commit b4dc44b3cac9e8327e0655f530ed0c46f2e6214c ]
the 9p client code overwrites our glock.client_id pointing to a static buffer by an allocated string holding the network provided value which we do not care about; free and reset the value as appropriate.
This is almost identical to the leak in v9fs_file_getlock() fixed by Al Viro in commit ce85dd58ad5a6 ("9p: we are leaking glock.client_id in v9fs_file_getlock()"), which was returned as an error by a coverity false positive -- while we are here attempt to make the code slightly more robust to future change of the net/9p/client code and hopefully more clear to coverity that there is no problem.
--- fs/9p/vfs_file.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
fs/9p/vfs_file.c +14 -2
@@ -204,6 +204,14 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)break ;if (schedule_timeout_interruptible (P9_LOCK_TIMEOUT ) !=0 )break ; +/* +* p9_client_lock_dotl overwrites flock.client_id with the +* server message, free and reuse the client name +*/ +if (flock.client_id != fid->clnt->name) { +kfree (flock.client_id); + flock.client_id = fid->clnt->name; + } }/* map 9p status to VFS status */
@@ -235,6 +243,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)locks_lock_file_wait (filp, fl); fl->fl_type = fl_type; } +if (flock.client_id != fid->clnt->name) +kfree (flock.client_id); out:return res; }
@@ -269,7 +279,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) res =p9_client_getlock_dotl (fid, &glock);if (res <0 ) -return res; + goto out;/* map 9p lock type to os lock type */ switch (glock.type) {case P9_LOCK_TYPE_RDLCK :
@@ -290,7 +300,9 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) fl->fl_end = glock.start + glock.length -1 ; fl->fl_pid = -glock.proc_id; } -kfree (glock.client_id); +out: +if (glock.client_id != fid->clnt->name) +kfree (glock.client_id);return res; }
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 43/45 udf: Prevent write-unsupported filesystem to be remounted read-write
In reply to Sasha LevinFrom: Jan Kara <[email protected]>
[ Upstream commit a9ad01bc759df79b0012f43ee52164391e31cd96 ]
There are certain filesystem features which we support for reading but not for writing. We properly refuse to mount such filesystems read-write however for some features (such as read-only partitions), we don't check for these features when remounting the filesystem from read-only to read-write. Thus such filesystems could be remounted read-write leading to strange behavior (most likely crashes).
Fix the problem by marking in superblock whether the filesystem has some features that are supported in read-only mode and check this flag during remount.
--- fs/udf/super.c | 30 ++++++++++++++++-------------- fs/udf/udf_sb.h | 2 ++ 2 files changed, 18 insertions(+), 14 deletions(-)
fs/udf/super.c +16 -14
@@ -613,14 +613,11 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)struct udf_options uopt;struct udf_sb_info *sbi =UDF_SB (sb);int error =0 ; -struct logicalVolIntegrityDescImpUse *lvidiu =udf_sb_lvidiu (sb); + +if (!(*flags &SB_RDONLY ) &&UDF_QUERY_FLAG (sb,UDF_FLAG_RW_INCOMPAT )) +return -EACCES ;sync_filesystem (sb); -if (lvidiu) { -int write_rev =le16_to_cpu (lvidiu->minUDFWriteRev); -if (write_rev >UDF_MAX_WRITE_VERSION && !(*flags &SB_RDONLY )) -return -EACCES ; - } uopt.flags = sbi->s_flags; uopt.uid = sbi->s_uid;
@@ -1317,6 +1314,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ret = -EACCES ; goto out_bh; } +UDF_SET_FLAG (sb,UDF_FLAG_RW_INCOMPAT ); ret =udf_load_vat (sb, i, type1_idx);if (ret <0 ) goto out_bh;
@@ -2215,10 +2213,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) UDF_MAX_READ_VERSION); ret = -EINVAL ; goto error_out; - }else if (minUDFWriteRev >UDF_MAX_WRITE_VERSION && - !sb_rdonly (sb)) { - ret = -EACCES ; - goto error_out; + }else if (minUDFWriteRev >UDF_MAX_WRITE_VERSION ) { +if (!sb_rdonly (sb)) { + ret = -EACCES ; + goto error_out; + } +UDF_SET_FLAG (sb,UDF_FLAG_RW_INCOMPAT ); } sbi->s_udfrev = minUDFWriteRev;
@@ -2236,10 +2236,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) }if (sbi->s_partmaps[sbi->s_partition].s_partition_flags & -UDF_PART_FLAG_READ_ONLY && - !sb_rdonly (sb)) { - ret = -EACCES ; - goto error_out; +UDF_PART_FLAG_READ_ONLY ) { +if (!sb_rdonly (sb)) { + ret = -EACCES ; + goto error_out; + } +UDF_SET_FLAG (sb,UDF_FLAG_RW_INCOMPAT ); }if (udf_find_fileset (sb, &fileset, &rootdir)) {
fs/udf/udf_sb.h +2 -0
@@ -30,6 +30,8 @@#define UDF_FLAG_LASTBLOCK_SET 16#define UDF_FLAG_BLOCKSIZE_SET 17#define UDF_FLAG_INCONSISTENT 18 +#define UDF_FLAG_RW_INCOMPAT 19/* Set when we find RW incompatible +* feature */ #define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 44/45 ARM: dts: imx6ull: keep IMX6UL_ prefix for signals on both i.MX6UL and i.MX6ULL
In reply to Sasha LevinFrom: Sébastien Szymanski <[email protected]>
[ Upstream commit 31edaa6e7fd8143085a6a60c564447c07e76ed9f ]
Signals available on both i.MX6UL and i.MX6ULL should have the same name because it is the case of all others common signals, it avoids to make mistakes (use the wrong ones) and it makes writing device tree files less complicated. For example:
imx6ul-imx6ull-board.dtsi:
...
pinctrl_uart5: uart5grp {
fsl,pins = <
MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX 0x1b0b1
MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX 0x1b0b1 >;
};
imx6ul-board.dts:
#include <imx6ul.dtsi>
#include <imx6ul-imx6ull-board.dtsi>
...
imx6ull-board.dts:
#include <imx6ull.dtsi>
#include <imx6ul-imx6ull-board.dtsi>
...
Without this patch, the imx6ull-board.dtb will use MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX instead of MX6ULL_PAD_UART5_RX_DATA__UART5_DCE_RX and the uart5 will be misconfigured.
--- arch/arm/boot/dts/imx6ull-pinfunc.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
arch/arm/boot/dts/imx6ull-pinfunc.h +13 -5
@@ -14,14 +14,23 @@* The pin function ID is a tuple of * <mux_reg conf_reg input_reg mux_mode input_val> */ +/* signals common for i.MX6UL and i.MX6ULL */ +#undef MX6UL_PAD_UART5_TX_DATA__UART5_DTE_RX +#define MX6UL_PAD_UART5_TX_DATA__UART5_DTE_RX 0x00BC 0x0348 0x0644 0x0 0x6 +#undef MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX +#define MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX 0x00C0 0x034C 0x0644 0x0 0x7 +#undef MX6UL_PAD_ENET1_RX_EN__UART5_DCE_RTS +#define MX6UL_PAD_ENET1_RX_EN__UART5_DCE_RTS 0x00CC 0x0358 0x0640 0x1 0x5 +#undef MX6UL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS +#define MX6UL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS 0x00D0 0x035C 0x0640 0x1 0x6 +#undef MX6UL_PAD_CSI_DATA02__UART5_DCE_RTS +#define MX6UL_PAD_CSI_DATA02__UART5_DCE_RTS 0x01EC 0x0478 0x0640 0x8 0x7 + +/* signals for i.MX6ULL only */ #define MX6ULL_PAD_UART1_TX_DATA__UART5_DTE_RX 0x0084 0x0310 0x0644 0x9 0x4#define MX6ULL_PAD_UART1_RX_DATA__UART5_DCE_RX 0x0088 0x0314 0x0644 0x9 0x5#define MX6ULL_PAD_UART1_CTS_B__UART5_DCE_RTS 0x008C 0x0318 0x0640 0x9 0x3#define MX6ULL_PAD_UART1_RTS_B__UART5_DTE_RTS 0x0090 0x031C 0x0640 0x9 0x4 -#define MX6ULL_PAD_UART5_TX_DATA__UART5_DTE_RX 0x00BC 0x0348 0x0644 0x0 0x6 -#define MX6ULL_PAD_UART5_RX_DATA__UART5_DCE_RX 0x00C0 0x034C 0x0644 0x0 0x7 -#define MX6ULL_PAD_ENET1_RX_EN__UART5_DCE_RTS 0x00CC 0x0358 0x0640 0x1 0x5 -#define MX6ULL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS 0x00D0 0x035C 0x0640 0x1 0x6#define MX6ULL_PAD_ENET2_RX_DATA0__EPDC_SDDO08 0x00E4 0x0370 0x0000 0x9 0x0#define MX6ULL_PAD_ENET2_RX_DATA1__EPDC_SDDO09 0x00E8 0x0374 0x0000 0x9 0x0#define MX6ULL_PAD_ENET2_RX_EN__EPDC_SDDO10 0x00EC 0x0378 0x0000 0x9 0x0
@@ -55,7 +64,6 @@#define MX6ULL_PAD_CSI_DATA00__ESAI_TX_HF_CLK 0x01E4 0x0470 0x0000 0x9 0x0#define MX6ULL_PAD_CSI_DATA01__ESAI_RX_HF_CLK 0x01E8 0x0474 0x0000 0x9 0x0#define MX6ULL_PAD_CSI_DATA02__ESAI_RX_FS 0x01EC 0x0478 0x0000 0x9 0x0 -#define MX6ULL_PAD_CSI_DATA02__UART5_DCE_RTS 0x01EC 0x0478 0x0640 0x8 0x7#define MX6ULL_PAD_CSI_DATA03__ESAI_RX_CLK 0x01F0 0x047C 0x0000 0x9 0x0#define MX6ULL_PAD_CSI_DATA04__ESAI_TX_FS 0x01F4 0x0480 0x0000 0x9 0x0#define MX6ULL_PAD_CSI_DATA05__ESAI_TX_CLK 0x01F8 0x0484 0x0000 0x9 0x0
Signature · 1 line
2.17.1
Sasha Levin
maintainerPATCH 45/45 9p: clear dangling pointers in p9stat_free
In reply to Sasha LevinFrom: Dominique Martinet <[email protected]>
[ Upstream commit 62e3941776fea8678bb8120607039410b1b61a65 ]
p9stat_free is more of a cleanup function than a 'free' function as it only frees the content of the struct; there are chances of use-after-free if it is improperly used (e.g. p9stat_free called twice as it used to be possible to)
Clearing dangling pointers makes the function idempotent and safer to use.
--- net/9p/protocol.c | 5 +++++ 1 file changed, 5 insertions(+)
net/9p/protocol.c +5 -0
@@ -46,10 +46,15 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);void p9stat_free (struct p9_wstat *stbuf) {kfree (stbuf->name); + stbuf->name =NULL ;kfree (stbuf->uid); + stbuf->uid =NULL ;kfree (stbuf->gid); + stbuf->gid =NULL ;kfree (stbuf->muid); + stbuf->muid =NULL ;kfree (stbuf->extension); + stbuf->extension =NULL ; }EXPORT_SYMBOL (p9stat_free);
Signature · 1 line
2.17.1