From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A26A8460; Mon, 4 May 2026 04:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.11 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777868787; cv=none; b=FzcF1C+GCFj+jJIeyA07cT9hHnasbjDi8Y9bCXZH4Vr9bRmTKwnxFKSXrMXBp0979Dgls+1RO9JecRoixOa1Z/mtR+vOA/VmQ8LPl7w2xWCbtZJwlInaSYstEZOKO400+XP7SLYN43ofGjhCNByc0OjC/WJAzK/v/SsPnb6xTgk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777868787; c=relaxed/simple; bh=zQoMfteVnaQntgARLaVx8wlm8c/AUEr2e+lBsP4Ho+M=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type; b=t8SWPFJnYLJCl87+yY3wy7CsXXT630hzAjEMwqYmaf3xn/UNyRZobkIT7rSfyBRlyRuFcb7vo+EjvKaonk26kp87TKHRROflRaTmJjHuZdM/tWIuVriB4YHuFf1V26rmSXaQCV12FQa5vVJvfeM0COoZtvRGK+RRxqTqiKQRP8M= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=mVFgeO7f; arc=none smtp.client-ip=192.198.163.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="mVFgeO7f" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1777868785; x=1809404785; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=zQoMfteVnaQntgARLaVx8wlm8c/AUEr2e+lBsP4Ho+M=; b=mVFgeO7fsbukB63RdrA/+6ov4LF4RVIfpKfPFHmKQs4M9ycbeotcrZSQ DWLq+zkl3fpxv90gglkUNuWPphciiA1NuqcrBahYMZtri1K/92SibdtiL rqbUEIoxuoMkQu44xX1aIFNt/gSU1Z5l2I7B4bZ3zXSlDURv35zI+QBSl Ou62mYBzBPOUMAys3AnBrbksSyjYZ3UHiD7chlt2rhGf423NOe752yH57 Gx3vPEFFeGBRLxLsVf6MQFGtN19hT9RZYuvlZXcBat3VlevEMpJheey96 t2TFcYSgSNilxrjBEhxs+Rzszz+9qjQ54pNVTOplgXN9a4/DNnfz4Ooxc Q==; X-CSE-ConnectionGUID: esNtiOulS4e+V2N1RyjDwg== X-CSE-MsgGUID: fg+fJGheTTOT8p54PqZIXg== X-IronPort-AV: E=McAfee;i="6800,10657,11775"; a="89310104" X-IronPort-AV: E=Sophos;i="6.23,214,1770624000"; d="scan'208";a="89310104" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 May 2026 21:26:24 -0700 X-CSE-ConnectionGUID: Y0w/qymWRYSKFzEN1c0S/w== X-CSE-MsgGUID: ML5LaMruRSyjXh94W4zzfQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,214,1770624000"; d="scan'208";a="235666547" Received: from gsse-cloud1.jf.intel.com ([10.54.39.91]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 May 2026 21:26:23 -0700 From: Matthew Brost To: intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org Cc: Christian Koenig , Huang Rui , Matthew Auld , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , linux-kernel@vger.kernel.org, stable@vger.kernel.org, =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Subject: [PATCH] drm/ttm/pool: back up at native page order Date: Sun, 3 May 2026 21:26:19 -0700 Message-Id: <20260504042619.2896273-1-matthew.brost@intel.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ttm_pool_split_for_swap() splits high-order pool pages into order-0 pages during backup so each 4K page can be released to the system as soon as it has been written to shmem. While this minimizes the allocator's working set during reclaim, it actively fragments memory: every TTM-backed compound page that the shrinker touches is shattered into order-0 pages, even when the rest of the system would prefer that the high-order block stay intact. Under sustained kswapd pressure this is enough to drive other parts of MM into recovery loops from which they cannot easily escape, because the memory TTM just freed is no longer contiguous. Stop splitting on the backup path and back up each compound atomically at its native order in ttm_pool_backup(): - For each non-handle slot, read the order from the head page and back up all 1<pages[] as we go. - On any per-subpage backup failure, drop the handles we just wrote for this compound and restore the original page pointers, so the compound is left fully intact and may be retried later. shrunken is only incremented once the whole compound succeeds. - On success, the compound is freed once at its native order. No split_page(), no per-4K refcount juggling, no fragmentation introduced from this path. - Slots that already hold a backup handle from a previous partial attempt are skipped. A compound that would extend past a fault-injection-truncated num_pages is skipped rather than split. The restore-side leftover-page branch in ttm_pool_restore_commit() is left as-is for now: that path can still split a previously-retained compound, but in practice it is unreachable under realistic workloads (per profiling we have not been able to trigger it), so it is not worth complicating the restore state machine to avoid the split there. If it ever becomes a problem in practice it can be addressed independently. ttm_pool_split_for_swap() itself is retained for the restore path's sole remaining caller. The DMA-mapped pre-backup unmap loop, the purge path, ttm_pool_free_*, and ttm_pool_unmap_and_free() already operate at native order and are unchanged. Cc: Christian Koenig Cc: Huang Rui Cc: Matthew Auld Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Simona Vetter Cc: dri-devel@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Fixes: b63d715b8090 ("drm/ttm/pool, drm/ttm/tt: Provide a helper to shrink pages") Suggested-by: Thomas Hellström Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Matthew Brost --- A follow-up should attempt writeback to shmem at folio order as well, but the API for doing so is unclear and may be incomplete. This patch is related to the pending series [1] and significantly reduces the likelihood of Xe entering a kswapd loop under fragmentation. The kswapd → shrinker → Xe shrinker → TTM backup path is still exercised; however, with this change the backup path no longer worsens fragmentation, which previously amplified reclaim pressure and reinforced the kswapd loop. Nonetheless, the pathological case that [1] aims to address still exists and requires a proper solution. Even with this patch, a kswapd loop due to severe fragmentation can still be triggered, although it is now substantially harder to reproduce. [1] https://patchwork.freedesktop.org/series/165330/ --- drivers/gpu/drm/ttm/ttm_pool.c | 71 +++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index 278bbe7a11ad..5ead0aba4bb7 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -1036,12 +1036,11 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt, { struct file *backup = tt->backup; struct page *page; - unsigned long handle; gfp_t alloc_gfp; gfp_t gfp; int ret = 0; pgoff_t shrunken = 0; - pgoff_t i, num_pages; + pgoff_t i, num_pages, npages; if (WARN_ON(ttm_tt_is_backed_up(tt))) return -EINVAL; @@ -1097,28 +1096,72 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt, if (IS_ENABLED(CONFIG_FAULT_INJECTION) && should_fail(&backup_fault_inject, 1)) num_pages = DIV_ROUND_UP(num_pages, 2); - for (i = 0; i < num_pages; ++i) { - s64 shandle; + for (i = 0; i < num_pages; i += npages) { + unsigned int order; + pgoff_t j; + npages = 1; page = tt->pages[i]; if (unlikely(!page)) continue; - ttm_pool_split_for_swap(pool, page); + /* Already-handled entry from a previous attempt. */ + if (unlikely(ttm_backup_page_ptr_is_handle(page))) + continue; - shandle = ttm_backup_backup_page(backup, page, flags->writeback, i, - gfp, alloc_gfp); - if (shandle < 0) { - /* We allow partially shrunken tts */ - ret = shandle; + order = ttm_pool_page_order(pool, page); + npages = 1UL << order; + + /* + * Back up the compound atomically at its native order. If + * fault injection truncated num_pages mid-compound, skip + * the partial tail rather than splitting. + */ + if (unlikely(i + npages > num_pages)) break; + + for (j = 0; j < npages; ++j) { + unsigned long handle; + s64 shandle; + + if (IS_ENABLED(CONFIG_FAULT_INJECTION) && + should_fail(&backup_fault_inject, 1)) + shandle = -1; + else + shandle = ttm_backup_backup_page(backup, page + j, + flags->writeback, + i + j, gfp, + alloc_gfp); + + if (unlikely(shandle < 0)) { + pgoff_t k; + + ret = shandle; + /* + * Roll back: drop the handles we just wrote + * and restore the original page pointers so + * the compound remains intact and may be + * retried later. + */ + for (k = 0; k < j; ++k) { + handle = ttm_backup_page_ptr_to_handle(tt->pages[i + k]); + ttm_backup_drop(backup, handle); + tt->pages[i + k] = page + k; + } + + goto out; + } + handle = shandle; + tt->pages[i + j] = ttm_backup_handle_to_page_ptr(shandle); } - handle = shandle; - tt->pages[i] = ttm_backup_handle_to_page_ptr(handle); - __free_pages_gpu_account(page, 0, false); - shrunken++; + + /* Compound fully backed up; free at native order. */ + page->private = 0; + __free_pages_gpu_account(page, order, false); + shrunken += npages; } +out: return shrunken ? shrunken : ret; } -- 2.34.1