aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2013-03-22 20:14:40 -0400
committerJens Axboe <axboe@kernel.dk>2013-03-22 20:14:40 -0400
commit113fef9e20e0d614b3f5940b67c96e719c559eea (patch)
treed116430f48e02c1a502df613e786787a36739552
parent6d9febe237146156947f0da8407c620b5c33c1df (diff)
drbd: prepare to queue write requests on a submit worker
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/block/drbd/drbd_int.h13
-rw-r--r--drivers/block/drbd/drbd_main.c26
-rw-r--r--drivers/block/drbd/drbd_nl.c1
-rw-r--r--drivers/block/drbd/drbd_req.c29
4 files changed, 68 insertions, 1 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 453fccfc440c..a6b71b6076b5 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -894,6 +894,14 @@ struct drbd_tconn { /* is a resource from the config file */
894 } send; 894 } send;
895}; 895};
896 896
897struct submit_worker {
898 struct workqueue_struct *wq;
899 struct work_struct worker;
900
901 spinlock_t lock;
902 struct list_head writes;
903};
904
897struct drbd_conf { 905struct drbd_conf {
898 struct drbd_tconn *tconn; 906 struct drbd_tconn *tconn;
899 int vnr; /* volume number within the connection */ 907 int vnr; /* volume number within the connection */
@@ -1034,6 +1042,10 @@ struct drbd_conf {
1034 atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */ 1042 atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
1035 unsigned int peer_max_bio_size; 1043 unsigned int peer_max_bio_size;
1036 unsigned int local_max_bio_size; 1044 unsigned int local_max_bio_size;
1045
1046 /* any requests that would block in drbd_make_request()
1047 * are deferred to this single-threaded work queue */
1048 struct submit_worker submit;
1037}; 1049};
1038 1050
1039static inline struct drbd_conf *minor_to_mdev(unsigned int minor) 1051static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1440,6 +1452,7 @@ extern void conn_free_crypto(struct drbd_tconn *tconn);
1440extern int proc_details; 1452extern int proc_details;
1441 1453
1442/* drbd_req */ 1454/* drbd_req */
1455extern void do_submit(struct work_struct *ws);
1443extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long); 1456extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long);
1444extern void drbd_make_request(struct request_queue *q, struct bio *bio); 1457extern void drbd_make_request(struct request_queue *q, struct bio *bio);
1445extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); 1458extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index e55271d6e7f6..a150b59897a0 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -45,7 +45,7 @@
45#include <linux/reboot.h> 45#include <linux/reboot.h>
46#include <linux/notifier.h> 46#include <linux/notifier.h>
47#include <linux/kthread.h> 47#include <linux/kthread.h>
48 48#include <linux/workqueue.h>
49#define __KERNEL_SYSCALLS__ 49#define __KERNEL_SYSCALLS__
50#include <linux/unistd.h> 50#include <linux/unistd.h>
51#include <linux/vmalloc.h> 51#include <linux/vmalloc.h>
@@ -2300,6 +2300,7 @@ static void drbd_cleanup(void)
2300 idr_for_each_entry(&minors, mdev, i) { 2300 idr_for_each_entry(&minors, mdev, i) {
2301 idr_remove(&minors, mdev_to_minor(mdev)); 2301 idr_remove(&minors, mdev_to_minor(mdev));
2302 idr_remove(&mdev->tconn->volumes, mdev->vnr); 2302 idr_remove(&mdev->tconn->volumes, mdev->vnr);
2303 destroy_workqueue(mdev->submit.wq);
2303 del_gendisk(mdev->vdisk); 2304 del_gendisk(mdev->vdisk);
2304 /* synchronize_rcu(); No other threads running at this point */ 2305 /* synchronize_rcu(); No other threads running at this point */
2305 kref_put(&mdev->kref, &drbd_minor_destroy); 2306 kref_put(&mdev->kref, &drbd_minor_destroy);
@@ -2589,6 +2590,21 @@ void conn_destroy(struct kref *kref)
2589 kfree(tconn); 2590 kfree(tconn);
2590} 2591}
2591 2592
2593int init_submitter(struct drbd_conf *mdev)
2594{
2595 /* opencoded create_singlethread_workqueue(),
2596 * to be able to say "drbd%d", ..., minor */
2597 mdev->submit.wq = alloc_workqueue("drbd%u_submit",
2598 WQ_UNBOUND | WQ_MEM_RECLAIM, 1, mdev->minor);
2599 if (!mdev->submit.wq)
2600 return -ENOMEM;
2601
2602 INIT_WORK(&mdev->submit.worker, do_submit);
2603 spin_lock_init(&mdev->submit.lock);
2604 INIT_LIST_HEAD(&mdev->submit.writes);
2605 return 0;
2606}
2607
2592enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr) 2608enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr)
2593{ 2609{
2594 struct drbd_conf *mdev; 2610 struct drbd_conf *mdev;
@@ -2678,6 +2694,12 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
2678 goto out_idr_remove_minor; 2694 goto out_idr_remove_minor;
2679 } 2695 }
2680 2696
2697 if (init_submitter(mdev)) {
2698 err = ERR_NOMEM;
2699 drbd_msg_put_info("unable to create submit workqueue");
2700 goto out_idr_remove_vol;
2701 }
2702
2681 add_disk(disk); 2703 add_disk(disk);
2682 kref_init(&mdev->kref); /* one ref for both idrs and the the add_disk */ 2704 kref_init(&mdev->kref); /* one ref for both idrs and the the add_disk */
2683 2705
@@ -2688,6 +2710,8 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
2688 2710
2689 return NO_ERROR; 2711 return NO_ERROR;
2690 2712
2713out_idr_remove_vol:
2714 idr_remove(&tconn->volumes, vnr_got);
2691out_idr_remove_minor: 2715out_idr_remove_minor:
2692 idr_remove(&minors, minor_got); 2716 idr_remove(&minors, minor_got);
2693 synchronize_rcu(); 2717 synchronize_rcu();
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 974ea47a656a..bcf900bcd142 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -3173,6 +3173,7 @@ static enum drbd_ret_code adm_delete_minor(struct drbd_conf *mdev)
3173 CS_VERBOSE + CS_WAIT_COMPLETE); 3173 CS_VERBOSE + CS_WAIT_COMPLETE);
3174 idr_remove(&mdev->tconn->volumes, mdev->vnr); 3174 idr_remove(&mdev->tconn->volumes, mdev->vnr);
3175 idr_remove(&minors, mdev_to_minor(mdev)); 3175 idr_remove(&minors, mdev_to_minor(mdev));
3176 destroy_workqueue(mdev->submit.wq);
3176 del_gendisk(mdev->vdisk); 3177 del_gendisk(mdev->vdisk);
3177 synchronize_rcu(); 3178 synchronize_rcu();
3178 kref_put(&mdev->kref, &drbd_minor_destroy); 3179 kref_put(&mdev->kref, &drbd_minor_destroy);
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 96d5968fc1e4..4af709e0aae5 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -1160,6 +1160,35 @@ void __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long
1160 drbd_send_and_submit(mdev, req); 1160 drbd_send_and_submit(mdev, req);
1161} 1161}
1162 1162
1163void __drbd_make_request_from_worker(struct drbd_conf *mdev, struct drbd_request *req)
1164{
1165 const int rw = bio_rw(req->master_bio);
1166
1167 if (rw == WRITE && req->private_bio && req->i.size
1168 && !test_bit(AL_SUSPENDED, &mdev->flags)) {
1169 drbd_al_begin_io(mdev, &req->i, false);
1170 req->rq_state |= RQ_IN_ACT_LOG;
1171 }
1172 drbd_send_and_submit(mdev, req);
1173}
1174
1175
1176void do_submit(struct work_struct *ws)
1177{
1178 struct drbd_conf *mdev = container_of(ws, struct drbd_conf, submit.worker);
1179 LIST_HEAD(writes);
1180 struct drbd_request *req, *tmp;
1181
1182 spin_lock(&mdev->submit.lock);
1183 list_splice_init(&mdev->submit.writes, &writes);
1184 spin_unlock(&mdev->submit.lock);
1185
1186 list_for_each_entry_safe(req, tmp, &writes, tl_requests) {
1187 list_del_init(&req->tl_requests);
1188 __drbd_make_request_from_worker(mdev, req);
1189 }
1190}
1191
1163void drbd_make_request(struct request_queue *q, struct bio *bio) 1192void drbd_make_request(struct request_queue *q, struct bio *bio)
1164{ 1193{
1165 struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; 1194 struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;