|
@@ -45,7 +45,7 @@
|
|
|
#include <linux/reboot.h>
|
|
|
#include <linux/notifier.h>
|
|
|
#include <linux/kthread.h>
|
|
|
-
|
|
|
+#include <linux/workqueue.h>
|
|
|
#define __KERNEL_SYSCALLS__
|
|
|
#include <linux/unistd.h>
|
|
|
#include <linux/vmalloc.h>
|
|
@@ -2300,6 +2300,7 @@ static void drbd_cleanup(void)
|
|
|
idr_for_each_entry(&minors, mdev, i) {
|
|
|
idr_remove(&minors, mdev_to_minor(mdev));
|
|
|
idr_remove(&mdev->tconn->volumes, mdev->vnr);
|
|
|
+ destroy_workqueue(mdev->submit.wq);
|
|
|
del_gendisk(mdev->vdisk);
|
|
|
/* synchronize_rcu(); No other threads running at this point */
|
|
|
kref_put(&mdev->kref, &drbd_minor_destroy);
|
|
@@ -2589,6 +2590,21 @@ void conn_destroy(struct kref *kref)
|
|
|
kfree(tconn);
|
|
|
}
|
|
|
|
|
|
+int init_submitter(struct drbd_conf *mdev)
|
|
|
+{
|
|
|
+ /* opencoded create_singlethread_workqueue(),
|
|
|
+ * to be able to say "drbd%d", ..., minor */
|
|
|
+ mdev->submit.wq = alloc_workqueue("drbd%u_submit",
|
|
|
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1, mdev->minor);
|
|
|
+ if (!mdev->submit.wq)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ INIT_WORK(&mdev->submit.worker, do_submit);
|
|
|
+ spin_lock_init(&mdev->submit.lock);
|
|
|
+ INIT_LIST_HEAD(&mdev->submit.writes);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr)
|
|
|
{
|
|
|
struct drbd_conf *mdev;
|
|
@@ -2678,6 +2694,12 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
|
|
|
goto out_idr_remove_minor;
|
|
|
}
|
|
|
|
|
|
+ if (init_submitter(mdev)) {
|
|
|
+ err = ERR_NOMEM;
|
|
|
+ drbd_msg_put_info("unable to create submit workqueue");
|
|
|
+ goto out_idr_remove_vol;
|
|
|
+ }
|
|
|
+
|
|
|
add_disk(disk);
|
|
|
kref_init(&mdev->kref); /* one ref for both idrs and the the add_disk */
|
|
|
|
|
@@ -2688,6 +2710,8 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
|
|
+out_idr_remove_vol:
|
|
|
+ idr_remove(&tconn->volumes, vnr_got);
|
|
|
out_idr_remove_minor:
|
|
|
idr_remove(&minors, minor_got);
|
|
|
synchronize_rcu();
|