mm/hmm: use a structure for update callback parameters
[linux-2.6-block.git] / mm / hmm.c
index a3d532ff7c3d5856cd98136879b652af90ebdc8e..b4e9afdc2181d4b634d33cb6fea4700349908afd 100644 (file)
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -126,10 +126,8 @@ void hmm_mm_destroy(struct mm_struct *mm)
        kfree(mm->hmm);
 }
 
-static void hmm_invalidate_range(struct hmm *hmm,
-                                enum hmm_update_type action,
-                                unsigned long start,
-                                unsigned long end)
+static int hmm_invalidate_range(struct hmm *hmm,
+                               const struct hmm_update *update)
 {
        struct hmm_mirror *mirror;
        struct hmm_range *range;
@@ -138,22 +136,30 @@ static void hmm_invalidate_range(struct hmm *hmm,
        list_for_each_entry(range, &hmm->ranges, list) {
                unsigned long addr, idx, npages;
 
-               if (end < range->start || start >= range->end)
+               if (update->end < range->start || update->start >= range->end)
                        continue;
 
                range->valid = false;
-               addr = max(start, range->start);
+               addr = max(update->start, range->start);
                idx = (addr - range->start) >> PAGE_SHIFT;
-               npages = (min(range->end, end) - addr) >> PAGE_SHIFT;
+               npages = (min(range->end, update->end) - addr) >> PAGE_SHIFT;
                memset(&range->pfns[idx], 0, sizeof(*range->pfns) * npages);
        }
        spin_unlock(&hmm->lock);
 
        down_read(&hmm->mirrors_sem);
-       list_for_each_entry(mirror, &hmm->mirrors, list)
-               mirror->ops->sync_cpu_device_pagetables(mirror, action,
-                                                       start, end);
+       list_for_each_entry(mirror, &hmm->mirrors, list) {
+               int ret;
+
+               ret = mirror->ops->sync_cpu_device_pagetables(mirror, update);
+               if (!update->blockable && ret == -EAGAIN) {
+                       up_read(&hmm->mirrors_sem);
+                       return -EAGAIN;
+               }
+       }
        up_read(&hmm->mirrors_sem);
+
+       return 0;
 }
 
 static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -202,11 +208,16 @@ static void hmm_invalidate_range_end(struct mmu_notifier *mn,
                                     unsigned long start,
                                     unsigned long end)
 {
+       struct hmm_update update;
        struct hmm *hmm = mm->hmm;
 
        VM_BUG_ON(!hmm);
 
-       hmm_invalidate_range(mm->hmm, HMM_UPDATE_INVALIDATE, start, end);
+       update.start = start;
+       update.end = end;
+       update.event = HMM_UPDATE_INVALIDATE;
+       update.blockable = true;
+       hmm_invalidate_range(hmm, &update);
 }
 
 static const struct mmu_notifier_ops hmm_mmu_notifier_ops = {