ret = -EWOULDBLOCK;
                        break;
                }
-               if (!kref_get_unless_zero(&ctrl->kref))
+               if (!kobject_get_unless_zero(&ctrl->device->kobj))
                        break;
                file->private_data = ctrl;
                ret = 0;
        list_add_tail(&ns->list, &ctrl->namespaces);
        mutex_unlock(&ctrl->namespaces_mutex);
 
-       kref_get(&ctrl->kref);
+       nvme_get_ctrl(ctrl);
 
        kfree(id);
 
 
 void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
 {
-       device_destroy(nvme_class, MKDEV(nvme_char_major, ctrl->instance));
+       device_del(ctrl->device);
 
        spin_lock(&dev_list_lock);
        list_del(&ctrl->node);
 }
 EXPORT_SYMBOL_GPL(nvme_uninit_ctrl);
 
-static void nvme_free_ctrl(struct kref *kref)
+static void nvme_free_ctrl(struct device *dev)
 {
-       struct nvme_ctrl *ctrl = container_of(kref, struct nvme_ctrl, kref);
+       struct nvme_ctrl *ctrl =
+               container_of(dev, struct nvme_ctrl, ctrl_device);
 
-       put_device(ctrl->device);
        ida_simple_remove(&nvme_instance_ida, ctrl->instance);
        ida_destroy(&ctrl->ns_ida);
 
        ctrl->ops->free_ctrl(ctrl);
 }
 
-void nvme_put_ctrl(struct nvme_ctrl *ctrl)
-{
-       kref_put(&ctrl->kref, nvme_free_ctrl);
-}
-EXPORT_SYMBOL_GPL(nvme_put_ctrl);
-
 /*
  * Initialize a NVMe controller structures.  This needs to be called during
  * earliest initialization so that we have the initialized structured around
        spin_lock_init(&ctrl->lock);
        INIT_LIST_HEAD(&ctrl->namespaces);
        mutex_init(&ctrl->namespaces_mutex);
-       kref_init(&ctrl->kref);
        ctrl->dev = dev;
        ctrl->ops = ops;
        ctrl->quirks = quirks;
                goto out;
        ctrl->instance = ret;
 
-       ctrl->device = device_create_with_groups(nvme_class, ctrl->dev,
-                               MKDEV(nvme_char_major, ctrl->instance),
-                               ctrl, nvme_dev_attr_groups,
-                               "nvme%d", ctrl->instance);
-       if (IS_ERR(ctrl->device)) {
-               ret = PTR_ERR(ctrl->device);
+       device_initialize(&ctrl->ctrl_device);
+       ctrl->device = &ctrl->ctrl_device;
+       ctrl->device->devt = MKDEV(nvme_char_major, ctrl->instance);
+       ctrl->device->class = nvme_class;
+       ctrl->device->parent = ctrl->dev;
+       ctrl->device->groups = nvme_dev_attr_groups;
+       ctrl->device->release = nvme_free_ctrl;
+       dev_set_drvdata(ctrl->device, ctrl);
+       ret = dev_set_name(ctrl->device, "nvme%d", ctrl->instance);
+       if (ret)
                goto out_release_instance;
-       }
-       get_device(ctrl->device);
+       ret = device_add(ctrl->device);
+       if (ret)
+               goto out_free_name;
+
        ida_init(&ctrl->ns_ida);
 
        spin_lock(&dev_list_lock);
                min(default_ps_max_latency_us, (unsigned long)S32_MAX));
 
        return 0;
+out_free_name:
+       kfree_const(dev->kobj.name);
 out_release_instance:
        ida_simple_remove(&nvme_instance_ida, ctrl->instance);
 out:
 
        struct request_queue *admin_q;
        struct request_queue *connect_q;
        struct device *dev;
-       struct kref kref;
        int instance;
        struct blk_mq_tag_set *tagset;
        struct blk_mq_tag_set *admin_tagset;
        struct list_head namespaces;
        struct mutex namespaces_mutex;
+       struct device ctrl_device;
        struct device *device;  /* char device */
        struct list_head node;
        struct ida ns_ida;
        blk_mq_complete_request(req);
 }
 
+static inline void nvme_get_ctrl(struct nvme_ctrl *ctrl)
+{
+       get_device(ctrl->device);
+}
+
+static inline void nvme_put_ctrl(struct nvme_ctrl *ctrl)
+{
+       put_device(ctrl->device);
+}
+
 void nvme_complete_rq(struct request *req);
 void nvme_cancel_request(struct request *req, void *data, bool reserved);
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 
         * Keep a reference until all work is flushed since
         * __nvme_rdma_del_ctrl can free the ctrl mem
         */
-       if (!kref_get_unless_zero(&ctrl->ctrl.kref))
-               return -EBUSY;
+       nvme_get_ctrl(&ctrl->ctrl);
        ret = __nvme_rdma_del_ctrl(ctrl);
        if (!ret)
                flush_work(&ctrl->delete_work);
        dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISpcs\n",
                ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
 
-       kref_get(&ctrl->ctrl.kref);
+       nvme_get_ctrl(&ctrl->ctrl);
 
        mutex_lock(&nvme_rdma_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_rdma_ctrl_list);