Archive-only list for patches
 help / color / mirror / Atom feed
diff for duplicates of <20260917151607.082567058@linuxfoundation.org>

diff --git a/a/1.txt b/N1/1.txt
index f9a6c40..40d41a5 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -1,47 +1,154 @@
-6.18-stable review patch.  If anyone has any objections, please let me know.
+6.12-stable review patch.  If anyone has any objections, please let me know.
 
 ------------------
 
-From: Jia Jia <physicalmtea@gmail.com>
+From: Qu Wenruo <wqu@suse.com>
 
-[ Upstream commit 22598f55a4c2b510b3df5e69e563387a963222ae ]
+[ Upstream commit 1e5773e0bab761c853eaf7286394905a544ef02d ]
 
-vhost-scsi translates guest response descriptors into userspace iovecs
-when commands are submitted.  Target-core completes those commands
-asynchronously, so VHOST_SET_MEM_TABLE can replace the memory table while
-an in-flight command still retains response iovecs translated through the
-old table.
+The function btrfs_punch_hole_lock_range() needs to make sure there is
+no other folio in the range, thus it goes with filemap_range_has_page(),
+which works pretty fine.
 
-If the old mapping is reused after VHOST_SET_MEM_TABLE returns, command
-completion can write the response to an unrelated userspace object.
+But if we have large folios, under the following case
+filemap_range_has_page() will always return true, forcing
+btrfs_punch_hole_lock_range() to do a very time consuming busy loop:
 
-Flush the vhost-scsi backend after vhost_dev_ioctl() handles a device
-ioctl.  This waits for in-flight commands that can still use the old
-response iovecs before the ioctl returns.
+        start                            end
+        |                                |
+  |//|//|//|//|  |  |  |  |  |  |  |  |//|//|
+   \         /                         \   /
+    Folio A                            Folio B
 
-Signed-off-by: Jia Jia <physicalmtea@gmail.com>
-Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-Message-ID: <20260724060919.1569170-1-physicalmtea@gmail.com>
+In the above case, folio A and B contain our start/end indexes, and there
+are no other folios in the range.  Thus we do not need to retry inside
+btrfs_punch_hole_lock_range().
+
+To prepare for large data folios, introduce a helper,
+check_range_has_page(), which will:
+
+- Shrink the search range towards page boundaries
+  If the rounded down end (exclusive, otherwise it can underflow when @end
+  is inside the folio at file offset 0) is no larger than the rounded up
+  start, it means the range contains no other pages other than the ones
+  covering @start and @end.
+
+  Can return false directly in that case.
+
+- Grab all the folios inside the range
+
+- Skip any large folios that cover the start and end indexes
+
+- If any other folios are found return true
+
+- Otherwise return false
+
+This new helper is going to handle both large folios and regular ones.
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 3f950867c307 ("btrfs: fix extent map leak in NOCOW direct I/O write")
 Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 ---
- drivers/vhost/scsi.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
-index 29716ce714554..deb4c8bfd3d57 100644
---- a/drivers/vhost/scsi.c
-+++ b/drivers/vhost/scsi.c
-@@ -2448,9 +2448,10 @@ vhost_scsi_ioctl(struct file *f,
- 	default:
- 		mutex_lock(&vs->dev.mutex);
- 		r = vhost_dev_ioctl(&vs->dev, ioctl, argp);
--		/* TODO: flush backend after dev ioctl. */
- 		if (r == -ENOIOCTLCMD)
- 			r = vhost_vring_ioctl(&vs->dev, ioctl, argp);
-+		else
-+			vhost_scsi_flush(vs);
- 		mutex_unlock(&vs->dev.mutex);
- 		return r;
- 	}
--- 
-2.53.0
+ fs/btrfs/file.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 56 insertions(+), 11 deletions(-)
+
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -2204,11 +2204,29 @@ static int find_first_non_hole(struct bt
+ 	return ret;
+ }
+ 
+-static void btrfs_punch_hole_lock_range(struct inode *inode,
+-					const u64 lockstart,
+-					const u64 lockend,
+-					struct extent_state **cached_state)
++/*
++ * Check if there is no folio in the range.
++ *
++ * We cannot utilize filemap_range_has_page() in a filemap with large folios
++ * as we can hit the following false positive:
++ *
++ *        start                            end
++ *        |                                |
++ *  |//|//|//|//|  |  |  |  |  |  |  |  |//|//|
++ *   \         /                         \   /
++ *    Folio A                            Folio B
++ *
++ * That large folio A and B cover the start and end indexes.
++ * In that case filemap_range_has_page() will always return true, but the above
++ * case is fine for btrfs_punch_hole_lock_range() usage.
++ *
++ * So here we only ensure that no other folios is in the range, excluding the
++ * head/tail large folio.
++ */
++static bool check_range_has_page(struct inode *inode, u64 start, u64 end)
+ {
++	struct folio_batch fbatch;
++	bool ret = false;
+ 	/*
+ 	 * For subpage case, if the range is not at page boundary, we could
+ 	 * have pages at the leading/tailing part of the range.
+@@ -2219,17 +2237,45 @@ static void btrfs_punch_hole_lock_range(
+ 	 *
+ 	 * And do not decrease page_lockend right now, as it can be 0.
+ 	 */
+-	const u64 page_lockstart = round_up(lockstart, PAGE_SIZE);
+-	const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE);
++	const u64 page_lockstart = round_up(start, PAGE_SIZE);
++	const u64 page_lockend = round_down(end + 1, PAGE_SIZE);
++	const pgoff_t start_index = page_lockstart >> PAGE_SHIFT;
++	const pgoff_t end_index = (page_lockend - 1) >> PAGE_SHIFT;
++	pgoff_t tmp = start_index;
++	int found_folios;
++
++	/* The same page or adjacent pages. */
++	if (page_lockend <= page_lockstart)
++		return false;
+ 
++	folio_batch_init(&fbatch);
++	found_folios = filemap_get_folios(inode->i_mapping, &tmp, end_index, &fbatch);
++	for (int i = 0; i < found_folios; i++) {
++		struct folio *folio = fbatch.folios[i];
++
++		/* A large folio begins before the start. Not a target. */
++		if (folio->index < start_index)
++			continue;
++		/* A large folio extends beyond the end. Not a target. */
++		if (folio->index + folio_nr_pages(folio) > end_index)
++			continue;
++		/* A folio doesn't cover the head/tail index. Found a target. */
++		ret = true;
++		break;
++	}
++	folio_batch_release(&fbatch);
++	return ret;
++}
++
++static void btrfs_punch_hole_lock_range(struct inode *inode,
++					const u64 lockstart, const u64 lockend,
++					struct extent_state **cached_state)
++{
+ 	while (1) {
+ 		truncate_pagecache_range(inode, lockstart, lockend);
+ 
+ 		lock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+ 			    cached_state);
+-		/* The same page or adjacent pages. */
+-		if (page_lockend <= page_lockstart)
+-			break;
+ 		/*
+ 		 * We can't have ordered extents in the range, nor dirty/writeback
+ 		 * pages, because we have locked the inode's VFS lock in exclusive
+@@ -2240,8 +2286,7 @@ static void btrfs_punch_hole_lock_range(
+ 		 * locking the range check if we have pages in the range, and if
+ 		 * we do, unlock the range and retry.
+ 		 */
+-		if (!filemap_range_has_page(inode->i_mapping, page_lockstart,
+-					    page_lockend - 1))
++		if (!check_range_has_page(inode, lockstart, lockend))
+ 			break;
+ 
+ 		unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,
diff --git a/a/content_digest b/N1/content_digest
index 1fc73d4..e5589ab 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -1,61 +1,169 @@
- "ref\020260917151551.901433442@linuxfoundation.org\0"
+ "ref\020260917151539.408551884@linuxfoundation.org\0"
  "From\0Greg Kroah-Hartman <gregkh@linuxfoundation.org>\0"
- "Subject\0[PATCH 6.18 0559/1250] vhost-scsi: flush backend after device ioctls\0"
- "Date\0Thu, 17 Sep 2026 16:05:54 +0100\0"
+ "Subject\0[PATCH 6.12 1047/1102] btrfs: prepare btrfs_punch_hole_lock_range() for large data folios\0"
+ "Date\0Thu, 17 Sep 2026 16:16:30 +0100\0"
  "To\0stable@vger.kernel.org\0"
  "Cc\0Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
   patches@lists.linux.dev
-  Jia Jia <physicalmtea@gmail.com>
-  Michael S. Tsirkin <mst@redhat.com>
+  Filipe Manana <fdmanana@suse.com>
+  Qu Wenruo <wqu@suse.com>
+  David Sterba <dsterba@suse.com>
  " Sasha Levin <sashal@kernel.org>\0"
  "\00:1\0"
  "b\0"
- "6.18-stable review patch.  If anyone has any objections, please let me know.\n"
+ "6.12-stable review patch.  If anyone has any objections, please let me know.\n"
  "\n"
  "------------------\n"
  "\n"
- "From: Jia Jia <physicalmtea@gmail.com>\n"
+ "From: Qu Wenruo <wqu@suse.com>\n"
  "\n"
- "[ Upstream commit 22598f55a4c2b510b3df5e69e563387a963222ae ]\n"
+ "[ Upstream commit 1e5773e0bab761c853eaf7286394905a544ef02d ]\n"
  "\n"
- "vhost-scsi translates guest response descriptors into userspace iovecs\n"
- "when commands are submitted.  Target-core completes those commands\n"
- "asynchronously, so VHOST_SET_MEM_TABLE can replace the memory table while\n"
- "an in-flight command still retains response iovecs translated through the\n"
- "old table.\n"
+ "The function btrfs_punch_hole_lock_range() needs to make sure there is\n"
+ "no other folio in the range, thus it goes with filemap_range_has_page(),\n"
+ "which works pretty fine.\n"
  "\n"
- "If the old mapping is reused after VHOST_SET_MEM_TABLE returns, command\n"
- "completion can write the response to an unrelated userspace object.\n"
+ "But if we have large folios, under the following case\n"
+ "filemap_range_has_page() will always return true, forcing\n"
+ "btrfs_punch_hole_lock_range() to do a very time consuming busy loop:\n"
  "\n"
- "Flush the vhost-scsi backend after vhost_dev_ioctl() handles a device\n"
- "ioctl.  This waits for in-flight commands that can still use the old\n"
- "response iovecs before the ioctl returns.\n"
+ "        start                            end\n"
+ "        |                                |\n"
+ "  |//|//|//|//|  |  |  |  |  |  |  |  |//|//|\n"
+ "   \\         /                         \\   /\n"
+ "    Folio A                            Folio B\n"
  "\n"
- "Signed-off-by: Jia Jia <physicalmtea@gmail.com>\n"
- "Signed-off-by: Michael S. Tsirkin <mst@redhat.com>\n"
- "Message-ID: <20260724060919.1569170-1-physicalmtea@gmail.com>\n"
+ "In the above case, folio A and B contain our start/end indexes, and there\n"
+ "are no other folios in the range.  Thus we do not need to retry inside\n"
+ "btrfs_punch_hole_lock_range().\n"
+ "\n"
+ "To prepare for large data folios, introduce a helper,\n"
+ "check_range_has_page(), which will:\n"
+ "\n"
+ "- Shrink the search range towards page boundaries\n"
+ "  If the rounded down end (exclusive, otherwise it can underflow when @end\n"
+ "  is inside the folio at file offset 0) is no larger than the rounded up\n"
+ "  start, it means the range contains no other pages other than the ones\n"
+ "  covering @start and @end.\n"
+ "\n"
+ "  Can return false directly in that case.\n"
+ "\n"
+ "- Grab all the folios inside the range\n"
+ "\n"
+ "- Skip any large folios that cover the start and end indexes\n"
+ "\n"
+ "- If any other folios are found return true\n"
+ "\n"
+ "- Otherwise return false\n"
+ "\n"
+ "This new helper is going to handle both large folios and regular ones.\n"
+ "\n"
+ "Reviewed-by: Filipe Manana <fdmanana@suse.com>\n"
+ "Signed-off-by: Qu Wenruo <wqu@suse.com>\n"
+ "Signed-off-by: David Sterba <dsterba@suse.com>\n"
+ "Stable-dep-of: 3f950867c307 (\"btrfs: fix extent map leak in NOCOW direct I/O write\")\n"
  "Signed-off-by: Sasha Levin <sashal@kernel.org>\n"
+ "Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>\n"
  "---\n"
- " drivers/vhost/scsi.c | 3 ++-\n"
- " 1 file changed, 2 insertions(+), 1 deletion(-)\n"
- "\n"
- "diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c\n"
- "index 29716ce714554..deb4c8bfd3d57 100644\n"
- "--- a/drivers/vhost/scsi.c\n"
- "+++ b/drivers/vhost/scsi.c\n"
- "@@ -2448,9 +2448,10 @@ vhost_scsi_ioctl(struct file *f,\n"
- " \tdefault:\n"
- " \t\tmutex_lock(&vs->dev.mutex);\n"
- " \t\tr = vhost_dev_ioctl(&vs->dev, ioctl, argp);\n"
- "-\t\t/* TODO: flush backend after dev ioctl. */\n"
- " \t\tif (r == -ENOIOCTLCMD)\n"
- " \t\t\tr = vhost_vring_ioctl(&vs->dev, ioctl, argp);\n"
- "+\t\telse\n"
- "+\t\t\tvhost_scsi_flush(vs);\n"
- " \t\tmutex_unlock(&vs->dev.mutex);\n"
- " \t\treturn r;\n"
- " \t}\n"
- "-- \n"
- 2.53.0
+ " fs/btrfs/file.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++----------\n"
+ " 1 file changed, 56 insertions(+), 11 deletions(-)\n"
+ "\n"
+ "--- a/fs/btrfs/file.c\n"
+ "+++ b/fs/btrfs/file.c\n"
+ "@@ -2204,11 +2204,29 @@ static int find_first_non_hole(struct bt\n"
+ " \treturn ret;\n"
+ " }\n"
+ " \n"
+ "-static void btrfs_punch_hole_lock_range(struct inode *inode,\n"
+ "-\t\t\t\t\tconst u64 lockstart,\n"
+ "-\t\t\t\t\tconst u64 lockend,\n"
+ "-\t\t\t\t\tstruct extent_state **cached_state)\n"
+ "+/*\n"
+ "+ * Check if there is no folio in the range.\n"
+ "+ *\n"
+ "+ * We cannot utilize filemap_range_has_page() in a filemap with large folios\n"
+ "+ * as we can hit the following false positive:\n"
+ "+ *\n"
+ "+ *        start                            end\n"
+ "+ *        |                                |\n"
+ "+ *  |//|//|//|//|  |  |  |  |  |  |  |  |//|//|\n"
+ "+ *   \\         /                         \\   /\n"
+ "+ *    Folio A                            Folio B\n"
+ "+ *\n"
+ "+ * That large folio A and B cover the start and end indexes.\n"
+ "+ * In that case filemap_range_has_page() will always return true, but the above\n"
+ "+ * case is fine for btrfs_punch_hole_lock_range() usage.\n"
+ "+ *\n"
+ "+ * So here we only ensure that no other folios is in the range, excluding the\n"
+ "+ * head/tail large folio.\n"
+ "+ */\n"
+ "+static bool check_range_has_page(struct inode *inode, u64 start, u64 end)\n"
+ " {\n"
+ "+\tstruct folio_batch fbatch;\n"
+ "+\tbool ret = false;\n"
+ " \t/*\n"
+ " \t * For subpage case, if the range is not at page boundary, we could\n"
+ " \t * have pages at the leading/tailing part of the range.\n"
+ "@@ -2219,17 +2237,45 @@ static void btrfs_punch_hole_lock_range(\n"
+ " \t *\n"
+ " \t * And do not decrease page_lockend right now, as it can be 0.\n"
+ " \t */\n"
+ "-\tconst u64 page_lockstart = round_up(lockstart, PAGE_SIZE);\n"
+ "-\tconst u64 page_lockend = round_down(lockend + 1, PAGE_SIZE);\n"
+ "+\tconst u64 page_lockstart = round_up(start, PAGE_SIZE);\n"
+ "+\tconst u64 page_lockend = round_down(end + 1, PAGE_SIZE);\n"
+ "+\tconst pgoff_t start_index = page_lockstart >> PAGE_SHIFT;\n"
+ "+\tconst pgoff_t end_index = (page_lockend - 1) >> PAGE_SHIFT;\n"
+ "+\tpgoff_t tmp = start_index;\n"
+ "+\tint found_folios;\n"
+ "+\n"
+ "+\t/* The same page or adjacent pages. */\n"
+ "+\tif (page_lockend <= page_lockstart)\n"
+ "+\t\treturn false;\n"
+ " \n"
+ "+\tfolio_batch_init(&fbatch);\n"
+ "+\tfound_folios = filemap_get_folios(inode->i_mapping, &tmp, end_index, &fbatch);\n"
+ "+\tfor (int i = 0; i < found_folios; i++) {\n"
+ "+\t\tstruct folio *folio = fbatch.folios[i];\n"
+ "+\n"
+ "+\t\t/* A large folio begins before the start. Not a target. */\n"
+ "+\t\tif (folio->index < start_index)\n"
+ "+\t\t\tcontinue;\n"
+ "+\t\t/* A large folio extends beyond the end. Not a target. */\n"
+ "+\t\tif (folio->index + folio_nr_pages(folio) > end_index)\n"
+ "+\t\t\tcontinue;\n"
+ "+\t\t/* A folio doesn't cover the head/tail index. Found a target. */\n"
+ "+\t\tret = true;\n"
+ "+\t\tbreak;\n"
+ "+\t}\n"
+ "+\tfolio_batch_release(&fbatch);\n"
+ "+\treturn ret;\n"
+ "+}\n"
+ "+\n"
+ "+static void btrfs_punch_hole_lock_range(struct inode *inode,\n"
+ "+\t\t\t\t\tconst u64 lockstart, const u64 lockend,\n"
+ "+\t\t\t\t\tstruct extent_state **cached_state)\n"
+ "+{\n"
+ " \twhile (1) {\n"
+ " \t\ttruncate_pagecache_range(inode, lockstart, lockend);\n"
+ " \n"
+ " \t\tlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,\n"
+ " \t\t\t    cached_state);\n"
+ "-\t\t/* The same page or adjacent pages. */\n"
+ "-\t\tif (page_lockend <= page_lockstart)\n"
+ "-\t\t\tbreak;\n"
+ " \t\t/*\n"
+ " \t\t * We can't have ordered extents in the range, nor dirty/writeback\n"
+ " \t\t * pages, because we have locked the inode's VFS lock in exclusive\n"
+ "@@ -2240,8 +2286,7 @@ static void btrfs_punch_hole_lock_range(\n"
+ " \t\t * locking the range check if we have pages in the range, and if\n"
+ " \t\t * we do, unlock the range and retry.\n"
+ " \t\t */\n"
+ "-\t\tif (!filemap_range_has_page(inode->i_mapping, page_lockstart,\n"
+ "-\t\t\t\t\t    page_lockend - 1))\n"
+ "+\t\tif (!check_range_has_page(inode, lockstart, lockend))\n"
+ " \t\t\tbreak;\n"
+ " \n"
+ " \t\tunlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,"
 
-543fddc699d70728d9ac6661fa82f811af9d4bf5ecbae3590e0e2fb91320f641
+b0572c518267b9b745bf2b278a88ddafd7b3293a249ce135a5c529fff00b65c7

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