}
 }
 
-static void eb_release_vmas(struct i915_execbuffer *eb, bool final, bool release_userptr)
+static void eb_release_vmas(struct i915_execbuffer *eb, bool final)
 {
        const unsigned int count = eb->buffer_count;
        unsigned int i;
 
                eb_unreserve_vma(ev);
 
-               if (release_userptr && ev->flags & __EXEC_OBJECT_USERPTR_INIT) {
-                       ev->flags &= ~__EXEC_OBJECT_USERPTR_INIT;
-                       i915_gem_object_userptr_submit_fini(vma->obj);
-               }
-
                if (final)
                        i915_vma_put(vma);
        }
        }
 
        /* We may process another execbuffer during the unlock... */
-       eb_release_vmas(eb, false, true);
+       eb_release_vmas(eb, false);
        i915_gem_ww_ctx_fini(&eb->ww);
 
        if (rq) {
 
 err:
        if (err == -EDEADLK) {
-               eb_release_vmas(eb, false, false);
+               eb_release_vmas(eb, false);
                err = i915_gem_ww_ctx_backoff(&eb->ww);
                if (!err)
                        goto repeat_validate;
 
 err:
        if (err == -EDEADLK) {
-               eb_release_vmas(eb, false, false);
+               eb_release_vmas(eb, false);
                err = i915_gem_ww_ctx_backoff(&eb->ww);
                if (!err)
                        goto retry;
 
 #ifdef CONFIG_MMU_NOTIFIER
        if (!err && (eb->args->flags & __EXEC_USERPTR_USED)) {
-               spin_lock(&eb->i915->mm.notifier_lock);
+               read_lock(&eb->i915->mm.notifier_lock);
 
                /*
                 * count is always at least 1, otherwise __EXEC_USERPTR_USED
                                break;
                }
 
-               spin_unlock(&eb->i915->mm.notifier_lock);
+               read_unlock(&eb->i915->mm.notifier_lock);
        }
 #endif
 
 
        err = eb_lookup_vmas(&eb);
        if (err) {
-               eb_release_vmas(&eb, true, true);
+               eb_release_vmas(&eb, true);
                goto err_engine;
        }
 
        i915_request_put(eb.request);
 
 err_vma:
-       eb_release_vmas(&eb, true, true);
+       eb_release_vmas(&eb, true);
        if (eb.trampoline)
                i915_vma_unpin(eb.trampoline);
        WARN_ON(err == -EDEADLK);
 
        if (!mmu_notifier_range_blockable(range))
                return false;
 
-       spin_lock(&i915->mm.notifier_lock);
+       write_lock(&i915->mm.notifier_lock);
 
        mmu_interval_set_seq(mni, cur_seq);
 
-       spin_unlock(&i915->mm.notifier_lock);
+       write_unlock(&i915->mm.notifier_lock);
 
        /*
         * We don't wait when the process is exiting. This is valid
 
 static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
        struct page **pvec = NULL;
 
-       spin_lock(&i915->mm.notifier_lock);
+       assert_object_held_shared(obj);
+
        if (!--obj->userptr.page_ref) {
                pvec = obj->userptr.pvec;
                obj->userptr.pvec = NULL;
        }
        GEM_BUG_ON(obj->userptr.page_ref < 0);
-       spin_unlock(&i915->mm.notifier_lock);
 
        if (pvec) {
                const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
 
 static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
        const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
        unsigned int max_segment = i915_sg_segment_size();
        struct sg_table *st;
        if (!st)
                return -ENOMEM;
 
-       spin_lock(&i915->mm.notifier_lock);
-       if (GEM_WARN_ON(!obj->userptr.page_ref)) {
-               spin_unlock(&i915->mm.notifier_lock);
-               ret = -EFAULT;
+       if (!obj->userptr.page_ref) {
+               ret = -EAGAIN;
                goto err_free;
        }
 
        obj->userptr.page_ref++;
        pvec = obj->userptr.pvec;
-       spin_unlock(&i915->mm.notifier_lock);
 
 alloc_table:
        sg = __sg_alloc_table_from_pages(st, pvec, num_pages, 0,
        i915_gem_object_userptr_drop_ref(obj);
 }
 
-static int i915_gem_object_userptr_unbind(struct drm_i915_gem_object *obj, bool get_pages)
+static int i915_gem_object_userptr_unbind(struct drm_i915_gem_object *obj)
 {
        struct sg_table *pages;
        int err;
        if (!IS_ERR_OR_NULL(pages))
                i915_gem_userptr_put_pages(obj, pages);
 
-       if (get_pages)
-               err = ____i915_gem_object_get_pages(obj);
-
        return err;
 }
 
 int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
        const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
        struct page **pvec;
        unsigned int gup_flags = 0;
        if (obj->userptr.notifier.mm != current->mm)
                return -EFAULT;
 
+       notifier_seq = mmu_interval_read_begin(&obj->userptr.notifier);
+
        ret = i915_gem_object_lock_interruptible(obj, NULL);
        if (ret)
                return ret;
 
-       /* optimistically try to preserve current pages while unlocked */
-       if (i915_gem_object_has_pages(obj) &&
-           !mmu_interval_check_retry(&obj->userptr.notifier,
-                                     obj->userptr.notifier_seq)) {
-               spin_lock(&i915->mm.notifier_lock);
-               if (obj->userptr.pvec &&
-                   !mmu_interval_read_retry(&obj->userptr.notifier,
-                                            obj->userptr.notifier_seq)) {
-                       obj->userptr.page_ref++;
-
-                       /* We can keep using the current binding, this is the fastpath */
-                       ret = 1;
-               }
-               spin_unlock(&i915->mm.notifier_lock);
+       if (notifier_seq == obj->userptr.notifier_seq && obj->userptr.pvec) {
+               i915_gem_object_unlock(obj);
+               return 0;
        }
 
-       if (!ret) {
-               /* Make sure userptr is unbound for next attempt, so we don't use stale pages. */
-               ret = i915_gem_object_userptr_unbind(obj, false);
-       }
+       ret = i915_gem_object_userptr_unbind(obj);
        i915_gem_object_unlock(obj);
-       if (ret < 0)
+       if (ret)
                return ret;
 
-       if (ret > 0)
-               return 0;
-
-       notifier_seq = mmu_interval_read_begin(&obj->userptr.notifier);
-
        pvec = kvmalloc_array(num_pages, sizeof(struct page *), GFP_KERNEL);
        if (!pvec)
                return -ENOMEM;
        }
        ret = 0;
 
-       spin_lock(&i915->mm.notifier_lock);
+       ret = i915_gem_object_lock_interruptible(obj, NULL);
+       if (ret)
+               goto out;
 
        if (mmu_interval_read_retry(&obj->userptr.notifier,
                !obj->userptr.page_ref ? notifier_seq :
        if (!obj->userptr.page_ref++) {
                obj->userptr.pvec = pvec;
                obj->userptr.notifier_seq = notifier_seq;
-
                pvec = NULL;
+               ret = ____i915_gem_object_get_pages(obj);
        }
 
+       obj->userptr.page_ref--;
+
 out_unlock:
-       spin_unlock(&i915->mm.notifier_lock);
+       i915_gem_object_unlock(obj);
 
 out:
        if (pvec) {
        return 0;
 }
 
-void i915_gem_object_userptr_submit_fini(struct drm_i915_gem_object *obj)
-{
-       i915_gem_object_userptr_drop_ref(obj);
-}
-
 int i915_gem_object_userptr_validate(struct drm_i915_gem_object *obj)
 {
        int err;
                i915_gem_object_unlock(obj);
        }
 
-       i915_gem_object_userptr_submit_fini(obj);
        return err;
 }
 
 int i915_gem_init_userptr(struct drm_i915_private *dev_priv)
 {
 #ifdef CONFIG_MMU_NOTIFIER
-       spin_lock_init(&dev_priv->mm.notifier_lock);
+       rwlock_init(&dev_priv->mm.notifier_lock);
 #endif
 
        return 0;