On Mon, Nov 04, 2019 at 11:30:32AM -0800, John Hubbard wrote:
> On 11/4/19 11:18 AM, Jerome Glisse wrote:
> > On Mon, Nov 04, 2019 at 11:04:38AM -0800, John Hubbard wrote:
> >> On 11/4/19 9:33 AM, Jerome Glisse wrote:
> >> ...
> >>>
> >>> Few nitpick belows, nonetheless:
> >>>
> >>> Reviewed-by: Jérôme Glisse <jgli...@redhat.com>
> >>> [...]
> >>>> +
> >>>> +CASE 3: ODP
> >>>> +-----------
> >>>> +(Mellanox/Infiniband On Demand Paging: the hardware supports
> >>>> +replayable page faulting). There are GUP references to pages serving as 
> >>>> DMA
> >>>> +buffers. For ODP, MMU notifiers are used to synchronize with 
> >>>> page_mkclean()
> >>>> +and munmap(). Therefore, normal GUP calls are sufficient, so neither 
> >>>> flag
> >>>> +needs to be set.
> >>>
> >>> I would not include ODP or anything like it here, they do not use
> >>> GUP anymore and i believe it is more confusing here. I would how-
> >>> ever include some text in this documentation explaining that hard-
> >>> ware that support page fault is superior as it does not incur any
> >>> of the issues described here.
> >>
> >> OK, agreed, here's a new write up that I'll put in v3:
> >>
> >>
> >> CASE 3: ODP
> >> -----------
> > 
> > ODP is RDMA, maybe Hardware with page fault support instead
> > 
> >> Advanced, but non-CPU (DMA) hardware that supports replayable page faults.
> 
> OK, so:
> 
>     "RDMA hardware with page faulting support."
> 
> for the first sentence.

I would drop RDMA completely, RDMA is just one example, they are GPU, FPGA and
others that are in that category. See below

> 
> 
> >> Here, a well-written driver doesn't normally need to pin pages at all. 
> >> However,
> >> if the driver does choose to do so, it can register MMU notifiers for the 
> >> range,
> >> and will be called back upon invalidation. Either way (avoiding page 
> >> pinning, or
> >> using MMU notifiers to unpin upon request), there is proper 
> >> synchronization with 
> >> both filesystem and mm (page_mkclean(), munmap(), etc).
> >>
> >> Therefore, neither flag needs to be set.
> > 
> > In fact GUP should never be use with those.
> 
> 
> Yes. The next paragraph says that, but maybe not strong enough.
> 
> 
> >>
> >> It's worth mentioning here that pinning pages should not be the first 
> >> design
> >> choice. If page fault capable hardware is available, then the software 
> >> should
> >> be written so that it does not pin pages. This allows mm and filesystems to
> >> operate more efficiently and reliably.
> 
> Here's what we have after the above changes:
> 
> CASE 3: ODP
> -----------
> RDMA hardware with page faulting support. Here, a well-written driver doesn't

CASE3: Hardware with page fault support
---------------------------------------

Here, a well-written ....


> normally need to pin pages at all. However, if the driver does choose to do 
> so,
> it can register MMU notifiers for the range, and will be called back upon
> invalidation. Either way (avoiding page pinning, or using MMU notifiers to 
> unpin
> upon request), there is proper synchronization with both filesystem and mm
> (page_mkclean(), munmap(), etc).
> 
> Therefore, neither flag needs to be set.
> 
> In this case, ideally, neither get_user_pages() nor pin_user_pages() should 
> be 
> called. Instead, the software should be written so that it does not pin 
> pages. 
> This allows mm and filesystems to operate more efficiently and reliably.
> 
> >>> [...]
> >>>
> >>>> @@ -1014,7 +1018,16 @@ static __always_inline long 
> >>>> __get_user_pages_locked(struct task_struct *tsk,
> >>>>                  BUG_ON(*locked != 1);
> >>>>          }
> >>>>  
> >>>> -        if (pages)
> >>>> +        /*
> >>>> +         * FOLL_PIN and FOLL_GET are mutually exclusive. Traditional 
> >>>> behavior
> >>>> +         * is to set FOLL_GET if the caller wants pages[] filled in 
> >>>> (but has
> >>>> +         * carelessly failed to specify FOLL_GET), so keep doing that, 
> >>>> but only
> >>>> +         * for FOLL_GET, not for the newer FOLL_PIN.
> >>>> +         *
> >>>> +         * FOLL_PIN always expects pages to be non-null, but no need to 
> >>>> assert
> >>>> +         * that here, as any failures will be obvious enough.
> >>>> +         */
> >>>> +        if (pages && !(flags & FOLL_PIN))
> >>>>                  flags |= FOLL_GET;
> >>>
> >>> Did you look at user that have pages and not FOLL_GET set ?
> >>> I believe it would be better to first fix them to end up
> >>> with FOLL_GET set and then error out if pages is != NULL but
> >>> nor FOLL_GET or FOLL_PIN is set.
> >>>
> >>
> >> I was perhaps overly cautious, and didn't go there. However, it's probably
> >> doable, given that there was already the following in __get_user_pages():
> >>
> >>     VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
> >>
> >> ...which will have conditioned people and code to set FOLL_GET together 
> >> with
> >> pages. So I agree that the time is right.
> >>
> >> In order to make bisecting future failures simpler, I can insert a patch 
> >> right 
> >> before this one, that changes the FOLL_GET setting into an assert, like 
> >> this:
> >>
> >> diff --git a/mm/gup.c b/mm/gup.c
> >> index 8f236a335ae9..be338961e80d 100644
> >> --- a/mm/gup.c
> >> +++ b/mm/gup.c
> >> @@ -1014,8 +1014,8 @@ static __always_inline long 
> >> __get_user_pages_locked(struct task_struct *tsk,
> >>                 BUG_ON(*locked != 1);
> >>         }
> >>  
> >> -       if (pages)
> >> -               flags |= FOLL_GET;
> >> +       if (pages && WARN_ON_ONCE(!(gup_flags & FOLL_GET)))
> >> +               return -EINVAL;
> >>  
> >>         pages_done = 0;
> >>         lock_dropped = false;
> >>
> >>
> >> ...and then add in FOLL_PIN, with this patch.
> > 
> > looks good but double check that it should not happens, i will try
> > to check on my side too.
> 
> Yes, I'll look.
> 
> ...
> >>>> +         */
> >>>> +        gup_flags |= FOLL_REMOTE | FOLL_PIN;
> >>>
> >>> Wouldn't it be better to not add pin_longterm_pages_remote() until
> >>> it can be properly implemented ?
> >>>
> >>
> >> Well, the problem is that I need each call site that requires FOLL_PIN
> >> to use a proper wrapper. It's the FOLL_PIN that is the focus here, because
> >> there is a hard, bright rule, which is: if and only if a caller sets
> >> FOLL_PIN, then the dma-page tracking happens, and put_user_page() must
> >> be called.
> >>
> >> So this leaves me with only two reasonable choices:
> >>
> >> a) Convert the call site as above: pin_longterm_pages_remote(), which sets
> >> FOLL_PIN (the key point!), and leaves the FOLL_LONGTERM situation exactly
> >> as it has been so far. When the FOLL_LONGTERM situation is fixed, the call
> >> site *might* not need any changes to adopt the working gup.c code.
> >>
> >> b) Convert the call site to pin_user_pages_remote(), which also sets
> >> FOLL_PIN, and also leaves the FOLL_LONGTERM situation exactly as before.
> >> There would also be a comment at the call site, to the effect of, "this
> >> is the wrong call to make: it really requires FOLL_LONGTERM behavior".
> >>
> >> When the FOLL_LONGTERM situation is fixed, the call site will need to be
> >> changed to pin_longterm_pages_remote().
> >>
> >> So you can probably see why I picked (a).
> > 
> > But right now nobody has FOLL_LONGTERM and FOLL_REMOTE. So you should
> > never have the need for pin_longterm_pages_remote(). My fear is that
> > longterm has implication and it would be better to not drop this implication
> > by adding a wrapper that does not do what the name says.
> > 
> > So do not introduce pin_longterm_pages_remote() until its first user
> > happens. This is option c)
> > 
> 
> Almost forgot, though: there is already another user: Infiniband:
> 
> drivers/infiniband/core/umem_odp.c:646:         npages = 
> pin_longterm_pages_remote(owning_process, owning_mm,

odp do not need that, i thought the HMM convertion was already upstream
but seems not, in any case odp do not need the longterm case it only
so best is to revert that user to gup_fast or something until it get
converted to HMM.

Cheers,
Jérôme

Reply via email to