---
 drivers/gpu/drm/drm_context.c           |   17 +++++++++--
 drivers/gpu/drm/drm_crtc.c              |   19 +++++++++---
 drivers/gpu/drm/drm_gem.c               |   49 ++++++++++++++++++++------------
 drivers/gpu/drm/drm_stub.c              |   19 +++++++++++-
 drivers/gpu/drm/i915/i915_gem_context.c |   21 ++++++++++---
 5 files changed, 93 insertions(+), 32 deletions(-)

--- a/drivers/gpu/drm/drm_context.c
+++ b/drivers/gpu/drm/drm_context.c
@@ -74,13 +74,24 @@ void drm_ctxbitmap_free(struct drm_devic
  */
 static int drm_ctxbitmap_next(struct drm_device * dev)
 {
+	int new_id;
 	int ret;
 
+again:
+	if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
+		DRM_ERROR("Out of memory expanding drawable idr\n");
+		return -ENOMEM;
+	}
 	mutex_lock(&dev->struct_mutex);
-	ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0,
-			GFP_KERNEL);
+	ret = idr_get_new_above(&dev->ctx_idr, NULL,
+				DRM_RESERVED_CONTEXTS, &new_id);
 	mutex_unlock(&dev->struct_mutex);
-	return ret;
+	if (ret == -EAGAIN)
+		goto again;
+	else if (ret)
+		return ret;
+
+	return new_id;
 }
 
 /**
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -300,21 +300,32 @@ EXPORT_SYMBOL(drm_get_format_name);
 static int drm_mode_object_get(struct drm_device *dev,
 			       struct drm_mode_object *obj, uint32_t obj_type)
 {
+	int new_id = 0;
 	int ret;
 
+again:
+	if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
+		DRM_ERROR("Ran out memory getting a mode number\n");
+		return -ENOMEM;
+	}
+
 	mutex_lock(&dev->mode_config.idr_mutex);
-	ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
-	if (ret >= 0) {
+	ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id);
+
+	if (!ret) {
 		/*
 		 * Set up the object linking under the protection of the idr
 		 * lock so that other users can't see inconsistent state.
 		 */
-		obj->id = ret;
+		obj->id = new_id;
 		obj->type = obj_type;
 	}
 	mutex_unlock(&dev->mode_config.idr_mutex);
 
-	return ret < 0 ? ret : 0;
+	if (ret == -EAGAIN)
+		goto again;
+
+	return ret;
 }
 
 /**
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -342,23 +342,28 @@ drm_gem_handle_create_tail(struct drm_fi
 	WARN_ON(!mutex_is_locked(&dev->object_name_lock));
 
 	/*
-	 * Get the user-visible handle using idr.  Preload and perform
-	 * allocation under our spinlock.
+	 * Get the user-visible handle using idr.
 	 */
-	idr_preload(GFP_KERNEL);
-	spin_lock(&file_priv->table_lock);
+again:
+	/* ensure there is space available to allocate a handle */
+	if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
-	ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
-	drm_gem_object_reference(obj);
-	obj->handle_count++;
+	/* do the allocation under our spinlock */
+	spin_lock(&file_priv->table_lock);
+	ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep);
 	spin_unlock(&file_priv->table_lock);
-	idr_preload_end();
+	if (ret == -EAGAIN)
+		goto again;
 	mutex_unlock(&dev->object_name_lock);
-	if (ret < 0) {
-		drm_gem_object_handle_unreference_unlocked(obj);
+ out:
+	if (ret)
 		return ret;
-	}
-	*handlep = ret;
+
+	drm_gem_object_reference(obj);
+	obj->handle_count++;
 
 	ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
 	if (ret) {
@@ -619,29 +624,37 @@ drm_gem_flink_ioctl(struct drm_device *d
 		return -ENOENT;
 
 	mutex_lock(&dev->object_name_lock);
-	idr_preload(GFP_KERNEL);
 	/* prevent races with concurrent gem_close. */
 	if (obj->handle_count == 0) {
 		ret = -ENOENT;
 		goto err;
 	}
 
+again:
+	if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
 	if (!obj->name) {
-		ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_NOWAIT);
-		if (ret < 0)
-			goto err;
+		ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
+					&obj->name);
 
-		obj->name = ret;
+		if (ret == -EAGAIN)
+			goto again;
+		else if (ret)
+			goto err;
 
 		/* Allocate a reference for the name table.  */
 		drm_gem_object_reference(obj);
+	} else {
+		ret = 0;
 	}
 
 	args->name = (uint64_t) obj->name;
 	ret = 0;
 
 err:
-	idr_preload_end();
 	mutex_unlock(&dev->object_name_lock);
 	drm_gem_object_unreference_unlocked(obj);
 	return ret;
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -105,6 +105,7 @@ EXPORT_SYMBOL(drm_ut_debug_printk);
 
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
+	int new_id;
 	int ret;
 	int base = 0, limit = 63;
 
@@ -116,11 +117,25 @@ static int drm_minor_get_id(struct drm_d
 		limit = base + 63;
 	}
 
+again:
+	if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
+		DRM_ERROR("Out of memory expanding drawable idr\n");
+		return -ENOMEM;
+	}
 	mutex_lock(&dev->struct_mutex);
-	ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
+	ret = idr_get_new_above(&drm_minors_idr, NULL,
+				base, &new_id);
 	mutex_unlock(&dev->struct_mutex);
+	if (ret == -EAGAIN)
+		goto again;
+	else if (ret)
+		return ret;
 
-	return ret == -ENOSPC ? -EINVAL : ret;
+	if (new_id >= limit) {
+		idr_remove(&drm_minors_idr, new_id);
+		return -EINVAL;
+	}
+	return new_id;
 }
 
 struct drm_master *drm_master_create(struct drm_minor *minor)
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -139,7 +139,7 @@ create_hw_context(struct drm_device *dev
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct i915_hw_context *ctx;
-	int ret;
+	int ret, id;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (ctx == NULL)
@@ -171,13 +171,24 @@ create_hw_context(struct drm_device *dev
 	if (file_priv == NULL)
 		return ctx;
 
-	ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
-			GFP_KERNEL);
-	if (ret < 0)
+again:
+	if (idr_pre_get(&file_priv->context_idr, GFP_KERNEL) == 0) {
+		ret = -ENOMEM;
+		DRM_DEBUG_DRIVER("idr allocation failed\n");
+		goto err_out;
+	}
+
+	ret = idr_get_new_above(&file_priv->context_idr, ctx,
+				DEFAULT_CONTEXT_ID + 1, &id);
+	if (ret == 0)
+		ctx->id = id;
+
+	if (ret == -EAGAIN)
+		goto again;
+	else if (ret)
 		goto err_out;
 
 	ctx->file_priv = file_priv;
-	ctx->id = ret;
 
 	return ctx;
 
