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; |
