static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
 static struct workqueue_struct *md_wq;
 static struct workqueue_struct *md_misc_wq;
-static struct workqueue_struct *md_rdev_misc_wq;
 
 static int remove_and_add_spares(struct mddev *mddev,
                                 struct md_rdev *this);
 static void mddev_detach(struct mddev *mddev);
+static void export_rdev(struct md_rdev *rdev, struct mddev *mddev);
 
 /*
  * Default number of read corrections we'll attempt on an rdev
 {
        mutex_init(&mddev->open_mutex);
        mutex_init(&mddev->reconfig_mutex);
+       mutex_init(&mddev->delete_mutex);
        mutex_init(&mddev->bitmap_info.mutex);
        INIT_LIST_HEAD(&mddev->disks);
        INIT_LIST_HEAD(&mddev->all_mddevs);
+       INIT_LIST_HEAD(&mddev->deleting);
        timer_setup(&mddev->safemode_timer, md_safemode_timeout, 0);
        atomic_set(&mddev->active, 1);
        atomic_set(&mddev->openers, 0);
 
 static const struct attribute_group md_redundancy_group;
 
+static void md_free_rdev(struct mddev *mddev)
+{
+       struct md_rdev *rdev;
+       struct md_rdev *tmp;
+
+       mutex_lock(&mddev->delete_mutex);
+       if (list_empty(&mddev->deleting))
+               goto out;
+
+       list_for_each_entry_safe(rdev, tmp, &mddev->deleting, same_set) {
+               list_del_init(&rdev->same_set);
+               kobject_del(&rdev->kobj);
+               export_rdev(rdev, mddev);
+       }
+out:
+       mutex_unlock(&mddev->delete_mutex);
+}
+
 void mddev_unlock(struct mddev *mddev)
 {
        if (mddev->to_remove) {
        } else
                mutex_unlock(&mddev->reconfig_mutex);
 
+       md_free_rdev(mddev);
+
        /* As we've dropped the mutex we need a spinlock to
         * make sure the thread doesn't disappear
         */
        return err;
 }
 
-static void rdev_delayed_delete(struct work_struct *ws)
-{
-       struct md_rdev *rdev = container_of(ws, struct md_rdev, del_work);
-       kobject_del(&rdev->kobj);
-       kobject_put(&rdev->kobj);
-}
-
 void md_autodetect_dev(dev_t dev);
 
 /* just for claiming the bdev */
 
 static void md_kick_rdev_from_array(struct md_rdev *rdev)
 {
+       struct mddev *mddev = rdev->mddev;
+
        bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
        list_del_rcu(&rdev->same_set);
        pr_debug("md: unbind<%pg>\n", rdev->bdev);
        rdev->sysfs_unack_badblocks = NULL;
        rdev->sysfs_badblocks = NULL;
        rdev->badblocks.count = 0;
-       /* We need to delay this, otherwise we can deadlock when
-        * writing to 'remove' to "dev/state".  We also need
-        * to delay it due to rcu usage.
-        */
+
        synchronize_rcu();
-       INIT_WORK(&rdev->del_work, rdev_delayed_delete);
-       kobject_get(&rdev->kobj);
-       queue_work(md_rdev_misc_wq, &rdev->del_work);
-       export_rdev(rdev, rdev->mddev);
+
+       /*
+        * kobject_del() will wait for all in progress writers to be done, where
+        * reconfig_mutex is held, hence it can't be called under
+        * reconfig_mutex and it's delayed to mddev_unlock().
+        */
+       mutex_lock(&mddev->delete_mutex);
+       list_add(&rdev->same_set, &mddev->deleting);
+       mutex_unlock(&mddev->delete_mutex);
 }
 
 static void export_array(struct mddev *mddev)
 {
        struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
        struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj);
+       struct kernfs_node *kn = NULL;
        ssize_t rv;
        struct mddev *mddev = rdev->mddev;
 
                return -EIO;
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
+
+       if (entry->store == state_store && cmd_match(page, "remove"))
+               kn = sysfs_break_active_protection(kobj, attr);
+
        rv = mddev ? mddev_lock(mddev) : -ENODEV;
        if (!rv) {
                if (rdev->mddev == NULL)
                        rv = entry->store(rdev, page, length);
                mddev_unlock(mddev);
        }
+
+       if (kn)
+               sysfs_unbreak_active_protection(kn);
+
        return rv;
 }
 
        return -EINVAL;
 }
 
-/* need to ensure rdev_delayed_delete() has completed */
-static void flush_rdev_wq(struct mddev *mddev)
-{
-       struct md_rdev *rdev;
-
-       rcu_read_lock();
-       rdev_for_each_rcu(rdev, mddev)
-               if (work_pending(&rdev->del_work)) {
-                       flush_workqueue(md_rdev_misc_wq);
-                       break;
-               }
-       rcu_read_unlock();
-}
-
 static ssize_t
 new_dev_store(struct mddev *mddev, const char *buf, size_t len)
 {
            minor != MINOR(dev))
                return -EOVERFLOW;
 
-       flush_rdev_wq(mddev);
        err = mddev_lock(mddev);
        if (err)
                return err;
         * removed (mddev_delayed_delete).
         */
        flush_workqueue(md_misc_wq);
-       flush_workqueue(md_rdev_misc_wq);
 
        mutex_lock(&disks_mutex);
        mddev = mddev_alloc(dev);
 
        }
 
-       if (cmd == ADD_NEW_DISK || cmd == HOT_ADD_DISK)
-               flush_rdev_wq(mddev);
-
        if (cmd == HOT_REMOVE_DISK)
                /* need to ensure recovery thread has run */
                wait_event_interruptible_timeout(mddev->sb_wait,
        if (!md_misc_wq)
                goto err_misc_wq;
 
-       md_rdev_misc_wq = alloc_workqueue("md_rdev_misc", 0, 0);
-       if (!md_rdev_misc_wq)
-               goto err_rdev_misc_wq;
-
        ret = __register_blkdev(MD_MAJOR, "md", md_probe);
        if (ret < 0)
                goto err_md;
 err_mdp:
        unregister_blkdev(MD_MAJOR, "md");
 err_md:
-       destroy_workqueue(md_rdev_misc_wq);
-err_rdev_misc_wq:
        destroy_workqueue(md_misc_wq);
 err_misc_wq:
        destroy_workqueue(md_wq);
        }
        spin_unlock(&all_mddevs_lock);
 
-       destroy_workqueue(md_rdev_misc_wq);
        destroy_workqueue(md_misc_wq);
        destroy_workqueue(md_wq);
 }