Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Missing cursor adjustment in `ttm_lru_bulk_move_add` when re-seeding an empty bulk move anchor causes recently-used resources to be prematurely evicted.
- [Medium] Computing `&man->lru[j]` when `man` is NULL in `ttm_bulk_move_drop_cursors` invokes Undefined Behavior and will trigger UBSAN panics.
--
--- Patch [1]: [PATCH] drm/ttm: Represent LRU bulk moves as nested sublists ---
commit b97657bee6dc1cddf7841bc260d33b4b040368e4
Author: Thomas Hellström <[email protected]>
Subject: drm/ttm: Represent LRU bulk moves as nested sublists
This patch changes the LRU bulk move mechanism to track each group as a
real nested sublist instead of ranges. Each group gets a persistent anchor
node linked on the manager LRU list along with a sublist holding its member
resources, simplifying cursor tracking and eliminating range-corruption bugs.
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/5387
> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
> index 4e6d3d658d858..195f960b2d738 100644
> --- a/drivers/gpu/drm/ttm/ttm_resource.c
> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
[ ... ]
> +static void ttm_bulk_move_drop_cursors(struct ttm_device *bdev,
> + struct ttm_lru_bulk_move *bulk)
> +{
> + unsigned int i, j;
> +
> + for (i = 0; i < TTM_NUM_MEM_TYPES; ++i) {
> + struct ttm_resource_manager *man = ttm_manager_type(bdev, i);
> +
> + for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) {
> + struct ttm_lru_bulk_move_pos *pos = &bulk->pos[i][j];
> + struct ttm_lru_item *lru, *next;
> +
> + list_for_each_entry_safe(lru, next, &pos->sublist, link) {
> + struct ttm_resource_cursor *cursor;
> +
> + if (ttm_lru_item_is_res(lru)) {
> + WARN_ON_ONCE(1);
> + continue;
> + }
> + /*
> + * This cursor descended here; its main hitch
> + * already sits on the manager list, so just
> + * detach it from this sublist.
> + */
> + cursor = container_of(lru, typeof(*cursor),
> + sublist_hitch);
> + cursor->cur_list = &man->lru[j];
> + list_del_init(&lru->link);
> + }
> + list_splice_tail_init(&pos->sublist, &man->lru[j]);
[Severity: Medium]
When ttm_manager_type() returns NULL for unused memory types, doesn't the
pointer arithmetic &man->lru[j] result in undefined behavior?
If the kernel is compiled with UBSAN, this can trigger a panic even if the
list operations don't actually dereference the pointer. Should there be a
check like if (!man) continue; before the inner loop?
> + list_del_init(&pos->marker.link);
> + }
> + }
> +}
[ ... ]
> +/* Add the resource to a bulk_move sublist */
> static void ttm_lru_bulk_move_add(struct ttm_lru_bulk_move *bulk,
> struct ttm_resource *res)
> {
> struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
> + struct ttm_resource *first = ttm_lru_first_res_or_null(&pos->sublist);
> + struct ttm_buffer_object *bo = res->bo;
> + struct ttm_resource_manager *man =
> + ttm_manager_type(bo->bdev, res->mem_type);
>
> - if (!pos->first) {
> - pos->first = res;
> - pos->last = res;
> + if (first) {
> - WARN_ON(pos->first->bo->base.resv != res->bo->base.resv);
> - ttm_lru_bulk_move_pos_tail(pos, res);
> + WARN_ON(first->bo->base.resv != res->bo->base.resv);
> } else {
> + /*
> + * Group empty (first activation, or all members were pinned
> + * or swapped out); re-seed the anchor at the tail so it
> + * counts as recently used.
> + */
> + list_move_tail(&pos->marker.link, &man->lru[bo->priority]);
> }
[Severity: High]
If an active LRU traversal cursor has descended into this sublist and all
resources are subsequently removed, the sublist becomes empty except for the
cursor's hitch.
When a new resource is added and 'first' is NULL, we re-seed the anchor to
the tail of the manager's LRU list. However, could this leave the descended
cursor parked in the sublist without adjusting it?
If ttm_lru_bulk_move_pos_adjust_cursors() is not called to detach it, the
resumed traversal might immediately process and evict this newly added
resource, violating the LRU guarantee.
> + /*
> + * The resource may still be on another list (manager LRU or
> + * bdev->unevictable); move it unconditionally to keep group
> + * membership consistent.
> + */
> + list_move_tail(&res->lru.link, &pos->sublist);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.