Hi Janusz,

[...]

> >  
> > -           do {
> > -                   cond_resched();
> > -                   folio = shmem_read_folio_gfp(mapping, i, gfp);
> > -                   if (!IS_ERR(folio))
> > -                           break;
> > +           /* Grab the next folio if we exhausted the current one. */
> 
> I think that even with folio_start < i < folio_end, 
> shmem_read_folio_gfp(..., i, ...) should always return the right folio, so 
> we shouldn't worry about getting the same folio again in a relatively rare 
> case of the folio size exceeding a scatterlist capacity, we only need to 
> take care of tracking an offset within that folio.  Then, ...
> 
> > +           if (!i || i > folio_end) {
> > +                   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 (!*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);
> > +                           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);
> > +
> > +                   folio_start = folio_pgoff(folio);
> > +                   folio_end = folio_start + folio_nr_pages(folio) - 1;
> > +           }
> > +
> > +           folio_page_index = i - folio_start;
> > +           if (WARN_ON_ONCE(folio_page_index >= folio_nr_pages(folio))) {
> > +                   ret = -EINVAL;
> > +                   folio_put(folio);
> > +                   goto err_sg;
> > +           }
> 
> ... the existing code above, including the existing 'do' loop, may be left 
> untouched, I believe, an your folio_page_index can easily be calculated 
> from an already maintained next_pfn as:
> 
> +             folio_page_index = next_pfn - folio_pfn(folio);
> +             if (folio_page_index < 0 || folio_page_index >= 
> folio_nr_pages(folio))
> +                     folio_page_index = 0;
> 
> IOW, we need to calculate and apply an offset within the folio only if 
> next_pfn is still within the folio's PFN range, otherwise that must be a 
> new folio and the offset we apply must be 0.
> 
> Then, unless I'm missing something, I believe the patch could be much more 
> compact while still correct with my approach.  However, if other reviewers 
> are more OK with your proposed changes rather than what I suggest then I 
> won't oppose.
Leaving the current do/while loop as is means we get multiple
references to a folio per folio with shmem_read_folio_gfp(), but
only one put in i915_gem_object_put_pages_shmem().

Looking at this again, it should be addressed explicitly in
commit message.

> 
> >  
> >             nr_pages = min_array(((unsigned long[]) {
> > -                                   folio_nr_pages(folio),
> > +                                   folio_nr_pages(folio) - 
> > folio_page_index,
> >                                     page_count - i,
> >                                     max_segment / PAGE_SIZE,
> >                                   }), 3);
> >  
> >             if (!i ||
> >                 sg->length >= max_segment ||
> > -               folio_pfn(folio) != next_pfn) {
> > +               folio_pfn(folio) + folio_page_index != next_pfn) {
> 
> I think the existing condition was correct, and still applicable even when 
> tracking potential offsets within folios: when there is still some room in 
> the current scatterlist, enter the else part that fills up the scatterlist 
> with more data only if we've got a new folio that starts exactly where 
> the previous one ended to have contiguity of pages preserved, otherwise 
> switch to a new scatterlist.
You are right.

> 
> >                     if (i)
> >                             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 {
> > +                   /*
> > +                    * If our prediction about folio placement is true and
> > +                    * scatterlist still has space left for more pages,
> > +                    * then we land here.
> > +                    */
> >                     nr_pages = min_t(unsigned long, nr_pages,
> >                                      (max_segment - sg->length) / 
> > PAGE_SIZE);
> >  
> >                     sg->length += nr_pages * PAGE_SIZE;
> >             }
> > -           next_pfn = folio_pfn(folio) + nr_pages;
> > +
> > +           /*
> > +            * We assume folios are placed one after the other in memory
> > +            * and predict where the next folio begins.
> > +            */
> > +           next_pfn = folio_pfn(folio) + folio_page_index + nr_pages;
> 
> 
> >             i += nr_pages - 1;
> >  
> >             /* Check that the i965g/gm workaround works. */
> > @@ -186,6 +216,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, 
> > struct sg_table *st,
> >     i915_sg_trim(st);
> >  
> >     return 0;
> > +
> 
> Not related, I wouldn't mix it in, unless you have a good justification.
Yes, Andi also mentioned this in his review, so I'll remove this
diff.

Thank you for looking at this!
> 
> Thanks,
> Janusz
> 
> >  err_sg:
> >     sg_mark_end(sg);
> >     if (sg != st->sgl) {

-- 
Best Regards,
Krzysztof

Reply via email to