6.1.24-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 133/164 drm/panfrost: Fix the panfrost_mmu_map_fault_addr() error path
In reply to Greg Kroah-HartmanFrom: Boris Brezillon <[email protected]>
commit 764a2ab9eb56e1200083e771aab16186836edf1d upstream.
Make sure all bo->base.pages entries are either NULL or pointing to a valid page before calling drm_gem_shmem_put_pages().
--- drivers/gpu/drm/panfrost/panfrost_mmu.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/panfrost/panfrost_mmu.c +1 -0
@@ -504,6 +504,7 @@ static int panfrost_mmu_map_fault_addr(sif (IS_ERR (pages[i])) {mutex_unlock (&bo->base.pages_lock); ret =PTR_ERR (pages[i]); + pages[i] =NULL ; goto err_pages; } }
Greg Kroah-Hartman
maintainerPATCH 134/164 drm/nouveau/disp: Support more modes by checking with lower bpc
In reply to Greg Kroah-HartmanFrom: Karol Herbst <[email protected]>
commit 7f67aa097e875c87fba024e850cf405342300059 upstream.
This allows us to advertise more modes especially on HDR displays.
Fixes using 4K@60 modes on my TV and main display both using a HDMI to DP adapter. Also fixes similar issues for users running into this.
--- drivers/gpu/drm/nouveau/dispnv50/disp.c | 32 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_dp.c | 8 +++++--- 2 files changed, 37 insertions(+), 3 deletions(-)
drivers/gpu/drm/nouveau/dispnv50/disp.c +32 -0
@@ -410,6 +410,35 @@ nv50_outp_atomic_check_view(struct drm_ereturn 0 ; } +static void +nv50_outp_atomic_fix_depth (struct drm_encoder *encoder,struct drm_crtc_state *crtc_state) +{ +struct nv50_head_atom *asyh =nv50_head_atom (crtc_state); +struct nouveau_encoder *nv_encoder =nouveau_encoder (encoder); +struct drm_display_mode *mode = &asyh->state.adjusted_mode; +unsigned int max_rate, mode_rate; + +switch (nv_encoder->dcb->type) { +case DCB_OUTPUT_DP : + max_rate = nv_encoder->dp.link_nr * nv_encoder->dp.link_bw; + +/* we don't support more than 10 anyway */ + asyh->or.bpc =min_t (u8, asyh->or.bpc,10 ); + +/* reduce the bpc until it works out */ +while (asyh->or.bpc >6 ) { + mode_rate =DIV_ROUND_UP (mode->clock * asyh->or.bpc *3 ,8 ); +if (mode_rate <= max_rate) +break ; + + asyh->or.bpc -=2 ; + } +break ; +default : +break ; + } +} + static int nv50_outp_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state,
@@ -428,6 +457,9 @@ nv50_outp_atomic_check(struct drm_encodeif (crtc_state->mode_changed || crtc_state->connectors_changed) asyh->or.bpc = connector->display_info.bpc; +/* We might have to reduce the bpc */ +nv50_outp_atomic_fix_depth (encoder, crtc_state); +return 0 ; }
drivers/gpu/drm/nouveau/nouveau_dp.c +5 -3
@@ -245,8 +245,6 @@ void nouveau_dp_irq(struct nouveau_drm * }/* TODO: -* - Use the minimum possible BPC here, once we add support for the max bpc -* property. * - Validate against the DP caps advertised by the GPU (we don't check these * yet) */
@@ -258,7 +256,11 @@ nv50_dp_mode_valid(struct drm_connector {const unsigned int min_clock =25000 ;unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock; -const u8 bpp = connector->display_info.bpc *3 ; +/* Check with the minmum bpc always, so we can advertise better modes. +* In particlar not doing this causes modes to be dropped on HDR +* displays as we might check with a bpc of 16 even. +*/ +const u8 bpp =6 *3 ;if (mode->flags &DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace)return MODE_NO_INTERLACE ;
Greg Kroah-Hartman
maintainerPATCH 135/164 drm/i915: Fix context runtime accounting
In reply to Greg Kroah-HartmanFrom: Tvrtko Ursulin <[email protected]>
commit dc3421560a67361442f33ec962fc6dd48895a0df upstream.
When considering whether to mark one context as stopped and another as started we need to look at whether the previous and new _contexts_ are different and not just requests. Otherwise the software tracked context start time was incorrectly updated to the most recent lite-restore time- stamp, which was in some cases resulting in active time going backward, until the context switch (typically the heartbeat pulse) would synchronise with the hardware tracked context runtime. Easiest use case to observe this behaviour was with a full screen clients with close to 100% engine load.
--- drivers/gpu/drm/i915/gt/intel_execlists_submission.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/gt/intel_execlists_submission.c +10 -2
@@ -2017,6 +2017,8 @@ process_csb(struct intel_engine_cs *engi* inspecting the queue to see if we need to resumbit. */ if (*prev != *execlists->active) {/* elide lite-restores */ +struct intel_context *prev_ce =NULL , *active_ce =NULL ; +/* * Note the inherent discrepancy between the HW runtime, * recorded as part of the context switch, and the CPU
@@ -2028,9 +2030,15 @@ process_csb(struct intel_engine_cs *engi* and correct overselves later when updating from HW. */ if (*prev) -lrc_runtime_stop ((*prev)->context); + prev_ce = (*prev)->context;if (*execlists->active) -lrc_runtime_start ((*execlists->active)->context); + active_ce = (*execlists->active)->context; +if (prev_ce != active_ce) { +if (prev_ce) +lrc_runtime_stop (prev_ce); +if (active_ce) +lrc_runtime_start (active_ce); + }new_timeslice (execlists); }
Greg Kroah-Hartman
maintainerPATCH 136/164 drm/i915: fix race condition UAF in i915_perf_add_config_ioctl
In reply to Greg Kroah-HartmanFrom: Min Li <[email protected]>
commit dc30c011469165d57af9adac5baff7d767d20e5c upstream.
Userspace can guess the id value and try to race oa_config object creation with config remove, resulting in a use-after-free if we dereference the object after unlocking the metrics_lock. For that reason, unlocking the metrics_lock must be done after we are done dereferencing the object.
--- drivers/gpu/drm/i915/i915_perf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_perf.c +3 -3
@@ -4270,13 +4270,13 @@ int i915_perf_add_config_ioctl(struct dr err = oa_config->id; goto sysfs_err; } - -mutex_unlock (&perf->metrics_lock); + id = oa_config->id;drm_dbg (&perf->i915->drm,"Added config %s id=%i\n" , oa_config->uuid, oa_config->id); +mutex_unlock (&perf->metrics_lock); -return oa_config->id; +return id; sysfs_err:mutex_unlock (&perf->metrics_lock);
Greg Kroah-Hartman
maintainerPATCH 137/164 ring-buffer: Fix race while reader and writer are on the same page
In reply to Greg Kroah-HartmanFrom: Zheng Yejian <[email protected]>
commit 6455b6163d8c680366663cdb8c679514d55fc30c upstream.
When user reads file 'trace_pipe', kernel keeps printing following logs that warn at "cpu_buffer->reader_page->read > rb_page_size(reader)" in rb_get_reader_page(). It just looks like there's an infinite loop in tracing_read_pipe(). This problem occurs several times on arm64 platform when testing v5.10 and below.
Call trace: rb_get_reader_page+0x248/0x1300 rb_buffer_peek+0x34/0x160 ring_buffer_peek+0xbc/0x224 peek_next_entry+0x98/0xbc __find_next_entry+0xc4/0x1c0 trace_find_next_entry_inc+0x30/0x94 tracing_read_pipe+0x198/0x304 vfs_read+0xb4/0x1e0 ksys_read+0x74/0x100 __arm64_sys_read+0x24/0x30 el0_svc_common.constprop.0+0x7c/0x1bc do_el0_svc+0x2c/0x94 el0_svc+0x20/0x30 el0_sync_handler+0xb0/0xb4 el0_sync+0x160/0x180
Then I dump the vmcore and look into the problematic per_cpu ring_buffer, I found that tail_page/commit_page/reader_page are on the same page while reader_page->read is obviously abnormal:
tail_page == commit_page == reader_page == {
.write = 0x100d20,
.read = 0x8f9f4805, // Far greater than 0xd20, obviously abnormal!!!
.entries = 0x10004c,
.real_end = 0x0,
.page = {
.time_stamp = 0x857257416af0,
.commit = 0xd20, // This page hasn't been full filled.
// .data[0...0xd20] seems normal.
}}
The root cause is most likely the race that reader and writer are on the same page while reader saw an event that not fully committed by writer.
To fix this, add memory barriers to make sure the reader can see the content of what is committed. Since commit a0fcaaed0c46 ("ring-buffer: Fix race between reset page and reading page") has added the read barrier in rb_get_reader_page(), here we just need to add the write barrier.
--- kernel/trace/ring_buffer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +12 -1
@@ -3084,6 +3084,10 @@ rb_set_commit_to_write(struct ring_buffeif (RB_WARN_ON (cpu_buffer,rb_is_reader_page (cpu_buffer->tail_page)))return ; +/* +* No need for a memory barrier here, as the update +* of the tail_page did it for this page. +*/ local_set (&cpu_buffer->commit_page->page->commit,rb_page_write (cpu_buffer->commit_page));rb_inc_page (&cpu_buffer->commit_page);
@@ -3093,6 +3097,8 @@ rb_set_commit_to_write(struct ring_buffewhile (rb_commit_index (cpu_buffer) !=rb_page_write (cpu_buffer->commit_page)) { +/* Make sure the readers see the content of what is committed. */ +smp_wmb ();local_set (&cpu_buffer->commit_page->page->commit,rb_page_write (cpu_buffer->commit_page)); RB_WARN_ON(cpu_buffer,
@@ -4672,7 +4678,12 @@ rb_get_reader_page(struct ring_buffer_pe/* * Make sure we see any padding after the write update -* (see rb_reset_tail()) +* (see rb_reset_tail()). +* +* In addition, a writer may be writing on the reader page +* if the page has not been fully filled, so the read barrier +* is also needed to make sure we see the content of what is +* committed by the writer (see rb_set_commit_to_write()). */ smp_rmb ();
Greg Kroah-Hartman
maintainerPATCH 138/164 mm/swap: fix swap_info_struct race between swapoff and get_swap_pages()
In reply to Greg Kroah-HartmanFrom: Rongwei Wang <[email protected]>
commit 6fe7d6b992113719e96744d974212df3fcddc76c upstream.
The si->lock must be held when deleting the si from the available list. Otherwise, another thread can re-add the si to the available list, which can lead to memory corruption. The only place we have found where this happens is in the swapoff path. This case can be described as below:
core 0 core 1
swapoff
del_from_avail_list(si) waiting
try lock si->lock acquire swap_avail_lock
and re-add si into
swap_avail_head
acquire si->lock but missing si already being added again, and continuing to clear SWP_WRITEOK, etc.
It can be easily found that a massive warning messages can be triggered inside get_swap_pages() by some special cases, for example, we call madvise(MADV_PAGEOUT) on blocks of touched memory concurrently, meanwhile, run much swapon-swapoff operations (e.g. stress-ng-swap).
However, in the worst case, panic can be caused by the above scene. In swapoff(), the memory used by si could be kept in swap_info[] after turning off a swap. This means memory corruption will not be caused immediately until allocated and reset for a new swap in the swapon path. A panic message caused: (with CONFIG_PLIST_DEBUG enabled)
------------[ cut here ]------------ top: 00000000e58a3003, n: 0000000013e75cda, p: 000000008cd4451a prev: 0000000035b1e58a, n: 000000008cd4451a, p: 000000002150ee8d next: 000000008cd4451a, n: 000000008cd4451a, p: 000000008cd4451a WARNING: CPU: 21 PID: 1843 at lib/plist.c:60 plist_check_prev_next_node+0x50/0x70 Modules linked in: rfkill(E) crct10dif_ce(E)... CPU: 21 PID: 1843 Comm: stress-ng Kdump: ... 5.10.134+ Hardware name: Alibaba Cloud ECS, BIOS 0.0.0 02/06/2015 pstate: 60400005 (nZCv daif +PAN -UAO -TCO BTYPE=--) pc : plist_check_prev_next_node+0x50/0x70 lr : plist_check_prev_next_node+0x50/0x70
sp : ffff0018009d3c30
x29: ffff0018009d3c40 x28: ffff800011b32a98
x27: 0000000000000000 x26: ffff001803908000
x25: ffff8000128ea088 x24: ffff800011b32a48
x23: 0000000000000028 x22: ffff001800875c00
x21: ffff800010f9e520 x20: ffff001800875c00
x19: ffff001800fdc6e0 x18: 0000000000000030
x17: 0000000000000000 x16: 0000000000000000
x15: 0736076307640766 x14: 0730073007380731
x13: 0736076307640766 x12: 0730073007380731
x11: 000000000004058d x10: 0000000085a85b76
x9 : ffff8000101436e4 x8 : ffff800011c8ce08
x7 : 0000000000000000 x6 : 0000000000000001
x5 : ffff0017df9ed338 x4 : 0000000000000001
x3 : ffff8017ce62a000 x2 : ffff0017df9ed340
x1 : 0000000000000000 x0 : 0000000000000000
Call trace: plist_check_prev_next_node+0x50/0x70 plist_check_head+0x80/0xf0 plist_add+0x28/0x140 add_to_avail_list+0x9c/0xf0 _enable_swap_info+0x78/0xb4 __do_sys_swapon+0x918/0xa10 __arm64_sys_swapon+0x20/0x30 el0_svc_common+0x8c/0x220 do_el0_svc+0x2c/0x90 el0_svc+0x1c/0x30 el0_sync_handler+0xa8/0xb0 el0_sync+0x148/0x180 irq event stamp: 2082270
Now, si->lock locked before calling 'del_from_avail_list()' to make sure other thread see the si had been deleted and SWP_WRITEOK cleared together, will not reinsert again.
This problem exists in versions after stable 5.10.y.
--- mm/swapfile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/swapfile.c +2 -1
@@ -679,6 +679,7 @@ static void __del_from_avail_list(struct {int nid; +assert_spin_locked (&p->lock);for_each_node (nid)plist_del (&p->avail_lists[nid], &swap_avail_heads[nid]); }
@@ -2428,8 +2429,8 @@ SYSCALL_DEFINE1(swapoff, const char __usspin_unlock (&swap_lock); goto out_dput; } -del_from_avail_list (p);spin_lock (&p->lock); +del_from_avail_list (p);if (p->prio <0 ) {struct swap_info_struct *si = p;int nid;
Greg Kroah-Hartman
maintainerPATCH 139/164 mm/hugetlb: fix uffd wr-protection for CoW optimization path
In reply to Greg Kroah-HartmanFrom: Peter Xu <[email protected]>
commit 60d5b473d61be61ac315e544fcd6a8234a79500e upstream.
This patch fixes an issue that a hugetlb uffd-wr-protected mapping can be writable even with uffd-wp bit set. It only happens with hugetlb private mappings, when someone firstly wr-protects a missing pte (which will install a pte marker), then a write to the same page without any prior access to the page.
Userfaultfd-wp trap for hugetlb was implemented in hugetlb_fault() before reaching hugetlb_wp() to avoid taking more locks that userfault won't need. However there's one CoW optimization path that can trigger hugetlb_wp() inside hugetlb_no_page(), which will bypass the trap.
This patch skips hugetlb_wp() for CoW and retries the fault if uffd-wp bit is detected. The new path will only trigger in the CoW optimization path because generic hugetlb_fault() (e.g. when a present pte was wr-protected) will resolve the uffd-wp bit already. Also make sure anonymous UNSHARE won't be affected and can still be resolved, IOW only skip CoW not CoR.
This patch will be needed for v5.19+ hence copy stable.
--- mm/hugetlb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
mm/hugetlb.c +12 -2
@@ -5469,7 +5469,7 @@ static vm_fault_t hugetlb_wp(struct mm_s struct page *pagecache_page, spinlock_t *ptl) { const bool unshare = flags & FAULT_FLAG_UNSHARE; -pte_t pte; +pte_t pte =huge_ptep_get (ptep);struct hstate *h =hstate_vma (vma);struct page *old_page, *new_page;int outside_reserve =0 ;
@@ -5481,6 +5481,17 @@ static vm_fault_t hugetlb_wp(struct mm_sVM_BUG_ON (!unshare && !(flags &FOLL_WRITE ));/* +* Never handle CoW for uffd-wp protected pages. It should be only +* handled when the uffd-wp protection is removed. +* +* Note that only the CoW optimization path (in hugetlb_no_page()) +* can trigger this, because hugetlb_fault() will always resolve +* uffd-wp bit first. +*/ +if (!unshare &&huge_pte_uffd_wp (pte)) +return 0 ; + +/* * hugetlb does not support FOLL_FORCE-style write faults that keep the * PTE mapped R/O such as maybe_mkwrite() would do. */
@@ -5495,7 +5506,6 @@ static vm_fault_t hugetlb_wp(struct mm_sreturn 0 ; } - pte =huge_ptep_get (ptep); old_page =pte_page (pte);delayacct_wpcopy_start ();
Greg Kroah-Hartman
maintainerPATCH 140/164 maple_tree: fix get wrong data_end in mtree_lookup_walk()
In reply to Greg Kroah-HartmanFrom: Peng Zhang <[email protected]>
commit ec07967d7523adb3670f9dfee0232e3bc868f3de upstream.
if (likely(offset > end))
max = pivots[offset];
The above code should be changed to if (likely(offset < end)), which is correct. This affects the correctness of ma_data_end(). Now it seems that the final result will not be wrong, but it is best to change it. This patch does not change the code as above, because it simplifies the code by the way.
--- lib/maple_tree.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-)
lib/maple_tree.c +5 -10
@@ -3870,18 +3870,13 @@ static inline void *mtree_lookup_walk(st end =ma_data_end (node, type, pivots, max);if (unlikely (ma_dead_node (node))) goto dead_node; - -if (pivots[offset] >= mas->index) - goto next; -do { - offset++; - }while ((offset < end) && (pivots[offset] < mas->index)); - -if (likely (offset > end)) - max = pivots[offset]; +if (pivots[offset] >= mas->index) { + max = pivots[offset]; +break ; + } + }while (++offset < end); -next: slots =ma_slots (node, type); next =mt_slot (mas->tree, slots, offset);if (unlikely (ma_dead_node (node)))
Greg Kroah-Hartman
maintainerPATCH 141/164 maple_tree: fix a potential concurrency bug in RCU mode
In reply to Greg Kroah-HartmanFrom: Peng Zhang <[email protected]>
commit c45ea315a602d45569b08b93e9ab30f6a63a38aa upstream.
There is a concurrency bug that may cause the wrong value to be loaded when a CPU is modifying the maple tree.
CPU1:mtree_insert_range()
mas_insert()
mas_store_root()
...
mas_root_expand()
...
rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node));
ma_set_meta(node, maple_leaf_64, 0, slot); <---IPCPU2:mtree_load()
mtree_lookup_walk()
ma_data_end();
When CPU1 is about to execute the instruction pointed to by IP, the ma_data_end() executed by CPU2 may return the wrong end position, which will cause the value loaded by mtree_load() to be wrong.
An example of triggering the bug:
Add mdelay(100) between rcu_assign_pointer() and ma_set_meta() in mas_root_expand().
static DEFINE_MTREE(tree);
int work(void *p) {
unsigned long val;
for (int i = 0 ; i< 30; ++i) {
val = (unsigned long)mtree_load(&tree, 8);
mdelay(5);
pr_info("%lu",val);
}
return 0;
}mt_init_flags(&tree, MT_FLAGS_USE_RCU);mtree_insert(&tree, 0, (void*)12345, GFP_KERNEL);run_thread(work)mtree_insert(&tree, 1, (void*)56789, GFP_KERNEL);
In RCU mode, mtree_load() should always return the value before or after the data structure is modified, and in this example mtree_load(&tree, 8) may return 56789 which is not expected, it should always return NULL. Fix it by put ma_set_meta() before rcu_assign_pointer().
--- lib/maple_tree.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
lib/maple_tree.c +1 -2
@@ -3654,10 +3654,9 @@ static inline int mas_root_expand(struct slot++; mas->depth =1 ;mas_set_height (mas); - +ma_set_meta (node, maple_leaf_64,0 , slot);/* swap the new root into the tree */ rcu_assign_pointer (mas->tree->ma_root,mte_mk_root (mas->node)); -ma_set_meta (node, maple_leaf_64,0 , slot);return slot; }
Greg Kroah-Hartman
maintainerPATCH 142/164 blk-throttle: Fix that bps of child could exceed bps limited in parent
In reply to Greg Kroah-HartmanFrom: Kemeng Shi <[email protected]>
commit 84aca0a7e039c8735abc0f89f3f48e9006c0dfc7 upstream.
Consider situation as following (on the default hierarchy):
HDD
|
root (bps limit: 4k)
|
child (bps limit :8k)
|
fio bs=8k
Rate of fio is supposed to be 4k, but result is 8k. Reason is as following:
Size of single IO from fio is larger than bytes allowed in one throtl_slice in child, so IOs are always queued in child group first. When queued IOs in child are dispatched to parent group, BIO_BPS_THROTTLED is set and these IOs will not be limited by tg_within_bps_limit anymore. Fix this by only set BIO_BPS_THROTTLED when the bio traversed the entire tree.
There patch has no influence on situation which is not on the default hierarchy as each group is a single root group without parent.
--- block/blk-throttle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/blk-throttle.c +1 -1
@@ -1066,7 +1066,6 @@ static void tg_dispatch_one_bio(struct t sq->nr_queued[rw]--;throtl_charge_bio (tg, bio); -bio_set_flag (bio,BIO_BPS_THROTTLED );/* * If our parent is another tg, we just need to transfer @bio to
@@ -1079,6 +1078,7 @@ static void tg_dispatch_one_bio(struct tthrotl_add_bio_tg (bio, &tg->qnode_on_parent[rw], parent_tg);start_parent_slice_with_credit (tg, parent_tg, rw); }else { +bio_set_flag (bio,BIO_BPS_THROTTLED );throtl_qnode_add_bio (bio, &tg->qnode_on_parent[rw], &parent_sq->queued[rw]);BUG_ON (tg->td->nr_queued[rw] <=0 );
Greg Kroah-Hartman
maintainerPATCH 143/164 drm/amd/display: Clear MST topology if it fails to resume
In reply to Greg Kroah-HartmanFrom: Roman Li <[email protected]>
commit 3f6752b4de41896c7f1609b1585db2080e8150d8 upstream.
[Why]
In case of failure to resume MST topology after suspend, an emtpty mst tree prevents further mst hub detection on the same connector. That causes the issue with MST hub hotplug after it's been unplug in suspend.
[How]
Stop topology manager on the connector after detecting DM_MST failure.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -0
@@ -2175,6 +2175,8 @@ static int detect_mst_link_for_all_conneDRM_ERROR ("DM_MST: Failed to start MST\n" ); aconnector->dc_link->type = dc_connection_single; + ret =dm_helpers_dp_mst_stop_top_mgr (aconnector->dc_link->ctx, + aconnector->dc_link);break ; } }
Greg Kroah-Hartman
maintainerPATCH 144/164 drm/amdgpu: for S0ix, skip SDMA 5.x+ suspend/resume
In reply to Greg Kroah-HartmanFrom: Alex Deucher <[email protected]>
commit 2a7798ea7390fd78f191c9e9bf68f5581d3b4a02 upstream.
SDMA 5.x is part of the GFX block so it's controlled via GFXOFF. Skip suspend as it should be handled the same as GFX.
v2: drop SDMA 4.x. That requires special handling.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +6 -0
@@ -3034,6 +3034,12 @@ static int amdgpu_device_ip_suspend_phas adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_MES))continue ; +/* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */ +if (adev->in_s0ix && + (adev->ip_versions[SDMA0_HWIP ][0 ] >=IP_VERSION (5 ,0 ,0 )) && + (adev->ip_blocks[i].version->type ==AMD_IP_BLOCK_TYPE_SDMA )) +continue ; +/* XXX handle errors */ r = adev->ip_blocks[i].version->funcs->suspend (adev);/* XXX handle errors */
Greg Kroah-Hartman
maintainerPATCH 145/164 drm/amdgpu: skip psp suspend for IMU enabled ASICs mode2 reset
In reply to Greg Kroah-HartmanFrom: Tim Huang <[email protected]>
commit e11c775030c5585370fda43035204bb5fa23b139 upstream.
The psp suspend & resume should be skipped to avoid destroy the TMR and reload FWs again for IMU enabled APU ASICs.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +12 -0
@@ -3040,6 +3040,18 @@ static int amdgpu_device_ip_suspend_phas (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; +/* Once swPSP provides the IMU, RLC FW binaries to TOS during cold-boot. +* These are in TMR, hence are expected to be reused by PSP-TOS to reload +* from this location and RLC Autoload automatically also gets loaded +* from here based on PMFW -> PSP message during re-init sequence. +* Therefore, the psp suspend & resume should be skipped to avoid destroy +* the TMR and reload FWs again for IMU enabled APU ASICs. +*/ +if (amdgpu_in_reset (adev) && + (adev->flags &AMD_IS_APU ) && adev->gfx.imu.funcs && + adev->ip_blocks[i].version->type ==AMD_IP_BLOCK_TYPE_PSP ) +continue ; +/* XXX handle errors */ r = adev->ip_blocks[i].version->funcs->suspend (adev);/* XXX handle errors */
Greg Kroah-Hartman
maintainerPATCH 146/164 drm/display/dp_mst: Handle old/new payload states in drm_dp_remove_payload()
In reply to Greg Kroah-HartmanFrom: Imre Deak <[email protected]>
commit e761cc20946a0094df71cb31a565a6a0d03bd8be upstream.
Atm, drm_dp_remove_payload() uses the same payload state to both get the vc_start_slot required for the payload removal DPCD message and to deduct time_slots from vc_start_slot of all payloads after the one being removed.
The above isn't always correct, as vc_start_slot must be the up-to-date version contained in the new payload state, but time_slots must be the one used when the payload was previously added, contained in the old payload state. The new payload's time_slots can change vs. the old one if the current atomic commit changes the corresponding mode.
This patch let's drivers pass the old and new payload states to drm_dp_remove_payload(), but keeps these the same for now in all drivers not to change the behavior. A follow-up i915 patch will pass in that driver the correct old and new states to the function.
Hand modified for missing 8c7d980da9ba3eb67a1b40fd4b33bcf49397084b
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 - drivers/gpu/drm/display/drm_dp_mst_topology.c | 26 +++++++------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 - include/drm/display/drm_dp_mst_helper.h | 3 + 5 files changed, 21 insertions(+), 16 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +1 -1
@@ -206,7 +206,7 @@ bool dm_helpers_dp_mst_write_payload_allif (enable)drm_dp_add_payload_part1 (mst_mgr, mst_state, payload);else -drm_dp_remove_payload (mst_mgr, mst_state, payload); +drm_dp_remove_payload (mst_mgr, mst_state, payload, payload);/* mst_mgr->->payloads are VC payload notify MST branch using DPCD or * AUX message. The sequence is slot 1-63 allocated sequence for each
drivers/gpu/drm/display/drm_dp_mst_topology.c +14 -12
@@ -3342,7 +3342,8 @@ EXPORT_SYMBOL(drm_dp_add_payload_part1);* drm_dp_remove_payload() - Remove an MST payload * @mgr: Manager to use. * @mst_state: The MST atomic state -* @payload: The payload to write +* @old_payload: The payload with its old state +* @new_payload: The payload to write * * Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates * the starting time slots of all other payloads which would have been shifted towards the start of
@@ -3350,36 +3351,37 @@ EXPORT_SYMBOL(drm_dp_add_payload_part1);*/ void drm_dp_remove_payload (struct drm_dp_mst_topology_mgr *mgr,struct drm_dp_mst_topology_state *mst_state, -struct drm_dp_mst_atomic_payload *payload) +const struct drm_dp_mst_atomic_payload *old_payload, +struct drm_dp_mst_atomic_payload *new_payload) {struct drm_dp_mst_atomic_payload *pos;bool send_remove = false;/* We failed to make the payload, so nothing to do */ -if (payload->vc_start_slot ==-1 ) +if (new_payload->vc_start_slot ==-1 )return ;mutex_lock (&mgr->lock); - send_remove =drm_dp_mst_port_downstream_of_branch (payload->port, mgr->mst_primary); + send_remove =drm_dp_mst_port_downstream_of_branch (new_payload->port, mgr->mst_primary);mutex_unlock (&mgr->lock);if (send_remove) -drm_dp_destroy_payload_step1 (mgr, mst_state, payload); +drm_dp_destroy_payload_step1 (mgr, mst_state, new_payload);else drm_dbg_kms (mgr->dev,"Payload for VCPI %d not in topology, not sending remove\n" , - payload->vcpi); + new_payload->vcpi);list_for_each_entry (pos, &mst_state->payloads, next) { -if (pos != payload && pos->vc_start_slot > payload->vc_start_slot) - pos->vc_start_slot -= payload->time_slots; +if (pos != new_payload && pos->vc_start_slot > new_payload->vc_start_slot) + pos->vc_start_slot -= old_payload->time_slots; } - payload->vc_start_slot =-1 ; + new_payload->vc_start_slot =-1 ; mgr->payload_count--; - mgr->next_start_slot -= payload->time_slots; + mgr->next_start_slot -= old_payload->time_slots; -if (payload->delete) -drm_dp_mst_put_port_malloc (payload->port); +if (new_payload->delete) +drm_dp_mst_put_port_malloc (new_payload->port); }EXPORT_SYMBOL (drm_dp_remove_payload);
drivers/gpu/drm/i915/display/intel_dp_mst.c +3 -1
@@ -366,6 +366,8 @@ static void intel_mst_disable_dp(structto_intel_connector (old_conn_state->connector);struct drm_dp_mst_topology_state *mst_state =drm_atomic_get_mst_topology_state (&state->base, &intel_dp->mst_mgr); +struct drm_dp_mst_atomic_payload *payload = +drm_atomic_get_mst_payload_state (mst_state, connector->port);struct drm_i915_private *i915 =to_i915 (connector->base.dev); drm_dbg_kms(&i915->drm, "active links %d\n",
@@ -374,7 +376,7 @@ static void intel_mst_disable_dp(structintel_hdcp_disable (intel_mst->connector);drm_dp_remove_payload (&intel_dp->mst_mgr, mst_state, -drm_atomic_get_mst_payload_state (mst_state, connector->port)); + payload, payload);intel_audio_codec_disable (encoder, old_crtc_state, old_conn_state); }
drivers/gpu/drm/nouveau/dispnv50/disp.c +1 -1
@@ -1028,7 +1028,7 @@ nv50_msto_prepare(struct drm_atomic_stat// TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? if (msto->disabled) { -drm_dp_remove_payload (mgr, mst_state, payload); +drm_dp_remove_payload (mgr, mst_state, payload, payload); }else {if (msto->enabled)drm_dp_add_payload_part1 (mgr, mst_state, payload);
include/drm/display/drm_dp_mst_helper.h +2 -1
@@ -841,7 +841,8 @@ int drm_dp_add_payload_part2(struct drm_ struct drm_dp_mst_atomic_payload *payload);void drm_dp_remove_payload (struct drm_dp_mst_topology_mgr *mgr,struct drm_dp_mst_topology_state *mst_state, -struct drm_dp_mst_atomic_payload *payload); +const struct drm_dp_mst_atomic_payload *old_payload, +struct drm_dp_mst_atomic_payload *new_payload);int drm_dp_check_act_status (struct drm_dp_mst_topology_mgr *mgr);
Greg Kroah-Hartman
maintainerPATCH 147/164 drm/i915/dp_mst: Fix payload removal during output disabling
In reply to Greg Kroah-HartmanFrom: Imre Deak <[email protected]>
commit eb50912ec931913e70640cecf75cb993fd26995f upstream.
Use the correct old/new topology and payload states in intel_mst_disable_dp(). So far drm_atomic_get_mst_topology_state() it used returned either the old state, in case the state was added already earlier during the atomic check phase or otherwise the new state (but the latter could fail, which can't be handled in the enable/disable hooks). After the first patch in the patchset, the state should always get added already during the check phase, so here we can get the old/new states without a failure.
drm_dp_remove_payload() should use time_slots from the old payload state and vc_start_slot in the new one. It should update the new payload states to reflect the sink's current payload table after the payload is removed. Pass the new topology state and the old and new payload states accordingly.
This also fixes a problem where the payload allocations for multiple MST streams on the same link got inconsistent after a few commits, as during payload removal the old instead of the new payload state got updated, so the subsequent enabling sequence and commits used a stale payload state.
v2: Constify the old payload state pointer. (Ville)
--- drivers/gpu/drm/i915/display/intel_dp_mst.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/gpu/drm/i915/display/intel_dp_mst.c +10 -6
@@ -364,10 +364,14 @@ static void intel_mst_disable_dp(structstruct intel_dp *intel_dp = &dig_port->dp;struct intel_connector *connector =to_intel_connector (old_conn_state->connector); -struct drm_dp_mst_topology_state *mst_state = -drm_atomic_get_mst_topology_state (&state->base, &intel_dp->mst_mgr); -struct drm_dp_mst_atomic_payload *payload = -drm_atomic_get_mst_payload_state (mst_state, connector->port); +struct drm_dp_mst_topology_state *old_mst_state = +drm_atomic_get_old_mst_topology_state (&state->base, &intel_dp->mst_mgr); +struct drm_dp_mst_topology_state *new_mst_state = +drm_atomic_get_new_mst_topology_state (&state->base, &intel_dp->mst_mgr); +const struct drm_dp_mst_atomic_payload *old_payload = +drm_atomic_get_mst_payload_state (old_mst_state, connector->port); +struct drm_dp_mst_atomic_payload *new_payload = +drm_atomic_get_mst_payload_state (new_mst_state, connector->port);struct drm_i915_private *i915 =to_i915 (connector->base.dev); drm_dbg_kms(&i915->drm, "active links %d\n",
@@ -375,8 +379,8 @@ static void intel_mst_disable_dp(structintel_hdcp_disable (intel_mst->connector); -drm_dp_remove_payload (&intel_dp->mst_mgr, mst_state, - payload, payload); +drm_dp_remove_payload (&intel_dp->mst_mgr, new_mst_state, + old_payload, new_payload);intel_audio_codec_disable (encoder, old_crtc_state, old_conn_state); }
Greg Kroah-Hartman
maintainerPATCH 148/164 drm/bridge: lt9611: Fix PLL being unable to lock
In reply to Greg Kroah-HartmanFrom: Robert Foss <[email protected]>
commit 2a9df204be0bbb896e087f00b9ee3fc559d5a608 upstream.
This fixes PLL being unable to lock, and is derived from an equivalent downstream commit.
Available LT9611 documentation does not list this register, neither does LT9611UXC (which is a different chip).
This commit has been confirmed to fix HDMI output on DragonBoard 845c.
--- drivers/gpu/drm/bridge/lontium-lt9611.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/bridge/lontium-lt9611.c +1 -0
@@ -258,6 +258,7 @@ static int lt9611_pll_setup(struct lt961 { 0x8126, 0x55 }, { 0x8127, 0x66 }, { 0x8128, 0x88 }, + { 0x812a, 0x20 }, };regmap_multi_reg_write (lt9611->regmap, reg_cfg,ARRAY_SIZE (reg_cfg));
Greg Kroah-Hartman
maintainerPATCH 149/164 drm/i915: Use _MMIO_PIPE() for SKL_BOTTOM_COLOR
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit 05ca98523481aa687c5a8dce8939fec539632153 upstream.
No need to use _MMIO_PIPE2() for SKL_BOTTOM_COLOR since all pipe registers are evenly spread on skl+. Switch to _MMIO_PIPE() and thus avoid the hidden dev_priv.
--- drivers/gpu/drm/i915/i915_reg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/i915_reg.h +2 -1
@@ -3747,9 +3747,10 @@/* Skylake+ pipe bottom (background) color */ #define _SKL_BOTTOM_COLOR_A 0x70034 +#define _SKL_BOTTOM_COLOR_B 0x71034#define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31)#define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) -#define SKL_BOTTOM_COLOR (pipe) _MMIO_PIPE2(pipe, _SKL_BOTTOM_COLOR_A) +#define SKL_BOTTOM_COLOR (pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B)#define _ICL_PIPE_A_STATUS 0x70058#define ICL_PIPESTATUS (pipe) _MMIO_PIPE2(pipe, _ICL_PIPE_A_STATUS)
Greg Kroah-Hartman
maintainerPATCH 150/164 drm/i915: Split icl_color_commit_noarm() from skl_color_commit_noarm()
In reply to Greg Kroah-HartmanFrom: Ville Syrjälä <[email protected]>
commit 76b767d4d1cd052e455cf18e06929e8b2b70101d upstream.
We're going to want different behavior for skl/glk vs. icl in .color_commit_noarm(), so split the hook into two. Arguably we already had slightly different behaviour since csc_enable/gamma_enable are never set on icl+, so the old code was perhaps a bit confusing as well.
--- drivers/gpu/drm/i915/display/intel_color.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_color.c +20 -1
@@ -2098,6 +2098,25 @@ static void glk_read_luts(struct intel_c } } +static void icl_color_commit_arm (const struct intel_crtc_state *crtc_state) +{ +struct intel_crtc *crtc =to_intel_crtc (crtc_state->uapi.crtc); +struct drm_i915_private *i915 =to_i915 (crtc->base.dev); +enum pipe pipe = crtc->pipe; + +/* +* We don't (yet) allow userspace to control the pipe background color, +* so force it to black. +*/ +intel_de_write (i915,SKL_BOTTOM_COLOR (pipe),0 ); + +intel_de_write (i915,GAMMA_MODE (crtc->pipe), + crtc_state->gamma_mode); + +intel_de_write_fw (i915,PIPE_CSC_MODE (crtc->pipe), + crtc_state->csc_mode); +} +static struct drm_property_blob *icl_read_lut_multi_segment (struct intel_crtc *crtc) {
@@ -2183,7 +2202,7 @@ static const struct intel_color_funcs i9static const struct intel_color_funcs icl_color_funcs = { .color_check = icl_color_check, .color_commit_noarm = icl_color_commit_noarm, - .color_commit_arm = skl_color_commit_arm, + .color_commit_arm = icl_color_commit_arm, .load_luts = icl_load_luts, .read_luts = icl_read_luts, };
Greg Kroah-Hartman
maintainerPATCH 151/164 mm: take a page reference when removing device exclusive entries
In reply to Greg Kroah-HartmanFrom: Alistair Popple <[email protected]>
commit 7c7b962938ddda6a9cd095de557ee5250706ea88 upstream.
Device exclusive page table entries are used to prevent CPU access to a page whilst it is being accessed from a device. Typically this is used to implement atomic operations when the underlying bus does not support atomic access. When a CPU thread encounters a device exclusive entry it locks the page and restores the original entry after calling mmu notifiers to signal drivers that exclusive access is no longer available.
The device exclusive entry holds a reference to the page making it safe to access the struct page whilst the entry is present. However the fault handling code does not hold the PTL when taking the page lock. This means if there are multiple threads faulting concurrently on the device exclusive entry one will remove the entry whilst others will wait on the page lock without holding a reference.
This can lead to threads locking or waiting on a folio with a zero refcount. Whilst mmap_lock prevents the pages getting freed via munmap() they may still be freed by a migration. This leads to warnings such as PAGE_FLAGS_CHECK_AT_FREE due to the page being locked when the refcount drops to zero.
Fix this by trying to take a reference on the folio before locking it. The code already checks the PTE under the PTL and aborts if the entry is no longer there. It is also possible the folio has been unmapped, freed and re-allocated allowing a reference to be taken on an unrelated folio. This case is also detected by the PTE check and the folio is unlocked without further changes.
--- mm/memory.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
mm/memory.c +15 -1
@@ -3619,8 +3619,21 @@ static vm_fault_t remove_device_exclusivstruct vm_area_struct *vma = vmf->vma;struct mmu_notifier_range range; -if (!folio_lock_or_retry (folio, vma->vm_mm, vmf->flags)) +/* +* We need a reference to lock the folio because we don't hold +* the PTL so a racing thread can remove the device-exclusive +* entry and unmap it. If the folio is free the entry must +* have been removed already. If it happens to have already +* been re-allocated after being freed all we do is lock and +* unlock it. +*/ +if (!folio_try_get (folio)) +return 0 ; + +if (!folio_lock_or_retry (folio, vma->vm_mm, vmf->flags)) { +folio_put (folio);return VM_FAULT_RETRY ; + }mmu_notifier_range_init_owner (&range,MMU_NOTIFY_EXCLUSIVE ,0 , vma, vma->vm_mm, vmf->address &PAGE_MASK , (vmf->address &PAGE_MASK ) +PAGE_SIZE ,NULL );
@@ -3633,6 +3646,7 @@ static vm_fault_t remove_device_exclusivpte_unmap_unlock (vmf->pte, vmf->ptl);folio_unlock (folio); +folio_put (folio);mmu_notifier_invalidate_range_end (&range);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 152/164 maple_tree: remove GFP_ZERO from kmem_cache_alloc() and kmem_cache_alloc_bulk()
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 541e06b772c1aaffb3b6a245ccface36d7107af2 upstream.
Preallocations are common in the VMA code to avoid allocating under certain locking conditions. The preallocations must also cover the worst-case scenario. Removing the GFP_ZERO flag from the kmem_cache_alloc() (and bulk variant) calls will reduce the amount of time spent zeroing memory that may not be used. Only zero out the necessary area to keep track of the allocations in the maple state. Zero the entire node prior to using it in the tree.
This required internal changes to node counting on allocation, so the test code is also updated.
This restores some micro-benchmark performance: up to +9% in mmtests mmap1 by my testing +10% to +20% in mmap, mmapaddr, mmapmany tests reported by Red Hat
--- lib/maple_tree.c | 80 ++++++++++++++++++++------------------- tools/testing/radix-tree/maple.c | 18 ++++---- 2 files changed, 52 insertions(+), 46 deletions(-)
lib/maple_tree.c +43 -37
@@ -149,13 +149,12 @@ struct maple_subtree_state {/* Functions */ static inline struct maple_node *mt_alloc_one (gfp_t gfp) { -return kmem_cache_alloc (maple_node_cache, gfp | __GFP_ZERO); +return kmem_cache_alloc (maple_node_cache, gfp); }static inline int mt_alloc_bulk (gfp_t gfp,size_t size,void **nodes) { -return kmem_cache_alloc_bulk (maple_node_cache, gfp | __GFP_ZERO, size, - nodes); +return kmem_cache_alloc_bulk (maple_node_cache, gfp, size, nodes); }static inline void mt_free_bulk (size_t size,void __rcu **nodes)
@@ -1123,9 +1122,10 @@ static inline struct maple_node *mas_pop {struct maple_alloc *ret, *node = mas->alloc;unsigned long total =mas_allocated (mas); +unsigned int req =mas_alloc_req (mas);/* nothing or a request pending. */ -if (unlikely (!total)) +if (WARN_ON (!total))return NULL ;if (total ==1 ) {
@@ -1135,27 +1135,25 @@ static inline struct maple_node *mas_pop goto single_node; } -if (!node->node_count) { +if (node->node_count ==1 ) {/* Single allocation in this node. */ mas->alloc = node->slot[0 ]; - node->slot[0 ] =NULL ; mas->alloc->total = node->total -1 ; ret = node; goto new_head; } - node->total--; - ret = node->slot[node->node_count]; - node->slot[node->node_count--] =NULL ; + ret = node->slot[--node->node_count]; + node->slot[node->node_count] =NULL ; single_node: new_head: - ret->total =0 ; - ret->node_count =0 ; -if (ret->request_count) { -mas_set_alloc_req (mas, ret->request_count +1 ); - ret->request_count =0 ; +if (req) { + req++; +mas_set_alloc_req (mas, req); } + +memset (ret,0 ,sizeof (*ret));return (struct maple_node *)ret; }
@@ -1174,21 +1172,20 @@ static inline void mas_push_node(structunsigned long count;unsigned int requested =mas_alloc_req (mas); -memset (reuse,0 ,sizeof (*reuse)); count =mas_allocated (mas); -if (count && (head->node_count <MAPLE_ALLOC_SLOTS -1 )) { -if (head->slot[0 ]) - head->node_count++; - head->slot[head->node_count] = reuse; + reuse->request_count =0 ; + reuse->node_count =0 ; +if (count && (head->node_count <MAPLE_ALLOC_SLOTS )) { + head->slot[head->node_count++] = reuse; head->total++; goto done; } reuse->total =1 ;if ((head) && !((unsigned long )head &0x1 )) { - head->request_count =0 ; reuse->slot[0 ] = head; + reuse->node_count =1 ; reuse->total += head->total; }
@@ -1207,7 +1204,6 @@ static inline void mas_alloc_nodes(struc {struct maple_alloc *node;unsigned long allocated =mas_allocated (mas); -unsigned long success = allocated;unsigned int requested =mas_alloc_req (mas);unsigned int count;void **slots =NULL ;
@@ -1223,24 +1219,29 @@ static inline void mas_alloc_nodes(strucWARN_ON (!allocated); } -if (!allocated || mas->alloc->node_count ==MAPLE_ALLOC_SLOTS -1 ) { +if (!allocated || mas->alloc->node_count ==MAPLE_ALLOC_SLOTS ) { node = (struct maple_alloc *)mt_alloc_one (gfp);if (!node) goto nomem_one; -if (allocated) +if (allocated) { node->slot[0 ] = mas->alloc; + node->node_count =1 ; + }else { + node->node_count =0 ; + } - success++; mas->alloc = node; + node->total = ++allocated; requested--; } node = mas->alloc; + node->request_count =0 ;while (requested) { max_req =MAPLE_ALLOC_SLOTS ; -if (node->slot[0 ]) { -unsigned int offset = node->node_count +1 ; +if (node->node_count) { +unsigned int offset = node->node_count; slots = (void **)&node->slot[offset]; max_req -= offset;
@@ -1254,15 +1255,13 @@ static inline void mas_alloc_nodes(struc goto nomem_bulk; node->node_count += count; -/* zero indexed. */ -if (slots == (void **)&node->slot) - node->node_count--; - - success += count; + allocated += count; node = node->slot[0 ]; + node->node_count =0 ; + node->request_count =0 ; requested -= count; } - mas->alloc->total = success; + mas->alloc->total = allocated;return ; nomem_bulk:
@@ -1271,7 +1270,7 @@ nomem_bulk: nomem_one:mas_set_alloc_req (mas, requested);if (mas->alloc && !(((unsigned long )mas->alloc &0x1 ))) - mas->alloc->total = success; + mas->alloc->total = allocated;mas_set_err (mas, -ENOMEM );return ;
@@ -5720,6 +5719,7 @@ int mas_preallocate(struct ma_state *masvoid mas_destroy (struct ma_state *mas) {struct maple_alloc *node; +unsigned long total;/* * When using mas_for_each() to insert an expected number of elements,
@@ -5742,14 +5742,20 @@ void mas_destroy(struct ma_state *mas) } mas->mas_flags &= ~(MA_STATE_BULK |MA_STATE_PREALLOC ); -while (mas->alloc && !((unsigned long )mas->alloc &0x1 )) { + total =mas_allocated (mas); +while (total) { node = mas->alloc; mas->alloc = node->slot[0 ]; -if (node->node_count >0 ) -mt_free_bulk (node->node_count, - (void __rcu **)&node->slot[1 ]); +if (node->node_count >1 ) { +size_t count = node->node_count -1 ; + +mt_free_bulk (count, (void __rcu **)&node->slot[1 ]); + total -= count; + }kmem_cache_free (maple_node_cache, node); + total--; } + mas->alloc =NULL ; }EXPORT_SYMBOL_GPL (mas_destroy);
tools/testing/radix-tree/maple.c +9 -9
@@ -172,11 +172,11 @@ static noinline void check_new_node(struif (!MAPLE_32BIT ) {if (i >=35 ) - e = i -35 ; + e = i -34 ;else if (i >=5 ) - e = i -5 ; + e = i -4 ;else if (i >=2 ) - e = i -2 ; + e = i -1 ; }else {if (i >=4 ) e = i -4 ;
@@ -304,17 +304,17 @@ static noinline void check_new_node(struMT_BUG_ON (mt, mas.node !=MA_ERROR (-ENOMEM ));MT_BUG_ON (mt, !mas_nomem (&mas,GFP_KERNEL ));MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS +1 ); -MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS -1 ); +MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS ); mn =mas_pop_node (&mas);/* get the next node. */ MT_BUG_ON (mt, mn ==NULL );MT_BUG_ON (mt,not_empty (mn));MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS ); -MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS -2 ); +MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS -1 );mas_push_node (&mas, mn);MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS +1 ); -MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS -1 ); +MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS );/* Check the limit of pop/push/pop */ mas_node_count (&mas,MAPLE_ALLOC_SLOTS +2 );/* Request */
@@ -322,14 +322,14 @@ static noinline void check_new_node(struMT_BUG_ON (mt, mas.node !=MA_ERROR (-ENOMEM ));MT_BUG_ON (mt, !mas_nomem (&mas,GFP_KERNEL ));MT_BUG_ON (mt,mas_alloc_req (&mas)); -MT_BUG_ON (mt, mas.alloc->node_count); +MT_BUG_ON (mt, mas.alloc->node_count !=1 );MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS +2 ); mn =mas_pop_node (&mas);MT_BUG_ON (mt,not_empty (mn));MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS +1 ); -MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS -1 ); +MT_BUG_ON (mt, mas.alloc->node_count !=MAPLE_ALLOC_SLOTS );mas_push_node (&mas, mn); -MT_BUG_ON (mt, mas.alloc->node_count); +MT_BUG_ON (mt, mas.alloc->node_count !=1 );MT_BUG_ON (mt,mas_allocated (&mas) !=MAPLE_ALLOC_SLOTS +2 ); mn =mas_pop_node (&mas);MT_BUG_ON (mt,not_empty (mn));
Greg Kroah-Hartman
maintainerPATCH 153/164 maple_tree: fix potential rcu issue
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 65be6f058b0eba98dc6c6f197ea9f62c9b6a519f upstream.
Ensure the node isn't dead after reading the node end.
--- lib/maple_tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/maple_tree.c +1 -1
@@ -4650,13 +4650,13 @@ static inline void *mas_next_nentry(stru pivots =ma_pivots (node, type); slots =ma_slots (node, type); mas->index =mas_safe_min (mas, pivots, mas->offset); + count =ma_data_end (node, type, pivots, mas->max);if (ma_dead_node (node))return NULL ;if (mas->index > max)return NULL ; - count =ma_data_end (node, type, pivots, mas->max);if (mas->offset > count)return NULL ;
Greg Kroah-Hartman
maintainerPATCH 154/164 maple_tree: reduce user error potential
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 50e81c82ad947045c7ed26ddc9acb17276b653b6 upstream.
When iterating, a user may operate on the tree and cause the maple state to be altered and left in an unintuitive state. Detect this scenario and correct it by setting to the limit and invalidating the state.
--- lib/maple_tree.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
lib/maple_tree.c +10 -0
@@ -4731,6 +4731,11 @@ static inline void *mas_next_entry(strucunsigned long last;enum maple_type mt; +if (mas->index > limit) { + mas->index = mas->last = limit; +mas_pause (mas); +return NULL ; + } last = mas->last; retry: offset = mas->offset;
@@ -4837,6 +4842,11 @@ static inline void *mas_prev_entry(struc {void *entry; +if (mas->index < min) { + mas->index = mas->last = min; +mas_pause (mas); +return NULL ; + } retry:while (likely (!mas_is_none (mas))) { entry =mas_prev_nentry (mas, min, mas->index);
Greg Kroah-Hartman
maintainerPATCH 155/164 maple_tree: fix handle of invalidated state in mas_wr_store_setup()
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 1202700c3f8cc5f7e4646c3cf05ee6f7c8bc6ccf upstream.
If an invalidated maple state is encountered during write, reset the maple state to MAS_START. This will result in a re-walk of the tree to the correct location for the write.
--- lib/maple_tree.c | 3 +++ 1 file changed, 3 insertions(+)
lib/maple_tree.c +3 -0
@@ -5594,6 +5594,9 @@ static inline void mte_destroy_walk(strustatic void mas_wr_store_setup (struct ma_wr_state *wr_mas) { +if (unlikely (mas_is_paused (wr_mas->mas))) +mas_reset (wr_mas->mas); +if (!mas_is_start (wr_mas->mas)) {if (mas_is_none (wr_mas->mas)) {mas_reset (wr_mas->mas);
Greg Kroah-Hartman
maintainerPATCH 156/164 maple_tree: fix mas_prev() and mas_find() state handling
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 17dc622c7b0f94e49bed030726df4db12ecaa6b5 upstream.
When mas_prev() does not find anything, set the state to MAS_NONE.
Handle the MAS_NONE in mas_find() like a MAS_START.
--- lib/maple_tree.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
lib/maple_tree.c +5 -1
@@ -4844,7 +4844,7 @@ static inline void *mas_prev_entry(strucif (mas->index < min) { mas->index = mas->last = min; -mas_pause (mas); + mas->node =MAS_NONE ;return NULL ; } retry:
@@ -5906,6 +5906,7 @@ void *mas_prev(struct ma_state *mas, unsif (!mas->index) {/* Nothing comes before 0 */ mas->last =0 ; + mas->node =MAS_NONE ;return NULL ; }
@@ -5996,6 +5997,9 @@ void *mas_find(struct ma_state *mas, uns mas->index = ++mas->last; } +if (unlikely (mas_is_none (mas))) + mas->node =MAS_START ; +if (unlikely (mas_is_start (mas))) {/* First run or continue */ void *entry;
Greg Kroah-Hartman
maintainerPATCH 157/164 maple_tree: be more cautious about dead nodes
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 39d0bd86c499ecd6abae42a9b7112056c5560691 upstream.
ma_pivots() and ma_data_end() may be called with a dead node. Ensure to that the node isn't dead before using the returned values.
This is necessary for RCU mode of the maple tree.
--- lib/maple_tree.c | 52 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-)
lib/maple_tree.c +43 -9
@@ -534,6 +534,7 @@ static inline bool ma_dead_node(const streturn (parent == node); } +/* * mte_dead_node() - check if the @enode is dead. * @enode: The encoded maple node
@@ -615,6 +616,8 @@ static inline unsigned int mas_alloc_req* @node - the maple node * @type - the node type * +* In the event of a dead node, this array may be %NULL +* * Return: A pointer to the maple node pivots */ static inline unsigned long *ma_pivots(struct maple_node *node,
@@ -1086,8 +1089,11 @@ static int mas_ascend(struct ma_state *m a_type =mas_parent_enum (mas, p_enode); a_node =mte_parent (p_enode); a_slot =mte_parent_slot (p_enode); - pivots =ma_pivots (a_node, a_type); a_enode =mt_mk_node (a_node, a_type); + pivots =ma_pivots (a_node, a_type); + +if (unlikely (ma_dead_node (a_node))) +return 1 ;if (!set_min && a_slot) { set_min = true;
@@ -1393,6 +1399,9 @@ static inline unsigned char ma_data_end( {unsigned char offset; +if (!pivots) +return 0 ; +if (type == maple_arange_64)return ma_meta_end (node, type);
@@ -1428,6 +1437,9 @@ static inline unsigned char mas_data_endreturn ma_meta_end (node, type); pivots =ma_pivots (node, type); +if (unlikely (ma_dead_node (node))) +return 0 ; + offset = mt_pivots[type] -1 ;if (likely (!pivots[offset]))return ma_meta_end (node, type);
@@ -4493,6 +4505,9 @@ static inline int mas_prev_node(struct m node =mas_mn (mas); slots =ma_slots (node, mt); pivots =ma_pivots (node, mt); +if (unlikely (ma_dead_node (node))) +return 1 ; + mas->max = pivots[offset];if (offset) mas->min = pivots[offset -1 ] +1 ;
@@ -4514,6 +4529,9 @@ static inline int mas_prev_node(struct m slots =ma_slots (node, mt); pivots =ma_pivots (node, mt); offset =ma_data_end (node, mt, pivots, mas->max); +if (unlikely (ma_dead_node (node))) +return 1 ; +if (offset) mas->min = pivots[offset -1 ] +1 ;
@@ -4562,6 +4580,7 @@ static inline int mas_next_node(struct mstruct maple_enode *enode;int level =0 ;unsigned char offset; +unsigned char node_end;enum maple_type mt;void __rcu **slots;
@@ -4585,7 +4604,11 @@ static inline int mas_next_node(struct m node =mas_mn (mas); mt =mte_node_type (mas->node); pivots =ma_pivots (node, mt); - }while (unlikely (offset ==ma_data_end (node, mt, pivots, mas->max))); + node_end =ma_data_end (node, mt, pivots, mas->max); +if (unlikely (ma_dead_node (node))) +return 1 ; + + }while (unlikely (offset == node_end)); slots =ma_slots (node, mt); pivot =mas_safe_pivot (mas, pivots, ++offset, mt);
@@ -4601,6 +4624,9 @@ static inline int mas_next_node(struct m mt =mte_node_type (mas->node); slots =ma_slots (node, mt); pivots =ma_pivots (node, mt); +if (unlikely (ma_dead_node (node))) +return 1 ; + offset =0 ; pivot = pivots[0 ]; }
@@ -4647,11 +4673,14 @@ static inline void *mas_next_nentry(strureturn NULL ; } - pivots =ma_pivots (node, type); slots =ma_slots (node, type); - mas->index =mas_safe_min (mas, pivots, mas->offset); + pivots =ma_pivots (node, type); count =ma_data_end (node, type, pivots, mas->max); -if (ma_dead_node (node)) +if (unlikely (ma_dead_node (node))) +return NULL ; + + mas->index =mas_safe_min (mas, pivots, mas->offset); +if (unlikely (ma_dead_node (node)))return NULL ;if (mas->index > max)
@@ -4809,6 +4838,11 @@ retry: slots =ma_slots (mn, mt); pivots =ma_pivots (mn, mt); +if (unlikely (ma_dead_node (mn))) { +mas_rewalk (mas, index); + goto retry; + } +if (offset == mt_pivots[mt]) pivot = mas->max;else
@@ -6611,11 +6645,11 @@ static inline void *mas_first_entry(struwhile (likely (!ma_is_leaf (mt))) {MT_BUG_ON (mas->tree,mte_dead_node (mas->node)); slots =ma_slots (mn, mt); - pivots =ma_pivots (mn, mt); - max = pivots[0 ]; entry =mas_slot (mas, slots,0 ); + pivots =ma_pivots (mn, mt);if (unlikely (ma_dead_node (mn)))return NULL ; + max = pivots[0 ]; mas->node = entry; mn =mas_mn (mas); mt =mte_node_type (mas->node);
@@ -6635,13 +6669,13 @@ static inline void *mas_first_entry(struif (likely (entry))return entry; - pivots =ma_pivots (mn, mt); - mas->index = pivots[0 ] +1 ; mas->offset =1 ; entry =mas_slot (mas, slots,1 ); + pivots =ma_pivots (mn, mt);if (unlikely (ma_dead_node (mn)))return NULL ; + mas->index = pivots[0 ] +1 ;if (mas->index > limit) goto none;
Greg Kroah-Hartman
maintainerPATCH 158/164 maple_tree: refine ma_state init from mas_start()
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 46b345848261009477552d654cb2f65000c30e4d upstream.
If mas->node is an MAS_START, there are three cases, and they all assign different values to mas->node and mas->offset. So there is no need to set them to a default value before updating.
Update them directly to make them easier to understand and for better readability.
--- lib/maple_tree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
lib/maple_tree.c +3 -3
@@ -1334,7 +1334,7 @@ static void mas_node_count(struct ma_sta* mas_start() - Sets up maple state for operations. * @mas: The maple state. * -* If mas->node == MAS_START, then set the min, max, depth, and offset to +* If mas->node == MAS_START, then set the min, max and depth to * defaults. * * Return:
@@ -1348,22 +1348,22 @@ static inline struct maple_enode *mas_stif (likely (mas_is_start (mas))) {struct maple_enode *root; - mas->node =MAS_NONE ; mas->min =0 ; mas->max =ULONG_MAX ; mas->depth =0 ; - mas->offset =0 ; root =mas_root (mas);/* Tree with nodes */ if (likely (xa_is_node (root))) { mas->depth =1 ; mas->node =mte_safe_root (root); + mas->offset =0 ;return NULL ; }/* empty tree */ if (unlikely (!root)) { + mas->node =MAS_NONE ; mas->offset =MAPLE_NODE_SLOTS ;return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 159/164 maple_tree: detect dead nodes in mas_start()
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit a7b92d59c885018cb7bb88539892278e4fd64b29 upstream.
When initially starting a search, the root node may already be in the process of being replaced in RCU mode. Detect and restart the walk if this is the case. This is necessary for RCU mode of the maple tree.
--- lib/maple_tree.c | 4 ++++ 1 file changed, 4 insertions(+)
lib/maple_tree.c +4 -0
@@ -1352,12 +1352,16 @@ static inline struct maple_enode *mas_st mas->max =ULONG_MAX ; mas->depth =0 ; +retry: root =mas_root (mas);/* Tree with nodes */ if (likely (xa_is_node (root))) { mas->depth =1 ; mas->node =mte_safe_root (root); mas->offset =0 ; +if (mte_dead_node (mas->node)) + goto retry; +return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 160/164 maple_tree: fix freeing of nodes in rcu mode
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 2e5b4921f8efc9e845f4f04741797d16f36847eb upstream.
The walk to destroy the nodes was not always setting the node type and would result in a destroy method potentially using the values as nodes. Avoid this by setting the correct node types. This is necessary for the RCU mode of the maple tree.
--- lib/maple_tree.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 11 deletions(-)
lib/maple_tree.c +62 -11
@@ -893,6 +893,44 @@ static inline void ma_set_meta(struct ma }/* +* mas_clear_meta() - clear the metadata information of a node, if it exists +* @mas: The maple state +* @mn: The maple node +* @mt: The maple node type +* @offset: The offset of the highest sub-gap in this node. +* @end: The end of the data in this node. +*/ +static inline void mas_clear_meta (struct ma_state *mas,struct maple_node *mn, +enum maple_type mt) +{ +struct maple_metadata *meta; +unsigned long *pivots; +void __rcu **slots; +void *next; + +switch (mt) { +case maple_range_64: + pivots = mn->mr64.pivot; +if (unlikely (pivots[MAPLE_RANGE64_SLOTS -2 ])) { + slots = mn->mr64.slot; + next =mas_slot_locked (mas, slots, +MAPLE_RANGE64_SLOTS -1 ); +if (unlikely ((mte_to_node (next) &&mte_node_type (next)))) +return ;/* The last slot is a node, no metadata */ + } + fallthrough; +case maple_arange_64: + meta =ma_meta (mn, mt); +break ; +default : +return ; + } + + meta->gap =0 ; + meta->end =0 ; +} + +/* * ma_meta_end() - Get the data end of a node from the metadata * @mn: The maple node * @mt: The maple node type
@@ -5433,20 +5471,22 @@ no_gap:* mas_dead_leaves() - Mark all leaves of a node as dead. * @mas: The maple state * @slots: Pointer to the slot array +* @type: The maple node type * * Must hold the write lock. * * Return: The number of leaves marked as dead. */ static inline -unsigned char mas_dead_leaves (struct ma_state *mas,void __rcu **slots) +unsigned char mas_dead_leaves (struct ma_state *mas,void __rcu **slots, +enum maple_type mt) {struct maple_node *node;enum maple_type type;void *entry;int offset; -for (offset =0 ; offset <mt_slot_count (mas->node); offset++) { +for (offset =0 ; offset < mt_slots[mt]; offset++) { entry =mas_slot_locked (mas, slots, offset); type =mte_node_type (entry); node =mte_to_node (entry);
@@ -5465,14 +5505,13 @@ unsigned char mas_dead_leaves(struct ma_static void __rcu **mas_dead_walk (struct ma_state *mas,unsigned char offset) { -struct maple_node *node, *next; +struct maple_node *next;void __rcu **slots =NULL ; next =mas_mn (mas);do { - mas->node =ma_enode_ptr (next); - node =mas_mn (mas); - slots =ma_slots (node, node->type); + mas->node =mt_mk_node (next, next->type); + slots =ma_slots (next, next->type); next =mas_slot_locked (mas, slots, offset); offset =0 ; }while (!ma_is_leaf (next->type));
@@ -5536,11 +5575,14 @@ static inline void __rcu **mas_destroy_d node =mas_mn (mas); slots =ma_slots (node,mte_node_type (mas->node)); next =mas_slot_locked (mas, slots,0 ); -if ((mte_dead_node (next))) +if ((mte_dead_node (next))) { +mte_to_node (next)->type =mte_node_type (next); next =mas_slot_locked (mas, slots,1 ); + }mte_set_node_dead (mas->node); node->type =mte_node_type (mas->node); +mas_clear_meta (mas, node, node->type); node->piv_parent = prev; node->parent_slot = offset; offset =0 ;
@@ -5560,13 +5602,18 @@ static void mt_destroy_walk(struct mapleMA_STATE (mas, &mt,0 ,0 ); -if (mte_is_leaf (enode)) + mas.node = enode; +if (mte_is_leaf (enode)) { + node->type =mte_node_type (enode); goto free_leaf; + } + ma_flags &= ~MT_FLAGS_LOCK_MASK ;mt_init_flags (&mt, ma_flags);mas_lock (&mas); - mas.node = start = enode; +mte_to_node (enode)->ma_flags = ma_flags; + start = enode; slots =mas_destroy_descend (&mas, start,0 ); node =mas_mn (&mas); do {
@@ -5574,7 +5621,8 @@ static void mt_destroy_walk(struct mapleunsigned char offset;struct maple_enode *parent, *tmp; - node->slot_len =mas_dead_leaves (&mas, slots); + node->type =mte_node_type (mas.node); + node->slot_len =mas_dead_leaves (&mas, slots, node->type);if (free)mt_free_bulk (node->slot_len, slots); offset = node->parent_slot +1 ;
@@ -5598,7 +5646,8 @@ next: }while (start != mas.node); node =mas_mn (&mas); - node->slot_len =mas_dead_leaves (&mas, slots); + node->type =mte_node_type (mas.node); + node->slot_len =mas_dead_leaves (&mas, slots, node->type);if (free)mt_free_bulk (node->slot_len, slots);
@@ -5608,6 +5657,8 @@ start_slots_free: free_leaf:if (free)mt_free_rcu (&node->rcu); +else +mas_clear_meta (&mas, node, node->type); }/*
Greg Kroah-Hartman
maintainerPATCH 161/164 maple_tree: remove extra smp_wmb() from mas_dead_leaves()
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 8372f4d83f96f35915106093cde4565836587123 upstream.
The call to mte_set_dead_node() before the smp_wmb() already calls smp_wmb() so this is not needed. This is an optimization for the RCU mode of the maple tree.
--- lib/maple_tree.c | 1 - 1 file changed, 1 deletion(-)
lib/maple_tree.c +0 -1
@@ -5495,7 +5495,6 @@ unsigned char mas_dead_leaves(struct ma_break ;mte_set_node_dead (entry); -smp_wmb ();/* Needed for RCU */ node->type = type;rcu_assign_pointer (slots[offset], node); }
Greg Kroah-Hartman
maintainerPATCH 162/164 maple_tree: add smp_rmb() to dead node detection
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 0a2b18d948838e16912b3b627b504ab062b7d02a upstream.
Add an smp_rmb() before reading the parent pointer to ensure that anything read from the node prior to the parent pointer hasn't been reordered ahead of this check.
The is necessary for RCU mode.
--- lib/maple_tree.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
lib/maple_tree.c +6 -2
@@ -529,9 +529,11 @@ static inline struct maple_node *mte_par*/ static inline bool ma_dead_node (const struct maple_node *node) { -struct maple_node *parent = (void *)((unsigned long ) - node->parent & ~MAPLE_NODE_MASK ); +struct maple_node *parent; +/* Do not reorder reads from the node prior to the parent check */ +smp_rmb (); + parent = (void *)((unsigned long ) node->parent & ~MAPLE_NODE_MASK );return (parent == node); }
@@ -546,6 +548,8 @@ static inline bool mte_dead_node(const sstruct maple_node *parent, *node; node =mte_to_node (enode); +/* Do not reorder reads from the node prior to the parent check */ +smp_rmb (); parent =mte_parent (enode);return (parent == node); }
Greg Kroah-Hartman
maintainerPATCH 163/164 maple_tree: add RCU lock checking to rcu callback functions
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 790e1fa86b340c2bd4a327e01c161f7a1ad885f6 upstream.
Dereferencing RCU objects within the RCU callback without the RCU check has caused lockdep to complain. Fix the RCU dereferencing by using the RCU callback lock to ensure the operation is safe.
Also stop creating a new lock to use for dereferencing during destruction of the tree or subtree. Instead, pass through a pointer to the tree that has the lock that is held for RCU dereferencing checking. It also does not make sense to use the maple state in the freeing scenario as the tree walk is a special case where the tree no longer has the normal encodings and parent pointers.
--- lib/maple_tree.c | 188 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 92 deletions(-)
lib/maple_tree.c +96 -92
@@ -814,6 +814,11 @@ static inline void *mt_slot(const structreturn rcu_dereference_check (slots[offset],mt_locked (mt)); } +static inline void *mt_slot_locked (struct maple_tree *mt,void __rcu **slots, +unsigned char offset) +{ +return rcu_dereference_protected (slots[offset],mt_locked (mt)); +}/* * mas_slot_locked() - Get the slot value when holding the maple tree lock. * @mas: The maple state
@@ -825,7 +830,7 @@ static inline void *mt_slot(const structstatic inline void *mas_slot_locked (struct ma_state *mas,void __rcu **slots,unsigned char offset) { -return rcu_dereference_protected (slots[offset],mt_locked (mas->tree)); +return mt_slot_locked (mas->tree, slots, offset); }/*
@@ -897,34 +902,35 @@ static inline void ma_set_meta(struct ma }/* -* mas_clear_meta() - clear the metadata information of a node, if it exists -* @mas: The maple state +* mt_clear_meta() - clear the metadata information of a node, if it exists +* @mt: The maple tree * @mn: The maple node -* @mt: The maple node type +* @type: The maple node type * @offset: The offset of the highest sub-gap in this node. * @end: The end of the data in this node. */ -static inline void mas_clear_meta (struct ma_state *mas,struct maple_node *mn, -enum maple_type mt) +static inline void mt_clear_meta (struct maple_tree *mt,struct maple_node *mn, +enum maple_type type) {struct maple_metadata *meta;unsigned long *pivots;void __rcu **slots;void *next; -switch (mt) { +switch (type) {case maple_range_64: pivots = mn->mr64.pivot;if (unlikely (pivots[MAPLE_RANGE64_SLOTS -2 ])) { slots = mn->mr64.slot; - next =mas_slot_locked (mas, slots, -MAPLE_RANGE64_SLOTS -1 ); -if (unlikely ((mte_to_node (next) &&mte_node_type (next)))) -return ;/* The last slot is a node, no metadata */ + next =mt_slot_locked (mt, slots, +MAPLE_RANGE64_SLOTS -1 ); +if (unlikely ((mte_to_node (next) && +mte_node_type (next)))) +return ;/* no metadata, could be node */ } fallthrough;case maple_arange_64: - meta =ma_meta (mn, mt); + meta =ma_meta (mn, type);break ;default :return ;
@@ -5472,7 +5478,7 @@ no_gap: }/* -* mas_dead_leaves() - Mark all leaves of a node as dead. +* mte_dead_leaves() - Mark all leaves of a node as dead. * @mas: The maple state * @slots: Pointer to the slot array * @type: The maple node type
@@ -5482,16 +5488,16 @@ no_gap:* Return: The number of leaves marked as dead. */ static inline -unsigned char mas_dead_leaves (struct ma_state *mas,void __rcu **slots, -enum maple_type mt) +unsigned char mte_dead_leaves (struct maple_enode *enode,struct maple_tree *mt, +void __rcu **slots) {struct maple_node *node;enum maple_type type;void *entry;int offset; -for (offset =0 ; offset < mt_slots[mt]; offset++) { - entry =mas_slot_locked (mas, slots, offset); +for (offset =0 ; offset <mt_slot_count (enode); offset++) { + entry =mt_slot (mt, slots, offset); type =mte_node_type (entry); node =mte_to_node (entry);/* Use both node and type to catch LE & BE metadata */
@@ -5506,162 +5512,160 @@ unsigned char mas_dead_leaves(struct ma_return offset; } -static void __rcu **mas_dead_walk (struct ma_state *mas,unsigned char offset) +/** +* mte_dead_walk() - Walk down a dead tree to just before the leaves +* @enode: The maple encoded node +* @offset: The starting offset +* +* Note: This can only be used from the RCU callback context. +*/ +static void __rcu **mte_dead_walk (struct maple_enode **enode,unsigned char offset) { -struct maple_node *next; +struct maple_node *node, *next;void __rcu **slots =NULL ; - next =mas_mn (mas); + next =mte_to_node (*enode);do { - mas->node =mt_mk_node (next, next->type); - slots =ma_slots (next, next->type); - next =mas_slot_locked (mas, slots, offset); + *enode =ma_enode_ptr (next); + node =mte_to_node (*enode); + slots =ma_slots (node, node->type); + next =rcu_dereference_protected (slots[offset], +lock_is_held (&rcu_callback_map)); offset =0 ; }while (!ma_is_leaf (next->type));return slots; } +/** +* mt_free_walk() - Walk & free a tree in the RCU callback context +* @head: The RCU head that's within the node. +* +* Note: This can only be used from the RCU callback context. +*/ static void mt_free_walk (struct rcu_head *head) {void __rcu **slots;struct maple_node *node, *start; -struct maple_tree mt; +struct maple_enode *enode;unsigned char offset;enum maple_type type; -MA_STATE (mas, &mt,0 ,0 ); node = container_of(head, struct maple_node, rcu);if (ma_is_leaf (node->type)) goto free_leaf; -mt_init_flags (&mt, node->ma_flags); -mas_lock (&mas); start = node; - mas.node =mt_mk_node (node, node->type); - slots =mas_dead_walk (&mas,0 ); - node =mas_mn (&mas); + enode =mt_mk_node (node, node->type); + slots =mte_dead_walk (&enode,0 ); + node =mte_to_node (enode);do {mt_free_bulk (node->slot_len, slots); offset = node->parent_slot +1 ; - mas.node = node->piv_parent; -if (mas_mn (&mas) == node) - goto start_slots_free; - - type =mte_node_type (mas.node); - slots =ma_slots (mte_to_node (mas.node), type); -if ((offset < mt_slots[type]) && (slots[offset])) - slots =mas_dead_walk (&mas, offset); - - node =mas_mn (&mas); + enode = node->piv_parent; +if (mte_to_node (enode) == node) + goto free_leaf; + + type =mte_node_type (enode); + slots =ma_slots (mte_to_node (enode), type); +if ((offset < mt_slots[type]) && +rcu_dereference_protected (slots[offset], +lock_is_held (&rcu_callback_map))) + slots =mte_dead_walk (&enode, offset); + node =mte_to_node (enode); }while ((node != start) || (node->slot_len < offset)); slots =ma_slots (node, node->type);mt_free_bulk (node->slot_len, slots); -start_slots_free: -mas_unlock (&mas); free_leaf:mt_free_rcu (&node->rcu); } -static inline void __rcu **mas_destroy_descend (struct ma_state *mas, -struct maple_enode *prev,unsigned char offset) +static inline void __rcu **mte_destroy_descend (struct maple_enode **enode, +struct maple_tree *mt,struct maple_enode *prev,unsigned char offset) {struct maple_node *node; -struct maple_enode *next = mas->node; +struct maple_enode *next = *enode;void __rcu **slots =NULL ; +enum maple_type type; +unsigned char next_offset =0 ;do { - mas->node = next; - node =mas_mn (mas); - slots =ma_slots (node,mte_node_type (mas->node)); - next =mas_slot_locked (mas, slots,0 ); -if ((mte_dead_node (next))) { -mte_to_node (next)->type =mte_node_type (next); - next =mas_slot_locked (mas, slots,1 ); - } + *enode = next; + node =mte_to_node (*enode); + type =mte_node_type (*enode); + slots =ma_slots (node, type); + next =mt_slot_locked (mt, slots, next_offset); +if ((mte_dead_node (next))) + next =mt_slot_locked (mt, slots, ++next_offset); -mte_set_node_dead (mas->node); - node->type =mte_node_type (mas->node); -mas_clear_meta (mas, node, node->type); +mte_set_node_dead (*enode); + node->type = type; node->piv_parent = prev; node->parent_slot = offset; - offset =0 ; - prev = mas->node; + offset = next_offset; + next_offset =0 ; + prev = *enode; }while (!mte_is_leaf (next));return slots; } -static void mt_destroy_walk (struct maple_enode *enode,unsigned char ma_flags, +static void mt_destroy_walk (struct maple_enode *enode,struct maple_tree *mt,bool free) {void __rcu **slots;struct maple_node *node =mte_to_node (enode);struct maple_enode *start; -struct maple_tree mt; -MA_STATE (mas, &mt,0 ,0 ); - - mas.node = enode;if (mte_is_leaf (enode)) { node->type =mte_node_type (enode); goto free_leaf; } - ma_flags &= ~MT_FLAGS_LOCK_MASK ; -mt_init_flags (&mt, ma_flags); -mas_lock (&mas); - -mte_to_node (enode)->ma_flags = ma_flags; start = enode; - slots =mas_destroy_descend (&mas, start,0 ); - node =mas_mn (&mas); + slots =mte_destroy_descend (&enode, mt, start,0 ); + node =mte_to_node (enode);// Updated in the above call. do {enum maple_type type;unsigned char offset;struct maple_enode *parent, *tmp; - node->type =mte_node_type (mas.node); - node->slot_len =mas_dead_leaves (&mas, slots, node->type); + node->slot_len =mte_dead_leaves (enode, mt, slots);if (free)mt_free_bulk (node->slot_len, slots); offset = node->parent_slot +1 ; - mas.node = node->piv_parent; -if (mas_mn (&mas) == node) - goto start_slots_free; + enode = node->piv_parent; +if (mte_to_node (enode) == node) + goto free_leaf; - type =mte_node_type (mas.node); - slots =ma_slots (mte_to_node (mas.node), type); + type =mte_node_type (enode); + slots =ma_slots (mte_to_node (enode), type);if (offset >= mt_slots[type]) goto next; - tmp =mas_slot_locked (&mas, slots, offset); + tmp =mt_slot_locked (mt, slots, offset);if (mte_node_type (tmp) &&mte_to_node (tmp)) { - parent = mas.node; - mas.node = tmp; - slots =mas_destroy_descend (&mas, parent, offset); + parent = enode; + enode = tmp; + slots =mte_destroy_descend (&enode, mt, parent, offset); } next: - node =mas_mn (&mas); - }while (start != mas.node); + node =mte_to_node (enode); + }while (start != enode); - node =mas_mn (&mas); - node->type =mte_node_type (mas.node); - node->slot_len =mas_dead_leaves (&mas, slots, node->type); + node =mte_to_node (enode); + node->slot_len =mte_dead_leaves (enode, mt, slots);if (free)mt_free_bulk (node->slot_len, slots); -start_slots_free: -mas_unlock (&mas); - free_leaf:if (free)mt_free_rcu (&node->rcu);else -mas_clear_meta (&mas, node, node->type); +mt_clear_meta (mt, node, node->type); }/*
@@ -5677,10 +5681,10 @@ static inline void mte_destroy_walk(strustruct maple_node *node =mte_to_node (enode);if (mt_in_rcu (mt)) { -mt_destroy_walk (enode, mt->ma_flags, false); +mt_destroy_walk (enode, mt, false);call_rcu (&node->rcu, mt_free_walk); }else { -mt_destroy_walk (enode, mt->ma_flags, true); +mt_destroy_walk (enode, mt, true); } }
Greg Kroah-Hartman
maintainerPATCH 164/164 mm: enable maple tree RCU mode by default.
In reply to Greg Kroah-HartmanFrom: "Liam R. Howlett" <[email protected]>
commit 3dd4432549415f3c65dd52d5c687629efbf4ece1 upstream.
Use the maple tree in RCU mode for VMA tracking.
The maple tree tracks the stack and is able to update the pivot (lower/upper boundary) in-place to allow the page fault handler to write to the tree while holding just the mmap read lock. This is safe as the writes to the stack have a guard VMA which ensures there will always be a NULL in the direction of the growth and thus will only update a pivot.
It is possible, but not recommended, to have VMAs that grow up/down without guard VMAs. syzbot has constructed a testcase which sets up a VMA to grow and consume the empty space. Overwriting the entire NULL entry causes the tree to be altered in a way that is not safe for concurrent readers; the readers may see a node being rewritten or one that does not match the maple state they are using.
Enabling RCU mode allows the concurrent readers to see a stable node and will return the expected result.
--- include/linux/mm_types.h | 3 ++- kernel/fork.c | 3 +++ mm/mmap.c | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-)
include/linux/mm_types.h +2 -1
@@ -725,7 +725,8 @@ struct mm_struct {unsigned long cpu_bitmap[]; }; -#define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN) +#define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | \ + MT_FLAGS_USE_RCU)extern struct mm_struct init_mm;/* Pointer magic because the dynamic array size confuses some compilers. */
kernel/fork.c +3 -0
@@ -617,6 +617,7 @@ static __latent_entropy int dup_mmap(strif (retval) goto out; +mt_clear_in_rcu (mas.tree);mas_for_each (&old_mas, mpnt,ULONG_MAX ) {struct file *file;
@@ -703,6 +704,8 @@ static __latent_entropy int dup_mmap(str retval =arch_dup_mmap (oldmm, mm); loop_out:mas_destroy (&mas); +if (!retval) +mt_set_in_rcu (mas.tree); out:mmap_write_unlock (mm);flush_tlb_mm (oldmm);
mm/mmap.c +2 -1
@@ -2308,7 +2308,7 @@ do_mas_align_munmap(struct ma_state *masint count =0 ;int error = -ENOMEM ;MA_STATE (mas_detach, &mt_detach,0 ,0 ); -mt_init_flags (&mt_detach,MT_FLAGS_LOCK_EXTERN ); +mt_init_flags (&mt_detach, mas->tree->ma_flags &MT_FLAGS_LOCK_MASK );mt_set_external_lock (&mt_detach, &mm->mmap_lock);if (mas_preallocate (mas, vma,GFP_KERNEL ))
@@ -3095,6 +3095,7 @@ void exit_mmap(struct mm_struct *mm)*/ set_bit (MMF_OOM_SKIP , &mm->flags);mmap_write_lock (mm); +mt_clear_in_rcu (&mm->mm_mt);free_pgtables (&tlb, &mm->mm_mt, vma,FIRST_USER_ADDRESS ,USER_PGTABLES_CEILING );tlb_finish_mmu (&tlb);
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Thanks,
Conor.
Quoted 7 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
Hi Greg
6.1.24-rc1
compiles, boots and runs here on x86_64
(AMD Ryzen 5 PRO 4650G, Slackware64-15.0)
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.24-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.1.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.24-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.1.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
Build results:
total: 155 pass: 155 fail: 0 Qemu test results: total: 519 pass: 519 fail: 0
Guenter
Quoted 5 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Successfully cross-compiled for arm64 (bcm2711_defconfig, GCC 10.2.0) and powerpc (ps3_defconfig, GCC 12.2.0).
Signature · 1 line
An old man doll... just what I always wanted! - Clara
Quoted 17 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.24-rc1.gz
or in the git tree and branch at:git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.1.y and the diffstat can be found below.
Quoted 3 lines
thanks,
greg k-h
Compiled & booted on two of my x86_64 test systems, no errors or regressions.
Slade
Quoted 10 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.24-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.1.y
and the diffstat can be found below.thanks,
greg k-h
Results from Linaro’s test farm.
No regressions on arm64, arm, x86_64, and i386.
## Build
* kernel: 6.1.24-rc1
* git: https://gitlab.com/Linaro/lkft/mirrors/stable/linux-stable-rc
* git branch: linux-6.1.y
* git commit: 3ffd355e5e57467adbc1a65ccc871125bb75c36e
* git describe: v6.1.22-344-g3ffd355e5e57
* test details:
https://qa-reports.linaro.org/lkft/linux-stable-rc-linux-6.1.y/build/v6.1.22-344-g3ffd355e5e57
## Test Regressions (compared to v6.1.22)
## Metric Regressions (compared to v6.1.22)
## Test Fixes (compared to v6.1.22)
## Metric Fixes (compared to v6.1.22)
## Test result summary
total: 153669, pass: 135435, fail: 4189, skip: 13710, xfail: 335
## Build Summary
* arc: 5 total, 5 passed, 0 failed
* arm: 149 total, 148 passed, 1 failed
* arm64: 52 total, 51 passed, 1 failed
* i386: 39 total, 36 passed, 3 failed
* mips: 30 total, 28 passed, 2 failed
* parisc: 8 total, 8 passed, 0 failed
* powerpc: 38 total, 36 passed, 2 failed
* riscv: 16 total, 15 passed, 1 failed
* s390: 16 total, 16 passed, 0 failed
* sh: 14 total, 12 passed, 2 failed
* sparc: 8 total, 8 passed, 0 failed
* x86_64: 44 total, 44 passed, 0 failed
## Test suites summary
* boot
* fwts
* igt-gpu-tools
* kselftest-android
* kselftest-arm64
* kselftest-breakpoints
* kselftest-capabilities
* kselftest-cgroup
* kselftest-clone3
* kselftest-core
* kselftest-cpu-hotplug
* kselftest-cpufreq
* kselftest-drivers-dma-buf
* kselftest-efivarfs
* kselftest-filesystems
* kselftest-filesystems-binderfs
* kselftest-firmware
* kselftest-fpu
* kselftest-ftrace
* kselftest-futex
* kselftest-gpio
* kselftest-intel_pstate
* kselftest-ipc
* kselftest-ir
* kselftest-kcmp
* kselftest-kexec
* kselftest-kvm
* kselftest-lib
* kselftest-livepatch
* kselftest-membarrier
* kselftest-memfd
* kselftest-memory-hotplug
* kselftest-mincore
* kselftest-mount
* kselftest-mqueue
* kselftest-net
* kselftest-net-forwarding
* kselftest-net-mptcp
* kselftest-netfilter
* kselftest-nsfs
* kselftest-openat2
* kselftest-pid_namespace
* kselftest-pidfd
* kselftest-proc
* kselftest-pstore
* kselftest-ptrace
* kselftest-rseq
* kselftest-rtc
* kselftest-seccomp
* kselftest-sigaltstack
* kselftest-size
* kselftest-splice
* kselftest-static_keys
* kselftest-sync
* kselftest-sysctl
* kselftest-tc-testing
* kselftest-timens
* kselftest-timers
* kselftest-tmpfs
* kselftest-tpm2
* kselftest-user
* kselftest-vm
* kselftest-x86
* kselftest-zram
* kunit
* kvm-unit-tests
* libhugetlbfs
* log-parser-boot
* log-parser-test
* ltp-cap_bounds
* ltp-commands
* ltp-containers
* ltp-controllers
* ltp-cpuhotplug
* ltp-crypto
* ltp-cve
* ltp-dio
* ltp-fcntl-locktests
* ltp-filecaps
* ltp-fs
* ltp-fs_bind
* ltp-fs_perms_simple
* ltp-fsx
* ltp-hugetlb
* ltp-io
* ltp-ipc
* ltp-math
* ltp-mm
* ltp-nptl
* ltp-pty
* ltp-sched
* ltp-securebits
* ltp-smoke
* ltp-syscalls
* ltp-tracing
* network-basic-tests
* perf
* rcutorture
* v4l2-compliance
* vdso
--
Linaro LKFT
https://lkft.linaro.org
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.1.24 release. There are 164 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Fri, 14 Apr 2023 08:28:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.1.24-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.1.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).