On 08/27/2018 07:26 AM, Michal Hocko wrote: > From: Michal Hocko <mhocko@xxxxxxxx> > > 93065ac753e4 ("mm, oom: distinguish blockable mode for mmu notifiers") > has introduced blockable parameter to all mmu_notifiers and the notifier > has to back off when called in !blockable case and it could block down > the road. > > The above commit implemented that for mn_invl_range_start but both > in_range checks are done unconditionally regardless of the blockable > mode and as such they would fail all the time for regular calls. > Fix this by checking blockable parameter as well. > > Once we are there we can remove the stale TODO. The lock has to be > sleepable because we wait for completion down in gnttab_unmap_refs_sync. > > Changes since v1 > - pull in_range check into mn_invl_range_start - Juergen > > Fixes: 93065ac753e4 ("mm, oom: distinguish blockable mode for mmu notifiers") > Cc: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx> > Cc: Juergen Gross <jgross@xxxxxxxx> > Signed-off-by: Michal Hocko <mhocko@xxxxxxxx> LGTM, although in_range() has a single call site so we really don't need it. I'll wait for Juergen to bless this since he asked for this approach. -boris > --- > drivers/xen/gntdev.c | 26 +++++++++++++++----------- > 1 file changed, 15 insertions(+), 11 deletions(-) > > diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c > index 57390c7666e5..b0b02a501167 100644 > --- a/drivers/xen/gntdev.c > +++ b/drivers/xen/gntdev.c > @@ -492,12 +492,19 @@ static bool in_range(struct gntdev_grant_map *map, > return true; > } > > -static void unmap_if_in_range(struct gntdev_grant_map *map, > - unsigned long start, unsigned long end) > +static int unmap_if_in_range(struct gntdev_grant_map *map, > + unsigned long start, unsigned long end, > + bool blockable) > { > unsigned long mstart, mend; > int err; > > + if (!in_range(map, start, end)) > + return 0; > + > + if (!blockable) > + return -EAGAIN; > + > mstart = max(start, map->vma->vm_start); > mend = min(end, map->vma->vm_end); > pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n", > @@ -508,6 +515,8 @@ static void unmap_if_in_range(struct gntdev_grant_map *map, > (mstart - map->vma->vm_start) >> PAGE_SHIFT, > (mend - mstart) >> PAGE_SHIFT); > WARN_ON(err); > + > + return 0; > } > > static int mn_invl_range_start(struct mmu_notifier *mn, > @@ -519,25 +528,20 @@ static int mn_invl_range_start(struct mmu_notifier *mn, > struct gntdev_grant_map *map; > int ret = 0; > > - /* TODO do we really need a mutex here? */ > if (blockable) > mutex_lock(&priv->lock); > else if (!mutex_trylock(&priv->lock)) > return -EAGAIN; > > list_for_each_entry(map, &priv->maps, next) { > - if (in_range(map, start, end)) { > - ret = -EAGAIN; > + ret = unmap_if_in_range(map, start, end, blockable); > + if (ret) > goto out_unlock; > - } > - unmap_if_in_range(map, start, end); > } > list_for_each_entry(map, &priv->freeable_maps, next) { > - if (in_range(map, start, end)) { > - ret = -EAGAIN; > + ret = unmap_if_in_range(map, start, end, blockable); > + if (ret) > goto out_unlock; > - } > - unmap_if_in_range(map, start, end); > } > > out_unlock: