summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/ttm/ttm_backup.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-07-24 14:11:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-07-24 14:11:53 -0700
commite2a936998ab25cf7272847356390041c3143b498 (patch)
tree9ebc19e3dcf018ae4bc4b91f91e5273932780473 /drivers/gpu/drm/ttm/ttm_backup.c
parentdad0a87d79ff3e7e4ef35ebd588fe4f115329964 (diff)
parent6c33542c01eac1ac4d5595c1ba2dace0e27e842d (diff)
downloadlinux-e2a936998ab25cf7272847356390041c3143b498.tar.gz
linux-e2a936998ab25cf7272847356390041c3143b498.tar.bz2
linux-e2a936998ab25cf7272847356390041c3143b498.zip
Merge tag 'drm-fixes-2026-07-25' of https://gitlab.freedesktop.org/drm/kernel
Pull drm fixes from Dave Airlie: "Weekly drm pull request, small and scattered seems to be the new normal, the ttm change is probably the largest, with xe being the most. Alex was out this week so amdgpu is smaller and only has some urgent fixes. MAINTAINERS: - update mailmap address ttm: - backup pages using correct order gpusvm: - fix mm leak on eviction - properly zero page array in mm scanning tests: - fix dma mask errors in tests panel: - fix dependency issues - ilitek-ili9881c - fix probing i915: - Remove DP_EDP_BACKLIGHT_AUX_ENABLE_CAP check for DPCD backlight xe: - Skip invalidation for purgeable state updates - Add drm_dev guards when detaching CCS read / write buffers - Alloc per domain unique i2c id - Fix SVM leak on resv obj alloc failure in xe_vm_create amdgpu: - Fix a backport mistake for dm_gpureset_toggle_interrupts() - Fix a failure on flip-done timeouts for mode1 reset appletbdrm: - fix issue in damage handling amdxdna: - fix command timeout race imagination: - fix gpu vm locking vc4: - prevent trusted bo from being mapped again - prevent timer rearm on shutdown v3d: - fix NULL deref in unbind - idle AXI before clock disable on suspend - use proper GMP access for newer hw vmwgfx: - validate shader array size ethosu: - fix length calculations - handle internal chaining buffers gma500: - return errors from HDMI i2c reads" * tag 'drm-fixes-2026-07-25' of https://gitlab.freedesktop.org/drm/kernel: (31 commits) drm/amd/display: Fix missing DCE check in dm_gpureset_toggle_interrupts() drm/amd/display: Fix flip-done timeouts on mode1 reset Revert "drm/pagemap: Guard HPAGE_PMD_ORDER use with CONFIG_ARCH_ENABLE_THP_MIGRATION" drm/vc4: Shut down BO cache timer before teardown drm/tests: shmem: Set DMA mask to 64-bit in drm_gem_shmem drm/xe/vm: Fix SVM leak on resv obj alloc failure in xe_vm_create() drm/xe/i2c: Allow per domain unique id drm/gma500: return errors from Oaktrail HDMI I2C reads drm/vc4: hvs/v3d: Fix null dereference in unbind drm/panel: fix unmet dependency bug for DRM_PANEL_HIMAX_HX83121A drm/panel: s6e3ha8: fix unmet dependency on DRM_DISPLAY_HELPER drm/panel: ilitek-ili9882t: fix unmet dependency for DRM_PANEL_ILITEK_ILI9882T drm/panel: ilitek-ili9881c: do not fail probe if iovcc is absent drm/v3d: Idle AXI transactions before disabling the clock on suspend drm/v3d: Reach the GMP through the hub registers on V3D 7.x mailmap: Update MaĆ­ra Canal's email address drm/pagemap: Guard HPAGE_PMD_ORDER use with CONFIG_ARCH_ENABLE_THP_MIGRATION drm/pagemap: Clear driver-provided PFNs from migration PFN array drm/xe/vf: Add drm_dev guards when detaching CCS read/write buffers accel: ethosu: Handle U85 internal chaining buffer ...
Diffstat (limited to 'drivers/gpu/drm/ttm/ttm_backup.c')
-rw-r--r--drivers/gpu/drm/ttm/ttm_backup.c123
1 files changed, 82 insertions, 41 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
index 81df4cb5606b..3c067aadc52d 100644
--- a/drivers/gpu/drm/ttm/ttm_backup.c
+++ b/drivers/gpu/drm/ttm/ttm_backup.c
@@ -6,9 +6,10 @@
#include <drm/ttm/ttm_backup.h>
#include <linux/export.h>
-#include <linux/page-flags.h>
#include <linux/swap.h>
+#include "ttm_pool_internal.h"
+
/*
* Need to map shmem indices to handle since a handle value
* of 0 means error, following the swp_entry_t convention.
@@ -68,17 +69,23 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
}
/**
- * ttm_backup_backup_page() - Backup a page
+ * ttm_backup_backup_folio() - Backup a folio
* @backup: The struct backup pointer to use.
- * @page: The page to back up.
- * @writeback: Whether to perform immediate writeback of the page.
+ * @folio: The folio to back up.
+ * @order: The allocation order of @folio. Since TTM allocates higher-order
+ * pages without __GFP_COMP, folio_nr_pages(@folio) would always
+ * return 1; the caller must pass the true order explicitly.
+ * @writeback: Whether to perform immediate writeback of the folio's pages.
* This may have performance implications.
- * @idx: A unique integer for each page and each struct backup.
+ * @idx: A unique integer for the first page of the folio and each struct backup.
* This allows the backup implementation to avoid managing
* its address space separately.
- * @page_gfp: The gfp value used when the page was allocated.
- * This is used for accounting purposes.
+ * @folio_gfp: The gfp value used when the folio was allocated.
+ * Currently unused.
* @alloc_gfp: The gfp to be used when allocating memory.
+ * @nr_pages_backed: Output. On a successful return, set to the number of
+ * pages actually backed up, which may be less than (1 << @order)
+ * if an -ENOMEM was encountered mid-folio.
*
* Context: If called from reclaim context, the caller needs to
* assert that the shrinker gfp has __GFP_FS set, to avoid
@@ -87,53 +94,87 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
* that the shrinker gfp has __GFP_IO set, since without it,
* we're not allowed to start backup IO.
*
- * Return: A handle on success. Negative error code on failure.
- *
- * Note: This function could be extended to back up a folio and
- * implementations would then split the folio internally if needed.
- * Drawback is that the caller would then have to keep track of
- * the folio size- and usage.
+ * Return: A handle for the first backed-up page on success (handles for
+ * subsequent pages follow sequentially). -ENOMEM if no pages could be backed
+ * up. Any other negative error code if a non-ENOMEM failure occurred; in that
+ * case any pages backed up so far are truncated before returning.
*/
s64
-ttm_backup_backup_page(struct file *backup, struct page *page,
- bool writeback, pgoff_t idx, gfp_t page_gfp,
- gfp_t alloc_gfp)
+ttm_backup_backup_folio(struct file *backup, struct folio *folio,
+ unsigned int order, bool writeback, pgoff_t idx,
+ gfp_t folio_gfp, gfp_t alloc_gfp,
+ pgoff_t *nr_pages_backed)
{
struct address_space *mapping = backup->f_mapping;
- unsigned long handle = 0;
+ int nr_pages = 1 << order;
struct folio *to_folio;
- int ret;
+ int ret, i;
- to_folio = shmem_read_folio_gfp(mapping, idx, alloc_gfp);
- if (IS_ERR(to_folio))
- return PTR_ERR(to_folio);
+ *nr_pages_backed = 0;
- folio_mark_accessed(to_folio);
- folio_lock(to_folio);
- folio_mark_dirty(to_folio);
- copy_highpage(folio_file_page(to_folio, idx), page);
- handle = ttm_backup_shmem_idx_to_handle(idx);
+ for (i = 0; i < nr_pages; ) {
+ int to_nr, j;
- if (writeback && !folio_mapped(to_folio) &&
- folio_clear_dirty_for_io(to_folio)) {
- folio_set_reclaim(to_folio);
- ret = shmem_writeout(to_folio, NULL, NULL);
- if (!folio_test_writeback(to_folio))
- folio_clear_reclaim(to_folio);
/*
- * If writeout succeeds, it unlocks the folio. errors
- * are otherwise dropped, since writeout is only best
- * effort here.
+ * Only inject past the first subpage so *nr_pages_backed is
+ * always > 0 here, matching a genuine mid-compound -ENOMEM
+ * and driving the caller's reactive split fallback instead
+ * of an early, no-progress failure.
*/
- if (ret)
+ if (IS_ENABLED(CONFIG_FAULT_INJECTION) && i &&
+ ttm_backup_fault_inject_folio())
+ to_folio = ERR_PTR(-ENOMEM);
+ else
+ to_folio = shmem_read_folio_gfp(mapping, idx + i, alloc_gfp);
+ if (IS_ERR(to_folio)) {
+ int err = PTR_ERR(to_folio);
+
+ if (err == -ENOMEM && *nr_pages_backed)
+ return ttm_backup_shmem_idx_to_handle(idx);
+
+ if (*nr_pages_backed) {
+ shmem_truncate_range(file_inode(backup),
+ (loff_t)idx << PAGE_SHIFT,
+ ((loff_t)(idx + i) << PAGE_SHIFT) - 1);
+ /*
+ * The pages just truncated are no longer
+ * backed up; don't let the caller mistake
+ * them for valid handles.
+ */
+ *nr_pages_backed = 0;
+ }
+ return err;
+ }
+
+ to_nr = min_t(int, nr_pages - i,
+ folio_next_index(to_folio) - (idx + i));
+
+ folio_mark_accessed(to_folio);
+ folio_lock(to_folio);
+ folio_mark_dirty(to_folio);
+
+ for (j = 0; j < to_nr; j++)
+ copy_highpage(folio_file_page(to_folio, idx + i + j),
+ folio_page(folio, i + j));
+
+ if (writeback && !folio_mapped(to_folio) &&
+ folio_clear_dirty_for_io(to_folio)) {
+ folio_set_reclaim(to_folio);
+ ret = shmem_writeout(to_folio, NULL, NULL);
+ if (!folio_test_writeback(to_folio))
+ folio_clear_reclaim(to_folio);
+ if (ret == AOP_WRITEPAGE_ACTIVATE)
+ folio_unlock(to_folio);
+ } else {
folio_unlock(to_folio);
- } else {
- folio_unlock(to_folio);
- }
+ }
- folio_put(to_folio);
+ folio_put(to_folio);
+ i += to_nr;
+ *nr_pages_backed = i;
+ }
- return handle;
+ return ttm_backup_shmem_idx_to_handle(idx);
}
/**