From: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
To: Krzysztof Karas <krzysztof.karas@intel.com>,
intel-gfx@lists.freedesktop.org,
dri-devel@lists.freedesktop.org
Cc: "Andi Shyti" <andi.shyti@linux.intel.com>,
"Michał Grzelak" <michal.grzelak@intel.com>,
"Sebastian Brzezinka" <sebastian.brzezinka@intel.com>,
"Krzysztof Niemiec" <krzysztof.niemiec@intel.com>,
stable@vger.kernel.org
Subject: Re: [PATCH v8 2/6] drm/i915/gem: Count mapped pages in a folio
Date: Thu, 12 Nov 2026 13:29:50 +0100 [thread overview]
Message-ID: <500844ca6329952ed41a7cedf97b5f6a84ede545.camel@linux.intel.com> (raw)
In-Reply-To: <20261109113758.1491891-3-krzysztof.karas@intel.com>
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. */
next prev parent reply other threads:[~2026-11-12 12:29 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=500844ca6329952ed41a7cedf97b5f6a84ede545.camel@linux.intel.com \
--to=janusz.krzysztofik@linux.intel.com \
--cc=andi.shyti@linux.intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=krzysztof.karas@intel.com \
--cc=krzysztof.niemiec@intel.com \
--cc=michal.grzelak@intel.com \
--cc=sebastian.brzezinka@intel.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.