diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2013-03-19 13:16:52 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-03-22 20:15:17 -0400 |
commit | b5bc8e08641805391f2c7834c40d0f647e8563c6 (patch) | |
tree | be2adceb4f169023eb5c3d56046751b40b8f6bab | |
parent | 113fef9e20e0d614b3f5940b67c96e719c559eea (diff) |
drbd: split drbd_al_begin_io into fastpath, prepare, and commit
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_actlog.c | 104 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 1 |
2 files changed, 72 insertions, 33 deletions
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 1d7244d2a910..e4f1231c2ef2 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c | |||
@@ -104,7 +104,6 @@ struct update_al_work { | |||
104 | int err; | 104 | int err; |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static int al_write_transaction(struct drbd_conf *mdev, bool delegate); | ||
108 | 107 | ||
109 | void *drbd_md_get_buffer(struct drbd_conf *mdev) | 108 | void *drbd_md_get_buffer(struct drbd_conf *mdev) |
110 | { | 109 | { |
@@ -246,30 +245,37 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) | |||
246 | return al_ext; | 245 | return al_ext; |
247 | } | 246 | } |
248 | 247 | ||
249 | /* | 248 | bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i) |
250 | * @delegate: delegate activity log I/O to the worker thread | ||
251 | */ | ||
252 | void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate) | ||
253 | { | 249 | { |
254 | /* for bios crossing activity log extent boundaries, | 250 | /* for bios crossing activity log extent boundaries, |
255 | * we may need to activate two extents in one go */ | 251 | * we may need to activate two extents in one go */ |
256 | unsigned first = i->sector >> (AL_EXTENT_SHIFT-9); | 252 | unsigned first = i->sector >> (AL_EXTENT_SHIFT-9); |
257 | unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9); | 253 | unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9); |
258 | unsigned enr; | 254 | bool fastpath_ok = true; |
259 | bool need_transaction = false; | ||
260 | bool locked = false; | ||
261 | 255 | ||
262 | /* When called through generic_make_request(), we must delegate | 256 | D_ASSERT((unsigned)(last - first) <= 1); |
263 | * activity log I/O to the worker thread: a further request | 257 | D_ASSERT(atomic_read(&mdev->local_cnt) > 0); |
264 | * submitted via generic_make_request() within the same task | 258 | |
265 | * would be queued on current->bio_list, and would only start | 259 | /* FIXME figure out a fast path for bios crossing AL extent boundaries */ |
266 | * after this function returns (see generic_make_request()). | 260 | if (first != last) |
267 | * | 261 | return false; |
268 | * However, if we *are* the worker, we must not delegate to ourselves. | 262 | |
269 | */ | 263 | spin_lock_irq(&mdev->al_lock); |
264 | fastpath_ok = | ||
265 | lc_find(mdev->resync, first/AL_EXT_PER_BM_SECT) == NULL && | ||
266 | lc_try_get(mdev->act_log, first) != NULL; | ||
267 | spin_unlock_irq(&mdev->al_lock); | ||
268 | return fastpath_ok; | ||
269 | } | ||
270 | 270 | ||
271 | if (delegate) | 271 | bool drbd_al_begin_io_prepare(struct drbd_conf *mdev, struct drbd_interval *i) |
272 | BUG_ON(current == mdev->tconn->worker.task); | 272 | { |
273 | /* for bios crossing activity log extent boundaries, | ||
274 | * we may need to activate two extents in one go */ | ||
275 | unsigned first = i->sector >> (AL_EXTENT_SHIFT-9); | ||
276 | unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9); | ||
277 | unsigned enr; | ||
278 | bool need_transaction = false; | ||
273 | 279 | ||
274 | D_ASSERT(first <= last); | 280 | D_ASSERT(first <= last); |
275 | D_ASSERT(atomic_read(&mdev->local_cnt) > 0); | 281 | D_ASSERT(atomic_read(&mdev->local_cnt) > 0); |
@@ -280,11 +286,28 @@ void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool dele | |||
280 | if (al_ext->lc_number != enr) | 286 | if (al_ext->lc_number != enr) |
281 | need_transaction = true; | 287 | need_transaction = true; |
282 | } | 288 | } |
289 | return need_transaction; | ||
290 | } | ||
283 | 291 | ||
284 | /* If *this* request was to an already active extent, | 292 | static int al_write_transaction(struct drbd_conf *mdev, bool delegate); |
285 | * we're done, even if there are pending changes. */ | 293 | |
286 | if (!need_transaction) | 294 | /* When called through generic_make_request(), we must delegate |
287 | return; | 295 | * activity log I/O to the worker thread: a further request |
296 | * submitted via generic_make_request() within the same task | ||
297 | * would be queued on current->bio_list, and would only start | ||
298 | * after this function returns (see generic_make_request()). | ||
299 | * | ||
300 | * However, if we *are* the worker, we must not delegate to ourselves. | ||
301 | */ | ||
302 | |||
303 | /* | ||
304 | * @delegate: delegate activity log I/O to the worker thread | ||
305 | */ | ||
306 | void drbd_al_begin_io_commit(struct drbd_conf *mdev, bool delegate) | ||
307 | { | ||
308 | bool locked = false; | ||
309 | |||
310 | BUG_ON(delegate && current == mdev->tconn->worker.task); | ||
288 | 311 | ||
289 | /* Serialize multiple transactions. | 312 | /* Serialize multiple transactions. |
290 | * This uses test_and_set_bit, memory barrier is implicit. | 313 | * This uses test_and_set_bit, memory barrier is implicit. |
@@ -303,11 +326,8 @@ void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool dele | |||
303 | write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates; | 326 | write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates; |
304 | rcu_read_unlock(); | 327 | rcu_read_unlock(); |
305 | 328 | ||
306 | if (write_al_updates) { | 329 | if (write_al_updates) |
307 | al_write_transaction(mdev, delegate); | 330 | al_write_transaction(mdev, delegate); |
308 | mdev->al_writ_cnt++; | ||
309 | } | ||
310 | |||
311 | spin_lock_irq(&mdev->al_lock); | 331 | spin_lock_irq(&mdev->al_lock); |
312 | /* FIXME | 332 | /* FIXME |
313 | if (err) | 333 | if (err) |
@@ -321,6 +341,17 @@ void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool dele | |||
321 | } | 341 | } |
322 | } | 342 | } |
323 | 343 | ||
344 | /* | ||
345 | * @delegate: delegate activity log I/O to the worker thread | ||
346 | */ | ||
347 | void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate) | ||
348 | { | ||
349 | BUG_ON(delegate && current == mdev->tconn->worker.task); | ||
350 | |||
351 | if (drbd_al_begin_io_prepare(mdev, i)) | ||
352 | drbd_al_begin_io_commit(mdev, delegate); | ||
353 | } | ||
354 | |||
324 | void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i) | 355 | void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i) |
325 | { | 356 | { |
326 | /* for bios crossing activity log extent boundaries, | 357 | /* for bios crossing activity log extent boundaries, |
@@ -478,15 +509,22 @@ _al_write_transaction(struct drbd_conf *mdev) | |||
478 | crc = crc32c(0, buffer, 4096); | 509 | crc = crc32c(0, buffer, 4096); |
479 | buffer->crc32c = cpu_to_be32(crc); | 510 | buffer->crc32c = cpu_to_be32(crc); |
480 | 511 | ||
481 | /* normal execution path goes through all three branches */ | ||
482 | if (drbd_bm_write_hinted(mdev)) | 512 | if (drbd_bm_write_hinted(mdev)) |
483 | err = -EIO; | 513 | err = -EIO; |
484 | /* drbd_chk_io_error done already */ | 514 | else { |
485 | else if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { | 515 | bool write_al_updates; |
486 | err = -EIO; | 516 | rcu_read_lock(); |
487 | drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR); | 517 | write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates; |
488 | } else { | 518 | rcu_read_unlock(); |
489 | mdev->al_tr_number++; | 519 | if (write_al_updates) { |
520 | if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { | ||
521 | err = -EIO; | ||
522 | drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR); | ||
523 | } else { | ||
524 | mdev->al_tr_number++; | ||
525 | mdev->al_writ_cnt++; | ||
526 | } | ||
527 | } | ||
490 | } | 528 | } |
491 | 529 | ||
492 | drbd_md_put_buffer(mdev); | 530 | drbd_md_put_buffer(mdev); |
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a6b71b6076b5..b7b52dd42325 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1611,6 +1611,7 @@ extern const char *drbd_conn_str(enum drbd_conns s); | |||
1611 | extern const char *drbd_role_str(enum drbd_role s); | 1611 | extern const char *drbd_role_str(enum drbd_role s); |
1612 | 1612 | ||
1613 | /* drbd_actlog.c */ | 1613 | /* drbd_actlog.c */ |
1614 | extern bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i); | ||
1614 | extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate); | 1615 | extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate); |
1615 | extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i); | 1616 | extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i); |
1616 | extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector); | 1617 | extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector); |