* [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu
@ 2026-11-09 11:37 Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 1/6] drm/i915/shmem: Validate max_segment Krzysztof Karas
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas
It was observed that allocating large objects via i915 driver
(igt-gpu-tools/tests/gem_exec_big/single) the folios and their
pages were not handled properly leading to buffer corruptions
during relocations.
Furthermore, using iommu driver in this context would leave
residual mappings in memory that could not be released, hogging
available RAM even after the process ended.
v8:
* Removed Assisted-by: LLM tags.
Krzysztof Karas (6):
drm/i915/shmem: Validate max_segment
drm/i915/gem: Count mapped pages in a folio
drm/i915/gem: Free sg table on failure to acquire second folio
drm/i915/gem: Pull out size validation into a separate function
drm/i915/gem: Read and shrink memory in a separate function
drm/i915/gem: Remove iterator and use while loop
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 163 ++++++++++++++--------
1 file changed, 101 insertions(+), 62 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v8 1/6] drm/i915/shmem: Validate max_segment
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio Krzysztof Karas
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas,
Andi Shyti
There is nothing preventing user of shmem_sg_alloc_table() from
passing max_segment smaller than PAGE_SIZE, which would result
in nr_pages = max_segment / PAGE_SIZE == 0 and cause a
non-terminating loop.
Suggested-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Suggested-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index bf9e7480f0f5..e35ee4bd456f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -85,6 +85,9 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
if (size > resource_size(&mr->region))
return -ENOMEM;
+ if (max_segment < PAGE_SIZE || !PAGE_ALIGNED(max_segment))
+ return -EINVAL;
+
if (sg_alloc_table(st, page_count, GFP_KERNEL | __GFP_NOWARN))
return -ENOMEM;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 1/6] drm/i915/shmem: Validate max_segment Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-12 12:29 ` Janusz Krzysztofik
2026-11-09 11:37 ` [PATCH v8 3/6] drm/i915/gem: Free sg table on failure to acquire second folio Krzysztof Karas
` (4 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas, stable
Before addition of commit 029ae067431a
("drm/i915: Fix potential overflow of shmem scatterlist length")
and after folios were introduced complete folios were always
allocated, possibly overloading the scatterlist capacity which
was never truly limited to PAGE_SIZE when requested via
max_segment. The above commit addressed scatterlist overloading,
but unintentionally disabled PAGE_SIZE as a valid max_segment
value and failed to take care of remaining pages from folios
above max_segment boundary.
This created a state, where multitude of scatterlists were used
for the same folio, but never counting enough of its pages to
jump to the next folio.
Furthermore, current do-while loop goes over the same folio
multiple times, increasing the refcount each time, and breaks
get/put symmetry: many shmem_read_folio_gfp() gets and only one
put in i915_gem_object_put_pages_shmem() per folio.
Track how many pages have already been counted in a folio and
use that number as an offset on consecutive allocations from the
same folio to ensure it is fully covered before reading next
folio.
Fixes: 029ae067431a ("drm/i915: Fix potential overflow of shmem scatterlist length")
Cc: stable@vger.kernel.org
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/15816
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 101 +++++++++++++---------
1 file changed, 59 insertions(+), 42 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index e35ee4bd456f..d57b5c67d47b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -71,6 +71,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
unsigned long i;
struct scatterlist *sg;
unsigned long next_pfn = 0; /* suppress gcc warning */
+ struct folio *folio = NULL;
gfp_t noreclaim;
int ret;
@@ -104,7 +105,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
sg = st->sgl;
st->nents = 0;
for (i = 0; i < page_count; i++) {
- struct folio *folio;
+ unsigned long folio_page_index;
unsigned long nr_pages;
const unsigned int shrink[] = {
I915_SHRINK_BOUND | I915_SHRINK_UNBOUND,
@@ -112,51 +113,61 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
}, *s = shrink;
gfp_t gfp = noreclaim;
- do {
- cond_resched();
- folio = shmem_read_folio_gfp(mapping, i, gfp);
- if (!IS_ERR(folio))
- break;
-
- if (!*s) {
- ret = PTR_ERR(folio);
- goto err_sg;
- }
+ if (!i || (next_pfn >= folio_pfn(folio) + folio_nr_pages(folio))) {
+ /* Grab the next folio if we exhausted the current one. */
+ do {
+ cond_resched();
+ folio = shmem_read_folio_gfp(mapping, i, gfp);
+ folio_page_index = 0;
+ if (!IS_ERR(folio))
+ break;
- i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
+ if (!*s) {
+ ret = PTR_ERR(folio);
+ goto err_sg;
+ }
- /*
- * We've tried hard to allocate the memory by reaping
- * our own buffer, now let the real VM do its job and
- * go down in flames if truly OOM.
- *
- * However, since graphics tend to be disposable,
- * defer the oom here by reporting the ENOMEM back
- * to userspace.
- */
- if (!*s) {
- /* reclaim and warn, but no oom */
- gfp = mapping_gfp_mask(mapping);
+ i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
/*
- * Our bo are always dirty and so we require
- * kswapd to reclaim our pages (direct reclaim
- * does not effectively begin pageout of our
- * buffers on its own). However, direct reclaim
- * only waits for kswapd when under allocation
- * congestion. So as a result __GFP_RECLAIM is
- * unreliable and fails to actually reclaim our
- * dirty pages -- unless you try over and over
- * again with !__GFP_NORETRY. However, we still
- * want to fail this allocation rather than
- * trigger the out-of-memory killer and for
- * this we want __GFP_RETRY_MAYFAIL.
+ * We've tried hard to allocate the memory by reaping
+ * our own buffer, now let the real VM do its job and
+ * go down in flames if truly OOM.
+ *
+ * However, since graphics tend to be disposable,
+ * defer the oom here by reporting the ENOMEM back
+ * to userspace.
*/
- gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
- }
- } while (1);
+ if (!*s) {
+ /* reclaim and warn, but no oom */
+ gfp = mapping_gfp_mask(mapping);
+
+ /*
+ * Our bo are always dirty and so we require
+ * kswapd to reclaim our pages (direct reclaim
+ * does not effectively begin pageout of our
+ * buffers on its own). However, direct reclaim
+ * only waits for kswapd when under allocation
+ * congestion. So as a result __GFP_RECLAIM is
+ * unreliable and fails to actually reclaim our
+ * dirty pages -- unless you try over and over
+ * again with !__GFP_NORETRY. However, we still
+ * want to fail this allocation rather than
+ * trigger the out-of-memory killer and for
+ * this we want __GFP_RETRY_MAYFAIL.
+ */
+ gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
+ }
+ } while (1);
+ } else {
+ /*
+ * Otherwise, we are still inside the same folio,
+ * so just update its page index.
+ */
+ folio_page_index = next_pfn - folio_pfn(folio);
+ }
- nr_pages = min3(folio_nr_pages(folio),
+ nr_pages = min3(folio_nr_pages(folio) - folio_page_index,
page_count - i, max_segment / PAGE_SIZE);
if (!i ||
@@ -166,13 +177,19 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
sg = sg_next(sg);
st->nents++;
- sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0);
+ sg_set_page(sg, folio_page(folio, folio_page_index),
+ nr_pages * PAGE_SIZE, 0);
} else {
nr_pages = min(nr_pages, (max_segment - sg->length) / PAGE_SIZE);
sg->length += nr_pages * PAGE_SIZE;
}
- next_pfn = folio_pfn(folio) + nr_pages;
+
+ /*
+ * Store the next PFN, so contiguous physical pages
+ * can be merged into the same SG entry.
+ */
+ next_pfn = folio_pfn(folio) + folio_page_index + nr_pages;
i += nr_pages - 1;
/* Check that the i965g/gm workaround works. */
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v8 3/6] drm/i915/gem: Free sg table on failure to acquire second folio
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 1/6] drm/i915/shmem: Validate max_segment Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 4/6] drm/i915/gem: Pull out size validation into a separate function Krzysztof Karas
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas, stable
We should release folios if the first entry was populated, but
loop failed before sg advanced (st->nents == 1 && sg == st->sgl).
Fixes: 957ad9a02be6 ("drm/i915/gem: Avoid iterating an empty list")
Cc: stable@vger.kernel.org
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index d57b5c67d47b..f4a2a3f34c36 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -204,7 +204,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
return 0;
err_sg:
sg_mark_end(sg);
- if (sg != st->sgl) {
+ if (st->nents) {
shmem_sg_free_table(st, mapping, false, false);
} else {
mapping_clear_unevictable(mapping);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v8 4/6] drm/i915/gem: Pull out size validation into a separate function
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
` (2 preceding siblings ...)
2026-11-09 11:37 ` [PATCH v8 3/6] drm/i915/gem: Free sg table on failure to acquire second folio Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 5/6] drm/i915/gem: Read and shrink memory in " Krzysztof Karas
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas
shmem_sg_alloc_table is a very large and hard to read function,
so reduce the number of operations it is responsible for by
placing "size" validation and page_count assignment in a new
helper.
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 30 +++++++++++++++--------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index f4a2a3f34c36..b09b83402b8c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -62,6 +62,23 @@ void shmem_sg_free_table(struct sg_table *st, struct address_space *mapping,
sg_free_table(st);
}
+static int validate_set_page_count(size_t size, unsigned int *page_count,
+ struct intel_memory_region *mr)
+{
+ if (overflows_type(size / PAGE_SIZE, *page_count))
+ return -E2BIG;
+
+ /*
+ * If there's no chance of allocating enough pages for the whole
+ * object, bail early.
+ */
+ if (size > resource_size(&mr->region))
+ return -ENOMEM;
+
+ *page_count = size / PAGE_SIZE;
+ return 0;
+}
+
int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
size_t size, struct intel_memory_region *mr,
struct address_space *mapping,
@@ -75,16 +92,9 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
gfp_t noreclaim;
int ret;
- if (overflows_type(size / PAGE_SIZE, page_count))
- return -E2BIG;
-
- page_count = size / PAGE_SIZE;
- /*
- * If there's no chance of allocating enough pages for the whole
- * object, bail early.
- */
- if (size > resource_size(&mr->region))
- return -ENOMEM;
+ ret = validate_set_page_count(size, &page_count, mr);
+ if (ret)
+ return ret;
if (max_segment < PAGE_SIZE || !PAGE_ALIGNED(max_segment))
return -EINVAL;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v8 5/6] drm/i915/gem: Read and shrink memory in a separate function
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
` (3 preceding siblings ...)
2026-11-09 11:37 ` [PATCH v8 4/6] drm/i915/gem: Pull out size validation into a separate function Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 6/6] drm/i915/gem: Remove iterator and use while loop Krzysztof Karas
2026-11-09 17:23 ` ✓ i915.CI.BAT: success for drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Patchwork
6 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas
Continue unloading shmem_sg_alloc_table by placing reading
folios and shrink call into a new helper.
Make the loop a bit more reader-friendly by removing iteration
over a structure and replacing it with inlined instructions.
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 105 ++++++++++++----------
1 file changed, 57 insertions(+), 48 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index b09b83402b8c..59dae47fcfc8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -79,6 +79,56 @@ static int validate_set_page_count(size_t size, unsigned int *page_count,
return 0;
}
+static struct folio *shmem_shrink_get_folio(struct address_space *mapping,
+ unsigned long folio_index,
+ gfp_t *gfp, unsigned int page_count,
+ struct drm_i915_private *i915)
+{
+ struct folio *folio;
+
+ cond_resched();
+ folio = shmem_read_folio_gfp(mapping, folio_index, *gfp);
+ if (IS_ERR(folio)) {
+ i915_gem_shrink(NULL, i915, 2 * page_count, NULL,
+ I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
+
+ /*
+ * We've tried hard to allocate the memory by reaping
+ * our own buffer, now let the real VM do its job and
+ * go down in flames if truly OOM.
+ *
+ * However, since graphics tend to be disposable,
+ * defer the oom here by reporting the ENOMEM back
+ * to userspace.
+ *
+ * Reclaim and warn, but no oom.
+ */
+ *gfp = mapping_gfp_mask(mapping);
+
+ /*
+ * Our bo are always dirty and so we require
+ * kswapd to reclaim our pages (direct reclaim
+ * does not effectively begin pageout of our
+ * buffers on its own). However, direct reclaim
+ * only waits for kswapd when under allocation
+ * congestion. So as a result __GFP_RECLAIM is
+ * unreliable and fails to actually reclaim our
+ * dirty pages -- unless you try over and over
+ * again with !__GFP_NORETRY. However, we still
+ * want to fail this allocation rather than
+ * trigger the out-of-memory killer and for
+ * this we want __GFP_RETRY_MAYFAIL.
+ */
+ *gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
+
+ /* Retry once after shrinking and gfp modification. */
+ cond_resched();
+ folio = shmem_read_folio_gfp(mapping, folio_index, *gfp);
+ }
+
+ return folio;
+}
+
int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
size_t size, struct intel_memory_region *mr,
struct address_space *mapping,
@@ -117,58 +167,17 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
for (i = 0; i < page_count; i++) {
unsigned long folio_page_index;
unsigned long nr_pages;
- const unsigned int shrink[] = {
- I915_SHRINK_BOUND | I915_SHRINK_UNBOUND,
- 0,
- }, *s = shrink;
gfp_t gfp = noreclaim;
if (!i || (next_pfn >= folio_pfn(folio) + folio_nr_pages(folio))) {
/* Grab the next folio if we exhausted the current one. */
- do {
- cond_resched();
- folio = shmem_read_folio_gfp(mapping, i, gfp);
- folio_page_index = 0;
- if (!IS_ERR(folio))
- break;
-
- if (!*s) {
- ret = PTR_ERR(folio);
- goto err_sg;
- }
-
- i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
-
- /*
- * We've tried hard to allocate the memory by reaping
- * our own buffer, now let the real VM do its job and
- * go down in flames if truly OOM.
- *
- * However, since graphics tend to be disposable,
- * defer the oom here by reporting the ENOMEM back
- * to userspace.
- */
- if (!*s) {
- /* reclaim and warn, but no oom */
- gfp = mapping_gfp_mask(mapping);
-
- /*
- * Our bo are always dirty and so we require
- * kswapd to reclaim our pages (direct reclaim
- * does not effectively begin pageout of our
- * buffers on its own). However, direct reclaim
- * only waits for kswapd when under allocation
- * congestion. So as a result __GFP_RECLAIM is
- * unreliable and fails to actually reclaim our
- * dirty pages -- unless you try over and over
- * again with !__GFP_NORETRY. However, we still
- * want to fail this allocation rather than
- * trigger the out-of-memory killer and for
- * this we want __GFP_RETRY_MAYFAIL.
- */
- gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
- }
- } while (1);
+ folio = shmem_shrink_get_folio(mapping, i, &gfp,
+ page_count, i915);
+ folio_page_index = 0;
+ if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio);
+ goto err_sg;
+ }
} else {
/*
* Otherwise, we are still inside the same folio,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v8 6/6] drm/i915/gem: Remove iterator and use while loop
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
` (4 preceding siblings ...)
2026-11-09 11:37 ` [PATCH v8 5/6] drm/i915/gem: Read and shrink memory in " Krzysztof Karas
@ 2026-11-09 11:37 ` Krzysztof Karas
2026-11-09 17:23 ` ✓ i915.CI.BAT: success for drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Patchwork
6 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Karas @ 2026-11-09 11:37 UTC (permalink / raw)
To: intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Janusz Krzysztofik,
Sebastian Brzezinka, Krzysztof Niemiec, Krzysztof Karas
Change the main "for" loop into "while" to get rid of obscure
iterator "i" and use more descriptive name to indicate how many
pages were already covered. Detect first loop with st->nents.
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 59dae47fcfc8..792996b1e075 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -135,7 +135,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
unsigned int max_segment)
{
unsigned int page_count; /* restricted by sg_alloc_table */
- unsigned long i;
+ unsigned long pages_done = 0;
struct scatterlist *sg;
unsigned long next_pfn = 0; /* suppress gcc warning */
struct folio *folio = NULL;
@@ -164,15 +164,15 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
sg = st->sgl;
st->nents = 0;
- for (i = 0; i < page_count; i++) {
+ while (pages_done < page_count) {
unsigned long folio_page_index;
unsigned long nr_pages;
gfp_t gfp = noreclaim;
- if (!i || (next_pfn >= folio_pfn(folio) + folio_nr_pages(folio))) {
+ if (!pages_done || (next_pfn >= folio_pfn(folio) + folio_nr_pages(folio))) {
/* Grab the next folio if we exhausted the current one. */
- folio = shmem_shrink_get_folio(mapping, i, &gfp,
- page_count, i915);
+ folio = shmem_shrink_get_folio(mapping, pages_done,
+ &gfp, page_count, i915);
folio_page_index = 0;
if (IS_ERR(folio)) {
ret = PTR_ERR(folio);
@@ -187,12 +187,12 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
}
nr_pages = min3(folio_nr_pages(folio) - folio_page_index,
- page_count - i, max_segment / PAGE_SIZE);
+ page_count - pages_done, max_segment / PAGE_SIZE);
- if (!i ||
+ if (!st->nents ||
sg->length >= max_segment ||
folio_pfn(folio) != next_pfn) {
- if (i)
+ if (st->nents)
sg = sg_next(sg);
st->nents++;
@@ -209,7 +209,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
* can be merged into the same SG entry.
*/
next_pfn = folio_pfn(folio) + folio_page_index + nr_pages;
- i += nr_pages - 1;
+ pages_done += nr_pages;
/* Check that the i965g/gm workaround works. */
GEM_BUG_ON(gfp & __GFP_DMA32 && next_pfn >= 0x00100000UL);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* ✓ i915.CI.BAT: success for drivers: Improve memory management for large object allocations when i915/shmem is used with iommu
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
` (5 preceding siblings ...)
2026-11-09 11:37 ` [PATCH v8 6/6] drm/i915/gem: Remove iterator and use while loop Krzysztof Karas
@ 2026-11-09 17:23 ` Patchwork
6 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2026-11-09 17:23 UTC (permalink / raw)
To: Krzysztof Karas; +Cc: intel-gfx
[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]
== Series Details ==
Series: drivers: Improve memory management for large object allocations when i915/shmem is used with iommu
URL : https://patchwork.freedesktop.org/series/178094/
State : success
== Summary ==
CI Bug Log - changes from CI_DRM_19475 -> Patchwork_178094v1
====================================================
Summary
-------
**SUCCESS**
No regressions found.
External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_178094v1/index.html
Participating hosts (40 -> 39)
------------------------------
Missing (1): bat-dg2-13
Changes
-------
No changes found
Build changes
-------------
* Linux: CI_DRM_19475 -> Patchwork_178094v1
CI-20190529: 20190529
CI_DRM_19475: d72707a042b6aff601449a9cf87e5fe55decbc5c @ git://anongit.freedesktop.org/gfx-ci/linux
IGT_9181: 9181
Patchwork_178094v1: d72707a042b6aff601449a9cf87e5fe55decbc5c @ git://anongit.freedesktop.org/gfx-ci/linux
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_178094v1/index.html
[-- Attachment #2: Type: text/html, Size: 1609 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio
2026-11-09 11:37 ` [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio Krzysztof Karas
@ 2026-11-12 12:29 ` Janusz Krzysztofik
0 siblings, 0 replies; 9+ messages in thread
From: Janusz Krzysztofik @ 2026-11-12 12:29 UTC (permalink / raw)
To: Krzysztof Karas, intel-gfx, dri-devel
Cc: Andi Shyti, Michał Grzelak, Sebastian Brzezinka,
Krzysztof Niemiec, stable
Hi Krzysztof,
On Mon, 2026-11-09 at 11:37 +0000, Krzysztof Karas wrote:
> Before addition of commit 029ae067431a
> ("drm/i915: Fix potential overflow of shmem scatterlist length")
> and after folios were introduced complete folios were always
> allocated, possibly overloading the scatterlist capacity which
> was never truly limited to PAGE_SIZE when requested via
> max_segment. The above commit addressed scatterlist overloading,
> but unintentionally disabled PAGE_SIZE as a valid max_segment
> value and failed to take care of remaining pages from folios
> above max_segment boundary.
> This created a state, where multitude of scatterlists were used
> for the same folio, but never counting enough of its pages to
> jump to the next folio.
>
> Furthermore, current do-while loop goes over the same folio
> multiple times, increasing the refcount each time, and breaks
> get/put symmetry: many shmem_read_folio_gfp() gets and only one
> put in i915_gem_object_put_pages_shmem() per folio.
>
> Track how many pages have already been counted in a folio and
> use that number as an offset on consecutive allocations from the
> same folio to ensure it is fully covered before reading next
> folio.
>
> Fixes: 029ae067431a ("drm/i915: Fix potential overflow of shmem scatterlist length")
> Cc: stable@vger.kernel.org
> Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/15816
> Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
> ---
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 101 +++++++++++++---------
> 1 file changed, 59 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> index e35ee4bd456f..d57b5c67d47b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> @@ -71,6 +71,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
> unsigned long i;
> struct scatterlist *sg;
> unsigned long next_pfn = 0; /* suppress gcc warning */
> + struct folio *folio = NULL;
> gfp_t noreclaim;
> int ret;
>
> @@ -104,7 +105,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
> sg = st->sgl;
> st->nents = 0;
> for (i = 0; i < page_count; i++) {
> - struct folio *folio;
> + unsigned long folio_page_index;
> unsigned long nr_pages;
> const unsigned int shrink[] = {
> I915_SHRINK_BOUND | I915_SHRINK_UNBOUND,
> @@ -112,51 +113,61 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
> }, *s = shrink;
> gfp_t gfp = noreclaim;
>
I was looking for a way to make this patch still more easily readable, but
all I invented would look like below, so not a standard syntax, then:
Reviewed-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
> - do {
+ if (i && (next_pfn < folio_pfn(folio) + folio_nr_pages(folio))) {
+ /*
+ * We are still inside the same folio,
+ * so just update its page index.
+ */
+ folio_page_index = next_pfn - folio_pfn(folio);
+ } else do {
+ /* Grab the next folio if we exhausted the current one. */
> - cond_resched();
> - folio = shmem_read_folio_gfp(mapping, i, gfp);
> - if (!IS_ERR(folio))
> - break;
> -
> - if (!*s) {
> - ret = PTR_ERR(folio);
> - goto err_sg;
> - }
> + if (!i || (next_pfn >= folio_pfn(folio) + folio_nr_pages(folio))) {
> + /* Grab the next folio if we exhausted the current one. */
> + do {
> + cond_resched();
> + folio = shmem_read_folio_gfp(mapping, i, gfp);
> + folio_page_index = 0;
> + if (!IS_ERR(folio))
> + break;
>
> - i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
> + if (!*s) {
> + ret = PTR_ERR(folio);
> + goto err_sg;
> + }
>
> - /*
> - * We've tried hard to allocate the memory by reaping
> - * our own buffer, now let the real VM do its job and
> - * go down in flames if truly OOM.
> - *
> - * However, since graphics tend to be disposable,
> - * defer the oom here by reporting the ENOMEM back
> - * to userspace.
> - */
> - if (!*s) {
> - /* reclaim and warn, but no oom */
> - gfp = mapping_gfp_mask(mapping);
> + i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
>
> /*
> - * Our bo are always dirty and so we require
> - * kswapd to reclaim our pages (direct reclaim
> - * does not effectively begin pageout of our
> - * buffers on its own). However, direct reclaim
> - * only waits for kswapd when under allocation
> - * congestion. So as a result __GFP_RECLAIM is
> - * unreliable and fails to actually reclaim our
> - * dirty pages -- unless you try over and over
> - * again with !__GFP_NORETRY. However, we still
> - * want to fail this allocation rather than
> - * trigger the out-of-memory killer and for
> - * this we want __GFP_RETRY_MAYFAIL.
> + * We've tried hard to allocate the memory by reaping
> + * our own buffer, now let the real VM do its job and
> + * go down in flames if truly OOM.
> + *
> + * However, since graphics tend to be disposable,
> + * defer the oom here by reporting the ENOMEM back
> + * to userspace.
> */
> - gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
> - }
> - } while (1);
> + if (!*s) {
> + /* reclaim and warn, but no oom */
> + gfp = mapping_gfp_mask(mapping);
> +
> + /*
> + * Our bo are always dirty and so we require
> + * kswapd to reclaim our pages (direct reclaim
> + * does not effectively begin pageout of our
> + * buffers on its own). However, direct reclaim
> + * only waits for kswapd when under allocation
> + * congestion. So as a result __GFP_RECLAIM is
> + * unreliable and fails to actually reclaim our
> + * dirty pages -- unless you try over and over
> + * again with !__GFP_NORETRY. However, we still
> + * want to fail this allocation rather than
> + * trigger the out-of-memory killer and for
> + * this we want __GFP_RETRY_MAYFAIL.
> + */
> + gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
> + }
> + } while (1);
> + } else {
> + /*
> + * Otherwise, we are still inside the same folio,
> + * so just update its page index.
> + */
> + folio_page_index = next_pfn - folio_pfn(folio);
> + }
>
> - nr_pages = min3(folio_nr_pages(folio),
> + nr_pages = min3(folio_nr_pages(folio) - folio_page_index,
> page_count - i, max_segment / PAGE_SIZE);
>
> if (!i ||
> @@ -166,13 +177,19 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
> sg = sg_next(sg);
>
> st->nents++;
> - sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0);
> + sg_set_page(sg, folio_page(folio, folio_page_index),
> + nr_pages * PAGE_SIZE, 0);
> } else {
> nr_pages = min(nr_pages, (max_segment - sg->length) / PAGE_SIZE);
>
> sg->length += nr_pages * PAGE_SIZE;
> }
> - next_pfn = folio_pfn(folio) + nr_pages;
> +
> + /*
> + * Store the next PFN, so contiguous physical pages
> + * can be merged into the same SG entry.
> + */
> + next_pfn = folio_pfn(folio) + folio_page_index + nr_pages;
> i += nr_pages - 1;
>
> /* Check that the i965g/gm workaround works. */
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-11-12 12:30 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09 11:37 [PATCH v8 0/6] drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 1/6] drm/i915/shmem: Validate max_segment Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio Krzysztof Karas
2026-11-12 12:29 ` Janusz Krzysztofik
2026-11-09 11:37 ` [PATCH v8 3/6] drm/i915/gem: Free sg table on failure to acquire second folio Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 4/6] drm/i915/gem: Pull out size validation into a separate function Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 5/6] drm/i915/gem: Read and shrink memory in " Krzysztof Karas
2026-11-09 11:37 ` [PATCH v8 6/6] drm/i915/gem: Remove iterator and use while loop Krzysztof Karas
2026-11-09 17:23 ` ✓ i915.CI.BAT: success for drivers: Improve memory management for large object allocations when i915/shmem is used with iommu Patchwork
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.