diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2013-03-22 20:14:40 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-03-22 20:14:40 -0400 |
commit | 113fef9e20e0d614b3f5940b67c96e719c559eea (patch) | |
tree | d116430f48e02c1a502df613e786787a36739552 | |
parent | 6d9febe237146156947f0da8407c620b5c33c1df (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.h | 13 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 26 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 29 |
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 | ||
897 | struct submit_worker { | ||
898 | struct workqueue_struct *wq; | ||
899 | struct work_struct worker; | ||
900 | |||
901 | spinlock_t lock; | ||
902 | struct list_head writes; | ||
903 | }; | ||
904 | |||
897 | struct drbd_conf { | 905 | struct 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 | ||
1039 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) | 1051 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) |
@@ -1440,6 +1452,7 @@ extern void conn_free_crypto(struct drbd_tconn *tconn); | |||
1440 | extern int proc_details; | 1452 | extern int proc_details; |
1441 | 1453 | ||
1442 | /* drbd_req */ | 1454 | /* drbd_req */ |
1455 | extern void do_submit(struct work_struct *ws); | ||
1443 | extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long); | 1456 | extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long); |
1444 | extern void drbd_make_request(struct request_queue *q, struct bio *bio); | 1457 | extern void drbd_make_request(struct request_queue *q, struct bio *bio); |
1445 | extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); | 1458 | extern 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 | ||
2593 | int 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 | |||
2592 | enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr) | 2608 | enum 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 | ||
2713 | out_idr_remove_vol: | ||
2714 | idr_remove(&tconn->volumes, vnr_got); | ||
2691 | out_idr_remove_minor: | 2715 | out_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 | ||
1163 | void __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 | |||
1176 | void 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 | |||
1163 | void drbd_make_request(struct request_queue *q, struct bio *bio) | 1192 | void 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; |