mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper
@ 2026-07-21 17:47 Matthew Brost
  2026-07-21 17:47 ` [PATCH 2/2] drm/ttm: use shmem_backup_folio() for folio backup Matthew Brost
  2026-07-22  9:43 ` [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Christoph Hellwig
  0 siblings, 2 replies; 4+ messages in thread
From: Matthew Brost @ 2026-07-21 17:47 UTC (permalink / raw)
  To: intel-xe, dri-devel, linux-mm, linux-kernel
  Cc: Hugh Dickins, Baolin Wang, Andrew Morton, Christian Koenig,
	Huang Rui, Matthew Auld, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter,
	Christoph Hellwig

Add a new generic helper, shmem_backup_folio(), that copies the pages
of an arbitrary source folio into a range of a shmem-backed file,
optionally issuing writeback for each destination folio. It is
extracted from drivers/gpu/drm/ttm's existing shmem-backup loop so
that other subsystems (starting with TTM in a follow-up patch) can
share the same implementation.

Semantics:

  - On full success, 0 is returned and *nr_pages_backed is set to
    (1 << order).
  - On a mid-range -ENOMEM after at least one destination folio has
    been populated, the partial backup is retained: *nr_pages_backed
    holds the successfully backed-up prefix and -ENOMEM is returned so
    the caller can commit that prefix and decide how to proceed
    (e.g. via a reactive split-and-retry path).
  - On any other error, or -ENOMEM with no progress, the pages already
    written are truncated from the backup file via
    shmem_truncate_range(), *nr_pages_backed is reset to 0, and the
    original error is returned.

@order is passed explicitly rather than derived from
folio_order(@folio). Some callers (e.g. TTM) allocate high-order
pages without __GFP_COMP, so folio_order() on such a "folio-shaped"
range would report 0.

folio_mark_dirty() runs after the copy loop, matching the kernel
write-path convention of lock -> modify -> mark_dirty.

Cc: Hugh Dickins <hughd@google.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Huang Rui <ray.huang@amd.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: David Airlie <airlied@gmail.com>
Cc: Simona Vetter <simona@ffwll.ch>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Assisted-by: GitHub-Copilot:claude-sonnet-5

---

The patch is based on drm-tip rather than the core MM branches to
facilitate Intel CI testing and initial review. It can be rebased onto
the core MM branches in a subsequent revision.
---
 include/linux/shmem_fs.h |   3 +
 mm/shmem.c               | 125 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 128 insertions(+)

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index e729b9b0e38d..541f1ab675b7 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -127,6 +127,9 @@ int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
 		struct list_head *folio_list);
 void shmem_truncate_range(struct inode *inode, loff_t start, uoff_t end);
 int shmem_unuse(unsigned int type);
+int shmem_backup_folio(struct folio *folio, struct file *backup, pgoff_t index,
+		       gfp_t gfp, unsigned int order, pgoff_t *nr_pages_backed,
+		       bool writeback);
 
 #if defined(CONFIG_TRANSPARENT_HUGEPAGE) && defined(CONFIG_SHMEM)
 unsigned long shmem_allowable_huge_orders(struct inode *inode,
diff --git a/mm/shmem.c b/mm/shmem.c
index b51f83c970bb..bc11c4039b7b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -5961,3 +5961,128 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
 	return page;
 }
 EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);
+
+/**
+ * shmem_backup_folio() - Copy a folio's contents into a shmem-backed file.
+ * @folio: Source folio whose contents are to be backed up. Must remain
+ *	pinned by the caller for the duration of the call. The source folio
+ *	is not modified; on success its contents live in @backup and the
+ *	caller may release the source memory.
+ * @backup: A file previously created with shmem_file_setup() (or a wrapper
+ *	such as ttm_backup_shmem_create()). Must be shmem-backed;
+ *	non-shmem files are rejected with -EINVAL.
+ * @index: shmem page index at which to begin storing the backup. The
+ *	subpages of @folio are written to consecutive indices starting at
+ *	@index. The caller is responsible for ensuring the range
+ *	[@index, @index + nr_pages) does not collide with other in-flight
+ *	backups against the same @backup.
+ * @gfp: Allocation flags used when reading/allocating the destination
+ *	shmem folios.
+ * @order: Number of source subpages to copy, expressed as a power of two
+ *	(nr_pages = 1 << @order). Passed explicitly rather than derived
+ *	from folio_order(@folio) so that callers may back up higher-order
+ *	page ranges that were allocated without __GFP_COMP (and for which
+ *	folio_order() would therefore return 0).
+ * @nr_pages_backed: Out parameter. Reset to 0 on entry. On any return
+ *	value, holds the number of source subpages whose contents are
+ *	guaranteed to be present in @backup and reachable via consecutive
+ *	shmem indices starting at @index. A value less than (1 << @order)
+ *	with return value -ENOMEM indicates a partial backup that the
+ *	caller may keep (see below).
+ * @writeback: If true, attempt immediate writeout of each destination
+ *	shmem folio after it is populated. This trades throughput for
+ *	promptly evicting the backup from page cache. Only meaningful for
+ *	unmapped destination folios.
+ *
+ * Copy the contents of @folio into @backup starting at shmem index
+ * @index, one destination shmem folio at a time. Destination folios may
+ * themselves be higher-order; the copy loop advances by the natural
+ * order of each destination folio so a large destination folio is
+ * populated in a single iteration.
+ *
+ * The function distinguishes two failure modes:
+ *
+ *  - Mid-folio -ENOMEM after at least one destination folio has been
+ *    populated: the partial backup is *retained*. @nr_pages_backed is
+ *    left at the number of subpages successfully copied so far, and
+ *    -ENOMEM is returned. Callers that support partial backup (e.g. a
+ *    subsequent split-and-retry of the source) can commit the returned
+ *    prefix by treating handles [@index, @index + *@nr_pages_backed) as
+ *    valid.
+ *
+ *  - Any other error, or -ENOMEM with no progress: the pages already
+ *    written (if any) are truncated from @backup via
+ *    shmem_truncate_range(), @nr_pages_backed is reset to 0, and the
+ *    original error is returned. On return the caller owns no valid
+ *    handles in @backup.
+ *
+ * Context: May sleep. The caller is responsible for any locking of
+ * @backup's page range against concurrent access.
+ *
+ * Return: 0 on full success (all 1 << @order subpages backed up),
+ * -ENOMEM on partial success (see above), or another negative errno on
+ * failure (backup fully rolled back).
+ */
+int shmem_backup_folio(struct folio *folio, struct file *backup, pgoff_t index,
+		       gfp_t gfp, unsigned int order, pgoff_t *nr_pages_backed,
+		       bool writeback)
+{
+	struct address_space *mapping = backup->f_mapping;
+	int nr_pages = 1 << order;
+	int ret, i;
+
+	*nr_pages_backed = 0;
+	if (!shmem_file(backup))
+		return -EINVAL;
+
+	for (i = 0; i < nr_pages; ) {
+		struct folio *to_folio;
+		int to_nr, j;
+
+		to_folio = shmem_read_folio_gfp(mapping, index + i, gfp);
+		if (IS_ERR(to_folio)) {
+			ret = PTR_ERR(to_folio);
+
+			/* All errors aside from -ENOMEM drop partial backup */
+			if (*nr_pages_backed && ret != -ENOMEM) {
+				shmem_truncate_range(file_inode(backup),
+						     (loff_t)index << PAGE_SHIFT,
+						     ((loff_t)(index + i) << PAGE_SHIFT) - 1);
+				*nr_pages_backed = 0;
+			}
+
+			return ret;
+		}
+
+		to_nr = min_t(int, nr_pages - i,
+			      folio_next_index(to_folio) - (index + i));
+
+		folio_mark_accessed(to_folio);
+		folio_lock(to_folio);
+
+		for (j = 0; j < to_nr; j++)
+			copy_highpage(folio_file_page(to_folio, index + i + j),
+				      folio_page(folio, i + j));
+
+		folio_mark_dirty(to_folio);
+
+		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);
+		}
+
+		folio_put(to_folio);
+		i += to_nr;
+		*nr_pages_backed = i;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(shmem_backup_folio);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] drm/ttm: use shmem_backup_folio() for folio backup
  2026-07-21 17:47 [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Matthew Brost
@ 2026-07-21 17:47 ` Matthew Brost
  2026-07-22  9:43 ` [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Christoph Hellwig
  1 sibling, 0 replies; 4+ messages in thread
From: Matthew Brost @ 2026-07-21 17:47 UTC (permalink / raw)
  To: intel-xe, dri-devel, linux-mm, linux-kernel
  Cc: Hugh Dickins, Baolin Wang, Andrew Morton, Christian Koenig,
	Huang Rui, Matthew Auld, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter,
	Christoph Hellwig

Replace the open-coded shmem-backup loop in ttm_backup_backup_folio()
with a thin wrapper around the new shmem_backup_folio() helper. The
wrapper maps the helper's (int errno, *nr_pages_backed) contract onto
TTM's existing (s64 handle) return convention:

  - 0                                     -> base handle
  - -ENOMEM with *nr_pages_backed > 0     -> base handle (short backup;
                                             partial progress kept)
  - any other error                       -> that error verbatim

The mid-compound -ENOMEM fault-injection point that used to live
inside the per-subpage loop moves up to the wrapper and takes a new
shape: instead of synthesizing an error partway through the loop, the
wrapper passes order-1 to shmem_backup_folio() when
ttm_backup_fault_inject_folio() fires. shmem_backup_folio() then
backs up the first half of the compound normally, returns 0 with
*nr_pages_backed = (1 << (order - 1)), and TTM's caller sees the same
"short backup, nr_backed < (1 << order)" it would see on a real
mid-compound OOM and drives its reactive-split path unchanged.
Injection is skipped for order == 0 since there is nothing to shrink;
the previous "inject only on i > 0" guard mapped onto the same
observable subset of runs.

No functional change intended for non-injection paths.

Cc: Hugh Dickins <hughd@google.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Huang Rui <ray.huang@amd.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: David Airlie <airlied@gmail.com>
Cc: Simona Vetter <simona@ffwll.ch>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Assisted-by: GitHub-Copilot:claude-sonnet-5

---

The patch is based on drm-tip rather than the core MM branches to
facilitate Intel CI testing and initial review. It can be rebased onto
the core MM branches in a subsequent revision.
---
 drivers/gpu/drm/ttm/ttm_backup.c | 91 ++++++++------------------------
 1 file changed, 21 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
index 3c067aadc52d..a6c4e6cb643b 100644
--- a/drivers/gpu/drm/ttm/ttm_backup.c
+++ b/drivers/gpu/drm/ttm/ttm_backup.c
@@ -105,76 +105,27 @@ ttm_backup_backup_folio(struct file *backup, struct folio *folio,
 			gfp_t folio_gfp, gfp_t alloc_gfp,
 			pgoff_t *nr_pages_backed)
 {
-	struct address_space *mapping = backup->f_mapping;
-	int nr_pages = 1 << order;
-	struct folio *to_folio;
-	int ret, i;
-
-	*nr_pages_backed = 0;
-
-	for (i = 0; i < nr_pages; ) {
-		int to_nr, j;
-
-		/*
-		 * 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 (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);
-		}
-
-		folio_put(to_folio);
-		i += to_nr;
-		*nr_pages_backed = i;
-	}
-
-	return ttm_backup_shmem_idx_to_handle(idx);
+	unsigned int backup_order = order;
+	int err;
+
+	/*
+	 * Fault injection: back up only the first half of the folio to
+	 * simulate a mid-compound OOM. The caller sees *nr_pages_backed
+	 * < (1 << order) on success and drives its reactive-split path
+	 * exactly as it would on a real short return. order == 0 cannot
+	 * be shrunk further, so injection is skipped in that case.
+	 */
+	if (IS_ENABLED(CONFIG_FAULT_INJECTION) && order &&
+	    ttm_backup_fault_inject_folio())
+		backup_order = order - 1;
+
+	err = shmem_backup_folio(folio, backup, idx, alloc_gfp, backup_order,
+				 nr_pages_backed, writeback);
+
+	if (!err || (err == -ENOMEM && *nr_pages_backed))
+		return ttm_backup_shmem_idx_to_handle(idx);
+
+	return err;
 }
 
 /**
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper
  2026-07-21 17:47 [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Matthew Brost
  2026-07-21 17:47 ` [PATCH 2/2] drm/ttm: use shmem_backup_folio() for folio backup Matthew Brost
@ 2026-07-22  9:43 ` Christoph Hellwig
  2026-07-22 20:11   ` Matthew Brost
  1 sibling, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2026-07-22  9:43 UTC (permalink / raw)
  To: Matthew Brost
  Cc: intel-xe, dri-devel, linux-mm, linux-kernel, Hugh Dickins,
	Baolin Wang, Andrew Morton, Christian Koenig, Huang Rui,
	Matthew Auld, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter,
	Christoph Hellwig

On Tue, Jul 21, 2026 at 10:47:22AM -0700, Matthew Brost wrote:
> Add a new generic helper, shmem_backup_folio(), that copies the pages
> of an arbitrary source folio into a range of a shmem-backed file,
> optionally issuing writeback for each destination folio. It is
> extracted from drivers/gpu/drm/ttm's existing shmem-backup loop so
> that other subsystems (starting with TTM in a follow-up patch) can
> share the same implementation.

Hmm, what is the difference to just doing a ITER_BVEC write with a bvec
containing the folio for this the pure write to shmem part of this?

You'd probably want a kernel_write_iter helper wrapping
__kernel_write_iter for the writecount, but otherwise this sounds
like a normal write.

We'd want something for the writeback part, preferably a purely
range based API to be generic.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper
  2026-07-22  9:43 ` [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Christoph Hellwig
@ 2026-07-22 20:11   ` Matthew Brost
  0 siblings, 0 replies; 4+ messages in thread
From: Matthew Brost @ 2026-07-22 20:11 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: intel-xe, dri-devel, linux-mm, linux-kernel, Hugh Dickins,
	Baolin Wang, Andrew Morton, Christian Koenig, Huang Rui,
	Matthew Auld, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter

On Wed, Jul 22, 2026 at 11:43:50AM +0200, Christoph Hellwig wrote:
> On Tue, Jul 21, 2026 at 10:47:22AM -0700, Matthew Brost wrote:
> > Add a new generic helper, shmem_backup_folio(), that copies the pages
> > of an arbitrary source folio into a range of a shmem-backed file,
> > optionally issuing writeback for each destination folio. It is
> > extracted from drivers/gpu/drm/ttm's existing shmem-backup loop so
> > that other subsystems (starting with TTM in a follow-up patch) can
> > share the same implementation.
> 
> Hmm, what is the difference to just doing a ITER_BVEC write with a bvec
> containing the folio for this the pure write to shmem part of this?

Thanks for the pointer here. I'm somewhat ignorant of filesystem-related
details.

There is slightly less GFP control since kernel reserves can't be dipped
into for the forward process, but perhaps that doesn't matter. There are
also slightly different locking chains (more on that below).

> 
> You'd probably want a kernel_write_iter helper wrapping
> __kernel_write_iter for the writecount, but otherwise this sounds
> like a normal write.
> 

I tried writing a `kernel_write_iter()` wrapper around
__kernel_write_iter() that performs file_start_write()/file_end_write(),
as suggested by the comment above __kernel_write_iter(), but lockdep
[1] isn't happy. 

We have a hard requirement in DRM to shrink under dma-resv locks which
creates the circle:

pipe->mutex -> mmap_lock -> dma_resv -> sb_writers -> pipe->mutex

If I simply export __kernel_write_iter(), bypassing
file_start_write()/file_end_write() and therefore bypassing sb_writers,
this seems to work.

I think this is safe for shmem files, but it's difficult to say with
100% certainty given my lack of filesystem knowledge, or whether
exposing a dangerous low-level bypass function for files would be
acceptable.

> We'd want something for the writeback part, preferably a purely
> range based API to be generic.

I found filemap_fdatawrite_range for this part.

Matt

[1] Lockdep splat:

[  105.374023] ======================================================
[  105.375386] WARNING: possible circular locking dependency detected
[  105.375396] 7.2.0-rc4-xe-01637-g40a493568fe3 #1290 Not tainted
[  105.375406] ------------------------------------------------------
[  105.375416] cat/3121 is trying to acquire lock:
[  105.375425] ffff888105677460 (&pipe->mutex){+.+.}-{3:3}, at: iter_file_splice_write+0xb9/0x550
[  105.375444]
               but task is already holding lock:
[  105.375453] ffff888112889420 (sb_writers#5){.+.+}-{0:0}, at: __do_splice+0xc4/0x180
[  105.375468]
               which lock already depends on the new lock.

[  105.375480]
               the existing dependency chain (in reverse order) is:
[  105.375492]
               -> #3 (sb_writers#5){.+.+}-{0:0}:
[  105.375503]        kernel_write_iter+0xaa/0x270
[  105.375513]        ttm_backup_backup_folio+0x95/0x130 [ttm]
[  105.375529]        ttm_pool_backup+0x376/0x560 [ttm]
[  105.375541]        ttm_tt_backup+0x32/0x60 [ttm]
[  105.375552]        ttm_bo_shrink+0x76/0x140 [ttm]
[  105.375564]        xe_bo_shrink+0x19e/0x290 [xe]
[  105.375642]        __xe_shrinker_walk+0xfb/0x310 [xe]
[  105.375803]        xe_shrinker_walk+0x36/0xc0 [xe]
[  105.375885]        xe_shrinker_scan+0x110/0x1e0 [xe]
[  105.376067]        do_shrink_slab+0x151/0x6c0
[  105.376076]        shrink_slab+0x140/0x8b0
[  105.376083]        drop_slab+0x3e/0x90
[  105.376092]        drop_caches_sysctl_handler+0x74/0xc0
[  105.376102]        proc_sys_call_handler+0x16c/0x230
[  105.376112]        vfs_write+0x3ae/0x560
[  105.376119]        ksys_write+0x66/0xe0
[  105.376127]        do_syscall_64+0xca/0x540
[  105.376136]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  105.376146]
               -> #2 (reservation_ww_class_mutex){+.+.}-{3:3}:
[  105.376159]        __ww_mutex_lock.constprop.0+0xca/0x1960
[  105.376170]        ww_mutex_lock_interruptible+0x26/0x90
[  105.376180]        xe_gem_object_mmap+0x1d/0x120 [xe]
[  105.376241]        drm_gem_mmap_obj+0x6c/0x190 [drm]
[  105.376417]        drm_gem_mmap+0x44/0xb0 [drm]
[  105.376446]        __mmap_region+0x8d0/0x10b0
[  105.376453]        mmap_region+0x157/0x180
[  105.376459]        do_mmap+0x4fb/0x660
[  105.376467]        vm_mmap_pgoff+0xae/0x190
[  105.376473]        ksys_mmap_pgoff+0x15e/0x200
[  105.376480]        do_syscall_64+0xca/0x540
[  105.376486]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  105.376494]
               -> #1 (&mm->mmap_lock){++++}-{3:3}:
[  105.376503]        __might_fault+0x4a/0x70
[  105.376509]        _copy_from_iter+0x4a/0x740
[  105.376517]        copy_page_from_iter+0x7a/0x100
[  105.376524]        anon_pipe_write+0x30f/0x7e0
[  105.376531]        vfs_write+0x43c/0x560
[  105.376537]        ksys_write+0xbc/0xe0
[  105.376543]        do_syscall_64+0xca/0x540
[  105.376549]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  105.376556]
               -> #0 (&pipe->mutex){+.+.}-{3:3}:
[  105.376565]        __lock_acquire+0x13c1/0x2400
[  105.376573]        lock_acquire+0xcb/0x310
[  105.376822]        __mutex_lock+0x9d/0x10f0
[  105.377067]        iter_file_splice_write+0xb9/0x550
[  105.377311]        do_splice+0x360/0x9f0
[  105.377551]        __do_splice+0xc4/0x180
[  105.377786]        __x64_sys_splice+0x89/0x110
[  105.378022]        do_syscall_64+0xca/0x540
[  105.378255]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  105.378500]
               other info that might help us debug this:

[  105.379182] Chain exists of:
                 &pipe->mutex --> reservation_ww_class_mutex --> sb_writers#5

[  105.379856]  Possible unsafe locking scenario:

[  105.380297]        CPU0                    CPU1
[  105.380517]        ----                    ----
[  105.380736]   rlock(sb_writers#5);
[  105.380954]                                lock(reservation_ww_class_mutex);
[  105.381174]                                lock(sb_writers#5);
[  105.381393]   lock(&pipe->mutex);
[  105.381609]
                *** DEADLOCK ***

[  105.382240] 1 lock held by cat/3121:
[  105.382452]  #0: ffff888112889420 (sb_writers#5){.+.+}-{0:0}, at: __do_splice+0xc4/0x180
[  105.382675]
               stack backtrace:
[  105.383108] CPU: 10 UID: 0 PID: 3121 Comm: cat Not tainted 7.2.0-rc4-xe-01637-g40a493568fe3 #1290 PREEMPT(full)
[  105.383110] Hardware name: Intel Corporation Raptor Lake Client Platform/RPL-S ADP-S DDR5 UDIMM CRB, BIOS RPLSFWI1.R00.5045.A00.2401260733 01/26/2024
[  105.383111] Call Trace:
[  105.383111]  <TASK>
[  105.383112]  dump_stack_lvl+0x82/0xd0
[  105.383115]  print_circular_bug+0x2d2/0x400
[  105.383116]  check_noncircular+0x12d/0x150
[  105.383117]  ? kernel_text_address+0x5b/0xc0
[  105.383121]  __lock_acquire+0x13c1/0x2400
[  105.383123]  lock_acquire+0xcb/0x310
[  105.383124]  ? iter_file_splice_write+0xb9/0x550
[  105.383126]  __mutex_lock+0x9d/0x10f0
[  105.383128]  ? iter_file_splice_write+0xb9/0x550
[  105.383128]  ? _raw_spin_unlock_irqrestore+0x41/0x70
[  105.383130]  ? iter_file_splice_write+0xb9/0x550
[  105.383131]  ? __kmalloc_noprof+0x3e0/0x5b0
[  105.383133]  ? iter_file_splice_write+0xa3/0x550
[  105.383134]  ? iter_file_splice_write+0xb9/0x550
[  105.383135]  iter_file_splice_write+0xb9/0x550
[  105.383138]  do_splice+0x360/0x9f0
[  105.383139]  __do_splice+0xc4/0x180
[  105.383141]  __x64_sys_splice+0x89/0x110
[  105.383142]  do_syscall_64+0xca/0x540
[  105.383144]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  105.383145] RIP: 0033:0x5601751088ae
[  105.383146] Code: 55 48 89 e5 53 49 89 f0 8b 3f 31 db 48 ba 01 00 00 00 00 00 00 00 4d 85 c0 74 3e b8 13 01 00 00 31 f6 45 31 d2 45 31 c9 0f 05 <48> 3d 01 f0 ff ff 0f 9d c1 48 85 c0 40 0f 98 c6 40 84 f1 75 05 49
[  105.383147] RSP: 002b:00007ffdccdc35f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000113
[  105.383148] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00005601751088ae
[  105.383149] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000009
[  105.383150] RBP: 00007ffdccdc3600 R08: 000000000000013e R09: 0000000000000000
[  105.383150] R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000000a
[  105.383151] R13: 00007ffdccdd36c0 R14: 00000000001a02ef R15: 00007ffdccdd36d0

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-22 20:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-21 17:47 [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Matthew Brost
2026-07-21 17:47 ` [PATCH 2/2] drm/ttm: use shmem_backup_folio() for folio backup Matthew Brost
2026-07-22  9:43 ` [PATCH 1/2] mm/shmem: add shmem_backup_folio() helper Christoph Hellwig
2026-07-22 20:11   ` Matthew Brost

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®