aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2013-03-19 13:16:52 -0400
committerJens Axboe <axboe@kernel.dk>2013-03-22 20:15:17 -0400
commitb5bc8e08641805391f2c7834c40d0f647e8563c6 (patch)
treebe2adceb4f169023eb5c3d56046751b40b8f6bab
parent113fef9e20e0d614b3f5940b67c96e719c559eea (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.c104
-rw-r--r--drivers/block/drbd/drbd_int.h1
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
107static int al_write_transaction(struct drbd_conf *mdev, bool delegate);
108 107
109void *drbd_md_get_buffer(struct drbd_conf *mdev) 108void *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/* 248bool 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 */
252void 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) 271bool 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, 292static 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 */
306void 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 */
347void 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
324void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i) 355void 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);
1611extern const char *drbd_role_str(enum drbd_role s); 1611extern const char *drbd_role_str(enum drbd_role s);
1612 1612
1613/* drbd_actlog.c */ 1613/* drbd_actlog.c */
1614extern bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i);
1614extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate); 1615extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate);
1615extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i); 1616extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i);
1616extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector); 1617extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector);