KRN-1117: Add path-compressed trie storage to stackdepot - #2
Conversation
Add stack_depot_fetch_into() so callers can copy a saved stack trace into caller-owned storage instead of receiving a pointer to stackdepot-owned memory. This is a preparatory API for trie-backed stack storage, where a saved stack may be spread across multiple trie nodes and must be materialized before use. Add KUnit coverage for successful copy-out and invalid or too-small buffer handling. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Cover the stackdepot public header and KUnit test under LIBRARY CODE so get_maintainer.pl reports the library maintainer for the new test file and checkpatch no longer warns that MAINTAINERS may need updating. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Document the caller-owned copy and handle lifetime contract for stack_depot_fetch_into() so the helper is explicit about how trie-backed materialization will be consumed. Cover the exact-fit, oversized-buffer, and zero-sized-buffer cases in KUnit to lock the all-or-nothing copy semantics. Keep the stackdepot KUnit entry ordered with nearby tests and broaden MAINTAINERS coverage so future stackdepot tests are routed to the library maintainer. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Use stack_depot_fetch_into() when rendering page_owner_stacks so the diagnostic path no longer depends on stackdepot's flat entries[] storage. Store the materialized stack in seq_file private data to avoid a large stack buffer and keep output formatting unchanged. Clarify the fetch_into() oversized-buffer documentation while adding the first page_owner caller that relies on caller-owned stack materialization. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Store page_owner stack handles in the show_stacks list instead of stackdepot internal stack_record pointers. This keeps the debugfs listing path from depending on stackdepot's flat record storage while preserving the existing page count accounting for a later helper conversion. Materialize stack frames into seq_file private storage with stack_depot_fetch_into() when printing page_owner_stacks so the output format stays unchanged and no large stack-local buffer is needed. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add internal stackdepot count helpers and use them from page_owner so page_owner no longer reads or mutates struct stack_record directly. This keeps page_owner behind handle-based stackdepot access before the persistent stack storage layout changes for trie-backed records. Keep the stackdepot KUnit test built-in-only because it exercises internal helpers, and add coverage for the saturated-to-counted transition and count boundary cases. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Move the flat stackdepot record and handle bitfield layout out of the public stackdepot header and into lib/stackdepot.c. Runtime callers now use handle-based helpers, so the flat storage details no longer need to be exposed before the persistent storage backend changes. Keep the page_owner count helpers internal to stackdepot, document their counted-mode semantics, and extend KUnit coverage for saturated, counted, and invalid-count cases. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add generic architecture hooks for stackdepot frame compression so future x86-64 and arm64 implementations can opt in without changing common stackdepot callers. The generic asm fallback keeps today's behavior by declining compression and storing raw frames. Keep stackdepot_fetch_into() safe across the copy by holding the same notrace RCU read-side section used by stackdepot lookups, and cover the raw frame fallback plus count-helper edge cases in KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Keep the stackdepot count decrement helper from silently discarding attempts to subtract more than the current counted value. Preserve the old refcount diagnostic behavior by warning before returning false on an underflow attempt. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the x86-64 stackdepot frame compression hook for frames whose high 32 bits match the kernel-text prefix. This keeps non-x86-64 builds on the generic raw fallback while allowing the common code to use the architecture hook added earlier. Extend stackdepot KUnit coverage for the x86-64 round trip and for non-compressible direct-map frames. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the internal frame-run encoding layer used by the trie-backed stackdepot prototype. Runs are described as either raw frames or compressed low 32-bit frame values that share one architecture prefix, with caller-provided scratch storage so the kernel port does not hide CONFIG_STACKDEPOT_MAX_FRAMES-sized arrays on the stack. Enable the corresponding arm64 compression hook using the runtime _text prefix plus adjacent 4 GiB prefixes so KASLR and module windows round-trip exactly, while non-matching frames keep the raw fallback. Harden the existing x86 and generic hooks and extend KUnit coverage for raw, compressed, invalid, and max-frame cases. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Keep the page_owner stack display buffer sized to the depth that page_owner actually saves, and make count_threshold use the same unsigned int range as the stackdepot page counters. This keeps the stack-list marker subtraction explicit before threshold filtering and rejects oversized debugfs thresholds instead of silently suppressing every stack. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private trie-node storage primitive from the userspace prototype. A node stores one homogeneous raw or compressed frame run in caller-provided storage and records immutable parent and stack-length metadata so a leaf parent chain can be materialized into caller-owned output. Keep the helper inert for now: stack_depot_save() and the public fetch path still use existing hash records. KUnit covers node sizing, raw and compressed round trips, parent-chain materialization, mixed-run rejection, short storage, and invalid fetch inputs. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the sorted child-array helper layer from the userspace trie prototype. Child arrays are built in caller-owned storage, reject duplicate first-frame keys and in-place replacement, and remain unpublished so no RCU or COW visibility rules change yet. Cover initialization, lookup, empty insertion, middle insertion, unsorted input, duplicate insertion, and in-place update rejection in stackdepot KUnit. Also document the page_owner stack listing race as best-effort because counts can change while seq_file output is being generated. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Tighten the private trie helper contracts after adding child arrays. Reject overlapping frame-run buffers, validate old child-array storage alignment, and use an explicit ULONG_MAX arm64 prefix bound. Keep the page_owner count helper limits consistent across set/inc paths and document best-effort page_owner stack listing semantics. Extend stackdepot KUnit coverage for arm64 compressed frame-run round trips, compressed trie nodes without scratch storage, count-boundary handling, and child-array edge cases. The trie helpers remain inert: they only build caller-owned unpublished storage and do not change stack_depot_save() or public fetch routing. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private trie node matching primitive from the userspace prototype. It decodes one raw or compressed node run and returns the matching prefix length against caller-provided frames without walking parent or child links. Extend stackdepot KUnit coverage for raw and compressed exact matches, partial matches, shorter and longer inputs, first-frame mismatches, and invalid inputs. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private append-chain primitive from the userspace trie prototype. The helper builds unpublished raw or compressed trie nodes from caller-owned storage, splitting chains at frame-run boundaries and linking newly-created nodes with one-child arrays. Keep the helper inert for now: it does not publish nodes, allocate memory, or change stack_depot_save() and fetch routing. Cover raw chains, parent chains, frame-run boundary splits, and invalid storage inputs in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private append-publication primitive from the userspace trie prototype. The helper builds a replacement child array around an unpublished appended chain and installs it into caller-owned root or parent storage only after validation succeeds. Cover root publication, parent publication, duplicate rejection, root replacement, and bad input handling in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Make the private append-publication helper read the current child array with READ_ONCE() and publish the replacement with release ordering. This keeps the helper safe for future lockless trie readers. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private trie lookup-step classifier from the userspace trie prototype. The helper reads one root or parent child array with acquire ordering, compares the matching child node against caller frames, and reports whether the caller should append, descend, split, promote, or return an existing leaf. Keep the helper inert for now: it does not allocate, publish, or change stack_depot_save() and fetch routing. Cover append, descend, found, promote, split, and invalid-input classifications in stackdepot KUnit. Also make the counted-stack increment helper fail closed if the cmpxchg loser path observes a non-positive count instead of delegating that case to refcount_add(). Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Harden the private stackdepot trie preparation helpers before the backend starts routing production saves through them. The lookup step now keeps parent-chain validation with the multi-step walker that has the full matched prefix context, and the publication and scratch-buffer contracts document the required writer serialization and aliasing rules. Tighten page_owner stack-list accounting so a failed list-node allocation cannot leave an untracked marker count behind, and keep diagnostic stack counts from being resurrected after they reach zero. The arm64 frame compression helper now rejects the synthetic zero prefix explicitly. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add the private append-only insertion helper from the userspace trie prototype. The helper handles the case where no existing child starts with the next input frame: it preflights root or parent context, storage aliasing, existing-child state, and publication storage before building the unpublished append chain and publishing the replacement child array last. Cover root and parent append insertion, multi-run append insertion, zero-frame rejection, alias rejection, existing-child rejection, and failure atomicity in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Extend the private append-insertion helper so it can descend through fully matched trie nodes before appending the remaining stack suffix. The helper still rejects found, promote, and split cases so those operations can be implemented as separate, reviewable steps. Preflight descend storage against the published child arrays and subtrees before mutating caller-owned staging slots, preserving the copy-on-write publication contract. Cover one-level and multi-level descend insertion plus sibling-alias rejection in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Give stackdepot files an explicit MAINTAINERS section so stackdepot changes route to the mm tree and linux-kernel list directly instead of being matched only through the broad library-code entry. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Document the stackdepot prep assumptions that came up during review: arm64 frame compression uses adjacent high-bit buckets around the 2 GB module relocation window, saturated refcounts must fail positive-count tests, and page_owner keeps saturated stacks retryable when list marker tracking cannot be allocated. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Keep the trie and frame-run prep interfaces private to stackdepot so the public header only exposes APIs used outside lib/. The helpers are still inert, but their contracts now reject aliasing, overlong parent chains, count overflows, and untracked page_owner handles before later storage-routing patches can depend on them. Strengthen KUnit coverage for those edge cases and remove fixed-size test buffers so the tests scale with the configured stack depth. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Teach the private append insertion helper to promote a fully matched, childless internal trie node into a terminal leaf by publishing a copy-on-write replacement child array. Keep split and promote-with- children cases rejected until subtree COW support lands. Cover root-level promotion, descended promotion, and the childful rejection path in stackdepot KUnit. Also keep raw node matching on the direct raw-frame path so mismatch handling avoids the generic decoder. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Allow the private trie promotion path to promote internal nodes that already have children by carrying the child array into the replacement node and reparenting descendants before publication. This keeps the copy-on-write shape intact while preparing split insertion to preserve existing subtrees. Cover the childful promotion path in stackdepot KUnit and keep the test node-slot allocator limited to single-run inputs. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add a private helper that initializes a trie node from a contiguous slice of an existing node's frame run. This gives split insertion a copy-on-write building block for prefix and old-tail nodes without decoding or recompressing stored frame payloads. Cover raw, compressed, parent-chain, and invalid slice cases in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Add a private helper that builds the child array for a future split prefix from the displaced old tail and an optional new stack tail. The helper keeps child ordering centralized and reuses existing child-array validation so split insertion can publish a fully initialized prefix subtree later. Cover one-child, sorted two-child, duplicate-key, short-storage, and storage-overlap cases in stackdepot KUnit. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Document that trie-backed saves do not fall back to hash storage when trie insertion cannot proceed. This keeps trie_enabled pool pressure visible instead of mixing backends in the same run. Also fix a indentation issue in trie lookup. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Document that stack_depot_save() may return trie-backed handles when trie storage is enabled. Callers that need backend-independent stack contents must use stack_depot_fetch_into(), stack_depot_print(), or stack_depot_snprint(). Also tighten the stack_depot_fetch() kernel-doc to state that it only accepts hash-backed handles, matching the legacy pointer-returning API. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Make debugfs persistent counters explicitly hash-backed now that normal persistent saves can use trie storage. This avoids reading hash-only record counts as total stackdepot usage during trie validation. Also make the gdb stackdepot helper reject trie-backed handles instead of decoding them as hash pool offsets, and fix its pool-index diagnostic. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Initialize trie free-list buckets once during trie init instead of lazily checking and deriving that state from allocation paths. This removes repeated hot-path checks while keeping trie enablement as the single publication point for initialized trie state. Also remove a single-use transaction init wrapper, make side-table ID commit warn-only on impossible ordering, and drop a useless KUnit assertion that only checked a local initializer. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
Type replacement child-array storage, warn when trie pool rollback cannot unwind, and avoid a redundant parent-chain length walk during trie lookup. Also keep arch frame decompression infallible to match the compressor contract, retry side-table boundary races once, and drop small page_owner and KUnit dead checks. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
| ret = __stack_depot_trie_alloc_txn_reserve(req); | ||
| if (ret) | ||
| return ret; | ||
| storage = req->storage ? *req->storage : NULL; |
There was a problem hiding this comment.
is it safe for storage to be NULL here? This seems like overly defensive programming again. What's the invariant we should be checking?
Keep the page_owner changes in this series limited to routing stack saves through countable stackdepot records. Drop the independent seq_file and threshold fixes, along with formatting-only churn, so those changes do not get buried in the trie series. Signed-off-by: Caleb Kan <ckan@cloudflare.com>
| ret = __stack_depot_trie_lookup_step(root, parent, entries, nr_entries, &lookup); | ||
| if (ret) | ||
| return ret; | ||
| if (lookup.status != STACK_DEPOT_TRIE_LOOKUP_DESCEND) |
There was a problem hiding this comment.
instead of using a status flag for this, I would really prefer to see this expressed in code, e.g.
found = trie_find_child(root, parent, entries[0], &children, &node, &pos, &found);
if (!found)
append_here();
matched = node_match(node, entries, nr_entries);
if (matched < node->run.nr_entries)
split_node();
if (matched < nr_entries) {
parent = node;
entries += matched;
nr_entries -= matched;
continue;
}
if (node->leaf_id)
found_leaf();
else
promote_node();
For me, this is much easier to follow and makes the algorithm crystal clear. This is how things are done in kernel/bpf/lpm_trie.c, for example.
| size_t child_size; | ||
| int ret; | ||
|
|
||
| if (!child) |
There was a problem hiding this comment.
we just looked up the entry before this, how is this condition possible?
|
|
||
| if (!child) | ||
| return -EINVAL; | ||
| if (child->parent != parent) |
There was a problem hiding this comment.
this is an invariant bug. This needs to be WARN_ON() or WARN_ON_ONCE() (if it needs to be ratelimited). This should never happen.
| if (root) | ||
| return &root->children; | ||
| return &parent->children; | ||
| } |
There was a problem hiding this comment.
is it not possible to make this unnecessary by minimising our use of the stack_depot_trie_root type? Beyond some initial checks I would just expend to use root->node and then all this checking of root vs parent goes away?
| return 0; | ||
|
|
||
| return ALIGN(size, sizeof(unsigned long)); | ||
| } |
There was a problem hiding this comment.
i'm not sure why we need all of this validation? Why can't this just be:
static inline size_t stack_depot_trie_node_size(const struct stack_depot_frame_run *run)
{
return ALIGN(struct_size(node, data,
stack_depot_frame_run_bytes(run)), sizeof(unsigned long));
}
| unsigned int pos; | ||
| bool found; | ||
|
|
||
| if (!old_array) |
There was a problem hiding this comment.
how is this even possible? we have no old array and no new array?
| return -EINVAL; | ||
| if (found || !trie_child_array_can_append(old_array, pos)) | ||
| return -EINVAL; | ||
| { |
There was a problem hiding this comment.
please don't use these kinds of nested blocks. It took me 30 seconds to realise the open brakcet wasn't associated with the if() condition.
If you need variables declarations just stick them at the top of the fuction, or inside a nested block guarded by a condition, but not a naked one like this.
| return -EINVAL; | ||
| if (stack_depot_trie_child_lower_bound(old_array, frame, &pos, &found)) | ||
| return -EINVAL; | ||
| if (found || !trie_child_array_can_append(old_array, pos)) |
There was a problem hiding this comment.
i don't follow why we only check whether we can append way down here inside the append_prepare() function after checking whether we have a new array available. The logic flow seems really weird to reason about.
Either we need to append or we need a new array, why are we worrying about both cases in one code path?
| memset(&txn->pool, 0, sizeof(txn->pool)); | ||
| } | ||
|
|
||
| static int trie_side_publish_locked(const struct stack_depot_trie_leaf_update *updates, |
There was a problem hiding this comment.
this is only ever called with the logs already held. Drop the lockdep_assert_held() and hoist this function into trie_side_publish(), please.
| trie_child_array_publish_child((struct stack_depot_trie_child_array *)old_array, | ||
| pos, head); | ||
| /* Only tail append mutates a live array; COW arrays are unpublished. */ | ||
| WRITE_ONCE(((struct stack_depot_trie_child_array *)old_array)->nr_children, |
There was a problem hiding this comment.
it would really help reviewers to know that this is safe because A) concurrent writers are prohibited by stcak_depot_trie_workspace_lock and B) only readers need to see the updated value.
| } | ||
|
|
||
| static int | ||
| stack_depot_trie_child_lower_bound(const struct stack_depot_trie_child_array *array, |
There was a problem hiding this comment.
stack_depot_trie_slot_binsesarch() or something would be more descriptive here, I think. The salient point is "slot to insert the child" not "lower bound".
|
The trie insertion path is currently hard to review because most internal helpers are written defensively, as if they are public APIs receiving hostile inputs. That obscures the actual invariants. In particular, the path around
If those are the intended invariants, I think they should be documented once near the writer lock / child-array definition, and the internal helpers should rely on them. Today the code keeps rediscovering state: e.g. This makes the code look like it supports many impossible interleavings and partial states. A simpler contract would be: boundary/planning code validates once, then trusted build/publish helpers consume an explicit planned op ( I’m not asking for a rewrite of the trie algorithm. I’m asking to narrow the helper contracts so invalid states are designed out rather than checked everywhere. That should make the insert path much easier to review and reduce the rollback/error-path surface. |
commit 68938cc upstream. The xe driver keeps track of whether to probe display, and whether display hardware is there, using xe->info.probe_display. It gets set to false if there's no display after intel_display_device_probe(). However, the display may also be disabled via fuses, detected at a later time in intel_display_device_info_runtime_init(). In this case, the xe driver does for_each_intel_crtc() on uninitialized mode config in xe_display_flush_cleanup_work(), leading to a NULL pointer dereference, and generally calls display code with display info cleared. Check for intel_display_device_present() after intel_display_device_info_runtime_init(), and reset xe->info.probe_display as necessary. Also do unset_display_features() for completeness, although display runtime init has already done that. This will need to be unified across all cases later. Move intel_display_device_info_runtime_init() call slightly earlier, similar to i915, to avoid a bunch of unnecessary setup for no display cases. Note #1: The xe driver has no business doing low level display plumbing like for_each_intel_crtc() to begin with. It all needs to happen in display code. Note #2: The actual bug is present already in commit 44e6949 ("drm/xe/display: Implement display support"), but the oops was likely introduced later at commit ddf6492 ("drm/xe/display: Make display suspend/resume work on discrete"). Fixes: 44e6949 ("drm/xe/display: Implement display support") Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7904 Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/6150 Cc: stable@vger.kernel.org # v6.8+ Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> Link: https://patch.msgid.link/20260515160920.1082842-1-jani.nikula@intel.com Signed-off-by: Jani Nikula <jani.nikula@intel.com> (cherry picked from commit 7c3eb9f) Signed-off-by: Matthew Brost <matthew.brost@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
commit cb481e5 upstream. The length for the internal output buffer is calculated incorrectly, which can result overflow when a too small buffer is provided. Fix the bug by allocating internal output with the size of the maximum length of the cryptographic primitive instead of caller provided size. Link: https://lore.kernel.org/keyrings/20260531024914.3712130-1-jarkko@kernel.org/ Cc: stable@vger.kernel.org # v4.20+ Fixes: 00d60fd ("KEYS: Provide keyctls to drive the new key type ops for asymmetric keys [ver #2]") Reported-by: Alessandro Groppo <ale.grpp@gmail.com> Tested-by: Alessandro Groppo <ale.grpp@gmail.com> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
commit 40ef3ed upstream. The current implementation uses pci_num_vf() while holding the memory_lock to prevent changing the power state of a PF when VFs are enabled. This creates a lockdep circular dependency warning because memory_lock is held during device probing. [ 286.997167] ====================================================== [ 287.003363] WARNING: possible circular locking dependency detected [ 287.009562] 7.0.0-dbg-DEV #3 Tainted: G S [ 287.015074] ------------------------------------------------------ [ 287.021270] vfio_pci_sriov_/18636 is trying to acquire lock: [ 287.026942] ff45bea2294d4968 (&vdev->memory_lock){+.+.}-{4:4}, at: vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.036530] [ 287.036530] but task is already holding lock: [ 287.042383] ff45bea3a96b8230 (&new_dev_set->lock){+.+.}-{4:4}, at: vfio_group_fops_unl_ioctl+0x44d/0x7b0 [ 287.051879] [ 287.051879] which lock already depends on the new lock. [ 287.051879] [ 287.060070] [ 287.060070] the existing dependency chain (in reverse order) is: [ 287.067568] [ 287.067568] -> #2 (&new_dev_set->lock){+.+.}-{4:4}: [ 287.073941] __mutex_lock+0x92/0xb80 [ 287.078058] vfio_assign_device_set+0x66/0x1b0 [ 287.083042] vfio_pci_core_register_device+0xd1/0x2a0 [ 287.088638] vfio_pci_probe+0xd2/0x100 [ 287.092933] local_pci_probe_callback+0x4d/0xa0 [ 287.098001] process_scheduled_works+0x2ca/0x680 [ 287.103158] worker_thread+0x1e8/0x2f0 [ 287.107452] kthread+0x10c/0x140 [ 287.111230] ret_from_fork+0x18e/0x360 [ 287.115519] ret_from_fork_asm+0x1a/0x30 [ 287.119983] [ 287.119983] -> #1 ((work_completion)(&arg.work)){+.+.}-{0:0}: [ 287.127219] __flush_work+0x345/0x490 [ 287.131429] pci_device_probe+0x2e3/0x490 [ 287.135979] really_probe+0x1f9/0x4e0 [ 287.140180] __driver_probe_device+0x77/0x100 [ 287.145079] driver_probe_device+0x1e/0x110 [ 287.149803] __device_attach_driver+0xe3/0x170 [ 287.154789] bus_for_each_drv+0x125/0x150 [ 287.159346] __device_attach+0xca/0x1a0 [ 287.163720] device_initial_probe+0x34/0x50 [ 287.168445] pci_bus_add_device+0x6e/0x90 [ 287.172995] pci_iov_add_virtfn+0x3c9/0x3e0 [ 287.177719] sriov_add_vfs+0x2c/0x60 [ 287.181838] sriov_enable+0x306/0x4a0 [ 287.186038] vfio_pci_core_sriov_configure+0x184/0x220 [ 287.191715] sriov_numvfs_store+0xd9/0x1c0 [ 287.196351] kernfs_fop_write_iter+0x13f/0x1d0 [ 287.201338] vfs_write+0x2be/0x3b0 [ 287.205286] ksys_write+0x73/0x100 [ 287.209233] do_syscall_64+0x14d/0x750 [ 287.213529] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 287.219120] [ 287.219120] -> #0 (&vdev->memory_lock){+.+.}-{4:4}: [ 287.225491] __lock_acquire+0x14c6/0x2800 [ 287.230048] lock_acquire+0xd3/0x2f0 [ 287.234168] down_write+0x3a/0xc0 [ 287.238019] vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.243436] __rpm_callback+0x8c/0x310 [ 287.247730] rpm_resume+0x529/0x6f0 [ 287.251765] __pm_runtime_resume+0x68/0x90 [ 287.256402] vfio_pci_core_enable+0x44/0x310 [ 287.261216] vfio_pci_open_device+0x1c/0x80 [ 287.265947] vfio_df_open+0x10f/0x150 [ 287.270148] vfio_group_fops_unl_ioctl+0x4a4/0x7b0 [ 287.275476] __se_sys_ioctl+0x71/0xc0 [ 287.279679] do_syscall_64+0x14d/0x750 [ 287.283975] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 287.289559] [ 287.289559] other info that might help us debug this: [ 287.289559] [ 287.297582] Chain exists of: [ 287.297582] &vdev->memory_lock --> (work_completion)(&arg.work) --> &new_dev_set->lock [ 287.297582] [ 287.310023] Possible unsafe locking scenario: [ 287.310023] [ 287.315961] CPU0 CPU1 [ 287.320510] ---- ---- [ 287.325059] lock(&new_dev_set->lock); [ 287.328917] lock((work_completion)(&arg.work)); [ 287.336153] lock(&new_dev_set->lock); [ 287.342523] lock(&vdev->memory_lock); [ 287.346382] [ 287.346382] *** DEADLOCK *** [ 287.346382] [ 287.352315] 2 locks held by vfio_pci_sriov_/18636: [ 287.357125] #0: ff45bea208ed3e18 (&group->group_lock){+.+.}-{4:4}, at: vfio_group_fops_unl_ioctl+0x3e3/0x7b0 [ 287.367048] #1: ff45bea3a96b8230 (&new_dev_set->lock){+.+.}-{4:4}, at: vfio_group_fops_unl_ioctl+0x44d/0x7b0 [ 287.376976] [ 287.376976] stack backtrace: [ 287.381353] CPU: 191 UID: 0 PID: 18636 Comm: vfio_pci_sriov_ Tainted: G S 7.0.0-dbg-DEV #3 PREEMPTLAZY [ 287.381355] Tainted: [S]=CPU_OUT_OF_SPEC [ 287.381356] Call Trace: [ 287.381357] <TASK> [ 287.381358] dump_stack_lvl+0x54/0x70 [ 287.381361] print_circular_bug+0x2e1/0x300 [ 287.381363] check_noncircular+0xf9/0x120 [ 287.381364] ? __lock_acquire+0x5b4/0x2800 [ 287.381366] __lock_acquire+0x14c6/0x2800 [ 287.381368] ? pci_mmcfg_read+0x4f/0x220 [ 287.381370] ? pci_mmcfg_write+0x57/0x220 [ 287.381371] ? lock_acquire+0xd3/0x2f0 [ 287.381373] ? pci_mmcfg_write+0x57/0x220 [ 287.381374] ? lock_release+0xef/0x360 [ 287.381376] ? vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.381377] lock_acquire+0xd3/0x2f0 [ 287.381378] ? vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.381379] ? lock_is_held_type+0x76/0x100 [ 287.381382] down_write+0x3a/0xc0 [ 287.381382] ? vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.381383] vfio_pci_core_runtime_resume+0x1f/0xa0 [ 287.381384] ? __pfx_pci_pm_runtime_resume+0x10/0x10 [ 287.381385] __rpm_callback+0x8c/0x310 [ 287.381386] ? ktime_get_mono_fast_ns+0x3d/0xb0 [ 287.381389] ? __pfx_pci_pm_runtime_resume+0x10/0x10 [ 287.381390] rpm_resume+0x529/0x6f0 [ 287.381392] ? lock_is_held_type+0x76/0x100 [ 287.381394] __pm_runtime_resume+0x68/0x90 [ 287.381396] vfio_pci_core_enable+0x44/0x310 [ 287.381398] vfio_pci_open_device+0x1c/0x80 [ 287.381399] vfio_df_open+0x10f/0x150 [ 287.381401] vfio_group_fops_unl_ioctl+0x4a4/0x7b0 [ 287.381402] __se_sys_ioctl+0x71/0xc0 [ 287.381404] do_syscall_64+0x14d/0x750 [ 287.381405] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 287.381406] ? trace_irq_disable+0x25/0xd0 [ 287.381409] entry_SYSCALL_64_after_hwframe+0x77/0x7f Introduce a private flag 'sriov_active' in the vfio_pci_core_device struct. This allows the driver to track the SR-IOV power state requirement without relying on pci_num_vf() while holding the memory_lock. The lock is now only held to set the flag and ensure the device is in D0, after which pci_enable_sriov() can be called without the lock. Fixes: f4162eb ("vfio/pci: Change the PF power state to D0 before enabling VFs") Cc: stable@vger.kernel.org Suggested-by: Jason Gunthorpe <jgg@ziepe.ca> Suggested-by: Alex Williamson <alex@shazbot.org> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com> Link: https://lore.kernel.org/r/20260514173449.3282188-1-rananta@google.com [promote bitfield to plain bool to avoid storage-unit races] Signed-off-by: Alex Williamson <alex@shazbot.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
commit fa09f08 upstream. The etb10 miscdevice uses drvdata->reading as a shared exclusivity gate for userspace buffer access. etb_open() claims that gate with local_cmpxchg(), and etb_release() clears it with local_set(). That gate is shared per-device state rather than CPU-local state. A running system can reach it whenever /dev/<etb> is opened, closed, and reopened by different tasks while the device remains registered, so the same drvdata->reading variable may be claimed on one CPU and later cleared on another. This code used to use atomic_t for the same gate, but commit 27b10da ("coresight: etb10: moving to local atomic operations") changed it to local_t even though the access pattern remained cross-task and cross-CPU. Restore atomic_t together with atomic_cmpxchg() and atomic_set() so the exclusivity gate again uses a primitive intended for shared state. The issue was found on Linux v6.18.21 by our static analysis tool while scanning surviving local_t-on-shared-state sites, and then manually reviewed against the live etb10 file-op path. It was runtime-validated with a reproducible QEMU no-device KCSAN PoC that kept the same report-local contract: 1. use one shared struct etb_drvdata carrier and its drvdata->reading gate; 2. call etb_open() and etb_release() sequentially on that gate to confirm the original claim/clear path; 3. bind the open side to CPU0 and the release side to CPU1 for the same gate to show cross-CPU ownership; 4. run bound workers that repeatedly race etb_open() and etb_release() on the same gate until KCSAN reports a target hit. The harness recorded: L1 passed open=1 release=1 reading_after_open=1 reading_after_release=0 L2 passed open_cpu=0 release_cpu=1 cross_cpu_release=1 reading_after=0 open_ret=0 Representative KCSAN excerpt from the no-device validation run: BUG: KCSAN: data-race in etb_open.constprop.0.isra.0 [vuln_msv] write to 0xffffffffc0003810 of 4 bytes by task 216 on cpu 1: etb_open.constprop.0.isra.0+0x38/0x80 [vuln_msv] l3_worker_thread_fn+0x4f/0xf0 [vuln_msv] kthread+0x17e/0x1c0 ret_from_fork+0x22/0x30 read to 0xffffffffc0003810 of 4 bytes by task 215 on cpu 0: etb_open.constprop.0.isra.0+0x18/0x80 [vuln_msv] l3_worker_thread_fn+0x4f/0xf0 [vuln_msv] kthread+0x17e/0x1c0 ret_from_fork+0x22/0x30 value changed: 0x00000000 -> 0x00000001 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 215 Comm: etb10_l3_a Tainted: G O 6.1.66 #2 This no-device harness is not a real ETB10 hardware end-to-end run, but it preserves the same shared drvdata->reading gate and the same etb_open()/etb_release() claim/clear contract. No real ETB10 hardware was available for runtime testing. Build-tested with: make olddefconfig make -j"$(nproc)" drivers/hwtracing/coresight/coresight-etb10.o Fixes: 27b10da ("coresight: etb10: moving to local atomic operations") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn> Reviewed-by: James Clark <james.clark@linaro.org> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20260528165201.319452-1-runyu.xiao@seu.edu.cn Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
…softlockup commit 66366d2 upstream. We hit a real softlockup in an internal stress test environment. The workload was LTP memory/swap stress on a large arm64 machine, with 320 CPUs, about 1TB memory and an 8.6GB swap device. The system was under heavy load and the swap device had a large number of full clusters. The softlockup was triggered during a stress test after about 3 days. So, add periodic cond_resched() calls during large full_clusters reclaim operations to prevent softlockup issues. Detailed call trace as follow: PID: 3817773 TASK: ffff0883bb28b780 CPU: 48 COMMAND: "kworker/48:7" #0 [ffff800080183d10] __crash_kexec at ffffa4c1361e5de4 #1 [ffff800080183d90] panic at ffffa4c1360d5e9c #2 [ffff800080183e20] watchdog_timer_fn at ffffa4c136231fa8 ... #16 [ffff8000c4ad3cb0] swap_cache_del_folio at ffffa4c1363e1614 #17 [ffff8000c4ad3ce0] __try_to_reclaim_swap at ffffa4c1363e4bfc #18 [ffff8000c4ad3d40] swap_reclaim_full_clusters at ffffa4c1363e5474 #19 [ffff8000c4ad3da0] swap_reclaim_work at ffffa4c1363e550c #20 [ffff8000c4ad3dc0] process_one_work at ffffa4c136102edc #21 [ffff8000c4ad3e10] worker_thread at ffffa4c136103398 #22 [ffff8000c4ad3e70] kthread at ffffa4c13610d95c Link: https://lore.kernel.org/20260506130919.2298807-1-kerayhuang@tencent.com Fixes: 5168a68 ("mm, swap: avoid over reclaim of full clusters") Signed-off-by: Zijiang Huang <kerayhuang@tencent.com> Reviewed-by: Kairui Song <kasong@tencent.com> Reviewed-by: Hao Peng <flyingpeng@tencent.com> Reviewed-by: albinwyang <albinwyang@tencent.com> Reviewed-by: Baoquan He <baoquan.he@linux.dev> Acked-by: Chris Li <chrisl@kernel.org> Cc: Barry Song <baohua@kernel.org> Cc: Kairui Song <kasong@tencent.com> Cc: Kemeng Shi <shikemeng@huaweicloud.com> Cc: Nhat Pham <nphamcs@gmail.com> Cc: Youngjun Park <youngjun.park@lge.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
commit b9399d2 upstream. EHCI and FOTG210 isochronous submits build an ehci_iso_sched before linking the URB to the endpoint queue, and keep the staged schedule in urb->hcpriv until iso_stream_schedule() and the link helpers consume it. If the controller is no longer accessible, or usb_hcd_link_urb_to_ep() fails, submit jumps to done_not_linked before that handoff happens and leaks the staged schedule still attached to urb->hcpriv. Free the staged schedule from done_not_linked when submit fails before the URB is linked and clear urb->hcpriv after the free. The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1. An x86_64 allyesconfig build showed no new warnings. As we do not have an EHCI host controller with a USB isochronous device to test with, no runtime testing was able to be performed. Fixes: 8de9840 ("[PATCH] USB: Fix USB suspend/resume crasher (#2)") Fixes: e9df41c ("USB: make HCDs responsible for managing endpoint queues") Fixes: 7d50195 ("usb: host: Faraday fotg210-hcd driver") Cc: stable <stable@kernel.org> Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://patch.msgid.link/20260630071419.349161-1-dawei.feng@seu.edu.cn Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Summary
This ports the KRN-1117 stackdepot redesign to Linux 6.18.
DOG KASAN hosts can exhaust stackdepot pools because stackdepot currently deduplicates only byte-identical full stacks. The RFC and userspace prototype showed that these stacks still share many frame sequences, even when the whole stack is unique.
This adds an opt-in path-compressed trie backend for persistent stack saves. The trie stores shared frame runs once and compresses kernel text frames when the arch helper can reconstruct them safely.
stackdepot.trie_enableddefaults off. The next step is DOG one-off testing and validation.Design Notes
The legacy hash backend is still used for:
STACK_DEPOT_FLAG_GETpage_ownercount-helper pathsThe trie path is used only for persistent, non-refcounted stack saves.
This keeps refcounted eviction out of scope and preserves existing hash semantics for the callers that still need them.
Review Focus
The parts I would most like reviewed are:
stack_depot_fetch_into()Validation
Based on
linux-6.18.yatv6.18.35.Passed:
git diff --check greg/linux-6.18.y...HEADmm/page_owner.clib/stackdepot.oandlib/tests/stackdepot_kunit.o136/136136/136136/136stackdepot.trie_enabledenable/disable smokeRollout
This is still experimental. DOG needs to answer:
stack_depot_save()cost is acceptable