Re: [bug report] drm/i915: Allow compaction upto SWIOTLB max segment size

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 06/02/2023 14:19, Dan Carpenter wrote:
[ Ancient code but the warning showed up again because the function was
   renamed or something? - dan ]

Hello Chris Wilson,

The patch 871dfbd67d4e: "drm/i915: Allow compaction upto SWIOTLB max
segment size" from Oct 11, 2016, leads to the following Smatch static
checker warning:

	drivers/gpu/drm/i915/gem/i915_gem_shmem.c:164 shmem_sg_alloc_table()
	warn: variable dereferenced before check 'sg' (see line 155)

Is smatch getting confused here? Not entirely sure but lets see below..

drivers/gpu/drm/i915/gem/i915_gem_shmem.c
     58 int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
     59                          size_t size, struct intel_memory_region *mr,
     60                          struct address_space *mapping,
     61                          unsigned int max_segment)
     62 {
     63         unsigned int page_count; /* restricted by sg_alloc_table */
     64         unsigned long i;
     65         struct scatterlist *sg;
     66         struct page *page;
     67         unsigned long last_pfn = 0;        /* suppress gcc warning */
     68         gfp_t noreclaim;
     69         int ret;
     70
     71         if (overflows_type(size / PAGE_SIZE, page_count))
     72                 return -E2BIG;
     73
     74         page_count = size / PAGE_SIZE;
     75         /*
     76          * If there's no chance of allocating enough pages for the whole
     77          * object, bail early.
     78          */
     79         if (size > resource_size(&mr->region))
     80                 return -ENOMEM;
     81
     82         if (sg_alloc_table(st, page_count, GFP_KERNEL | __GFP_NOWARN))
     83                 return -ENOMEM;
     84
     85         /*
     86          * Get the list of pages out of our struct file.  They'll be pinned
     87          * at this point until we release them.
     88          *
     89          * Fail silently without starting the shrinker
     90          */
     91         mapping_set_unevictable(mapping);
     92         noreclaim = mapping_gfp_constraint(mapping, ~__GFP_RECLAIM);
     93         noreclaim |= __GFP_NORETRY | __GFP_NOWARN;
     94
     95         sg = st->sgl;
                ^^^^^^^^^^^^
"sg" set here.

It is guaranteed to be non-NULL since sg_alloc_table succeeded.


     96         st->nents = 0;
     97         for (i = 0; i < page_count; i++) {
     98                 const unsigned int shrink[] = {
     99                         I915_SHRINK_BOUND | I915_SHRINK_UNBOUND,
     100                         0,
     101                 }, *s = shrink;
     102                 gfp_t gfp = noreclaim;
     103
     104                 do {
     105                         cond_resched();
     106                         page = shmem_read_mapping_page_gfp(mapping, i, gfp);
     107                         if (!IS_ERR(page))
     108                                 break;

This should probably break out of the outer loop instead of the inner
loop?

Don't think so, the loop has allocated a page and wants to break out the inner loop so the page can be appended to the sg list.


     109
     110                         if (!*s) {
     111                                 ret = PTR_ERR(page);
     112                                 goto err_sg;
     113                         }
     114
     115                         i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++);
     116
     117                         /*
     118                          * We've tried hard to allocate the memory by reaping
     119                          * our own buffer, now let the real VM do its job and
     120                          * go down in flames if truly OOM.
     121                          *
     122                          * However, since graphics tend to be disposable,
     123                          * defer the oom here by reporting the ENOMEM back
     124                          * to userspace.
     125                          */
     126                         if (!*s) {
     127                                 /* reclaim and warn, but no oom */
     128                                 gfp = mapping_gfp_mask(mapping);
     129
     130                                 /*
     131                                  * Our bo are always dirty and so we require
     132                                  * kswapd to reclaim our pages (direct reclaim
     133                                  * does not effectively begin pageout of our
     134                                  * buffers on its own). However, direct reclaim
     135                                  * only waits for kswapd when under allocation
     136                                  * congestion. So as a result __GFP_RECLAIM is
     137                                  * unreliable and fails to actually reclaim our
     138                                  * dirty pages -- unless you try over and over
     139                                  * again with !__GFP_NORETRY. However, we still
     140                                  * want to fail this allocation rather than
     141                                  * trigger the out-of-memory killer and for
     142                                  * this we want __GFP_RETRY_MAYFAIL.
     143                                  */
     144                                 gfp |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
     145                         }
     146                 } while (1);
     147
     148                 if (!i ||
     149                     sg->length >= max_segment ||
     150                     page_to_pfn(page) != last_pfn + 1) {
     151                         if (i)
     152                                 sg = sg_next(sg);
     153
     154                         st->nents++;
     155                         sg_set_page(sg, page, PAGE_SIZE, 0);
                                             ^^
Dereferenced.

Does smatch worry about the sg = sg_next(sg) here, or the initially highlighted state? Even for the former we know we have allocated enough entries (always allocate assuming worst possible fragmentation) so this will still be valid whatever happens.


     156                 } else {
     157                         sg->length += PAGE_SIZE;
                                 ^^
Here too.

     158                 }
     159                 last_pfn = page_to_pfn(page);
     160
     161                 /* Check that the i965g/gm workaround works. */
     162                 GEM_BUG_ON(gfp & __GFP_DMA32 && last_pfn >= 0x00100000UL);
     163         }
--> 164         if (sg) /* loop terminated early; short sg table */

If "sg" were NULL then we are already toasted.

AFAICT it can never be since the loop can never try to iterate past the last sg entry.

Regards,

Tvrtko


     165                 sg_mark_end(sg);
     166
     167         /* Trim unused sg entries to avoid wasting memory. */
     168         i915_sg_trim(st);
     169
     170         return 0;
     171 err_sg:
     172         sg_mark_end(sg);
     173         if (sg != st->sgl) {
     174                 shmem_sg_free_table(st, mapping, false, false);
     175         } else {
     176                 mapping_clear_unevictable(mapping);
     177                 sg_free_table(st);
     178         }
     179
     180         /*
     181          * shmemfs first checks if there is enough memory to allocate the page
     182          * and reports ENOSPC should there be insufficient, along with the usual
     183          * ENOMEM for a genuine allocation failure.
     184          *
     185          * We use ENOSPC in our driver to mean that we have run out of aperture
     186          * space and so want to translate the error from shmemfs back to our
     187          * usual understanding of ENOMEM.
     188          */
     189         if (ret == -ENOSPC)
     190                 ret = -ENOMEM;
     191
     192         return ret;
     193 }

regards,
dan carpenter



[Index of Archives]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux