diff options
Diffstat (limited to 'drivers/block/drbd/drbd_req.c')
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 43bc1d064bc7..b923d41678e1 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -1164,32 +1164,74 @@ void __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long | |||
1164 | drbd_send_and_submit(mdev, req); | 1164 | drbd_send_and_submit(mdev, req); |
1165 | } | 1165 | } |
1166 | 1166 | ||
1167 | void __drbd_make_request_from_worker(struct drbd_conf *mdev, struct drbd_request *req) | 1167 | static void submit_fast_path(struct drbd_conf *mdev, struct list_head *incoming) |
1168 | { | 1168 | { |
1169 | const int rw = bio_rw(req->master_bio); | 1169 | struct drbd_request *req, *tmp; |
1170 | list_for_each_entry_safe(req, tmp, incoming, tl_requests) { | ||
1171 | const int rw = bio_data_dir(req->master_bio); | ||
1170 | 1172 | ||
1171 | if (rw == WRITE && req->private_bio && req->i.size | 1173 | if (rw == WRITE /* rw != WRITE should not even end up here! */ |
1172 | && !test_bit(AL_SUSPENDED, &mdev->flags)) { | 1174 | && req->private_bio && req->i.size |
1173 | drbd_al_begin_io(mdev, &req->i, false); | 1175 | && !test_bit(AL_SUSPENDED, &mdev->flags)) { |
1174 | req->rq_state |= RQ_IN_ACT_LOG; | 1176 | if (!drbd_al_begin_io_fastpath(mdev, &req->i)) |
1177 | continue; | ||
1178 | |||
1179 | req->rq_state |= RQ_IN_ACT_LOG; | ||
1180 | } | ||
1181 | |||
1182 | list_del_init(&req->tl_requests); | ||
1183 | drbd_send_and_submit(mdev, req); | ||
1175 | } | 1184 | } |
1176 | drbd_send_and_submit(mdev, req); | ||
1177 | } | 1185 | } |
1178 | 1186 | ||
1187 | static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev, | ||
1188 | struct list_head *incoming, | ||
1189 | struct list_head *pending) | ||
1190 | { | ||
1191 | struct drbd_request *req, *tmp; | ||
1192 | int wake = 0; | ||
1193 | int err; | ||
1194 | |||
1195 | spin_lock_irq(&mdev->al_lock); | ||
1196 | list_for_each_entry_safe(req, tmp, incoming, tl_requests) { | ||
1197 | err = drbd_al_begin_io_nonblock(mdev, &req->i); | ||
1198 | if (err == -EBUSY) | ||
1199 | wake = 1; | ||
1200 | if (err) | ||
1201 | continue; | ||
1202 | req->rq_state |= RQ_IN_ACT_LOG; | ||
1203 | list_move_tail(&req->tl_requests, pending); | ||
1204 | } | ||
1205 | spin_unlock_irq(&mdev->al_lock); | ||
1206 | if (wake) | ||
1207 | wake_up(&mdev->al_wait); | ||
1208 | |||
1209 | return !list_empty(pending); | ||
1210 | } | ||
1179 | 1211 | ||
1180 | void do_submit(struct work_struct *ws) | 1212 | void do_submit(struct work_struct *ws) |
1181 | { | 1213 | { |
1182 | struct drbd_conf *mdev = container_of(ws, struct drbd_conf, submit.worker); | 1214 | struct drbd_conf *mdev = container_of(ws, struct drbd_conf, submit.worker); |
1183 | LIST_HEAD(writes); | 1215 | LIST_HEAD(incoming); |
1216 | LIST_HEAD(pending); | ||
1184 | struct drbd_request *req, *tmp; | 1217 | struct drbd_request *req, *tmp; |
1185 | 1218 | ||
1186 | spin_lock(&mdev->submit.lock); | 1219 | for (;;) { |
1187 | list_splice_init(&mdev->submit.writes, &writes); | 1220 | spin_lock(&mdev->submit.lock); |
1188 | spin_unlock(&mdev->submit.lock); | 1221 | list_splice_tail_init(&mdev->submit.writes, &incoming); |
1222 | spin_unlock(&mdev->submit.lock); | ||
1189 | 1223 | ||
1190 | list_for_each_entry_safe(req, tmp, &writes, tl_requests) { | 1224 | submit_fast_path(mdev, &incoming); |
1191 | list_del_init(&req->tl_requests); | 1225 | if (list_empty(&incoming)) |
1192 | __drbd_make_request_from_worker(mdev, req); | 1226 | break; |
1227 | |||
1228 | wait_event(mdev->al_wait, prepare_al_transaction_nonblock(mdev, &incoming, &pending)); | ||
1229 | drbd_al_begin_io_commit(mdev, false); | ||
1230 | |||
1231 | list_for_each_entry_safe(req, tmp, &pending, tl_requests) { | ||
1232 | list_del_init(&req->tl_requests); | ||
1233 | drbd_send_and_submit(mdev, req); | ||
1234 | } | ||
1193 | } | 1235 | } |
1194 | } | 1236 | } |
1195 | 1237 | ||