diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2013-12-20 14:39:48 +0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2014-07-10 20:34:49 +0400 |
commit | c7a58db4e9dc523b18bbfbc3aa311d8308acc293 (patch) | |
tree | 0860df4c69658c43adb83bd690b6d54a964ef9f2 /drivers/block/drbd/drbd_worker.c | |
parent | 70df70927b75eb86f12b14167c398b99dc3a56e4 (diff) | |
download | linux-c7a58db4e9dc523b18bbfbc3aa311d8308acc293.tar.xz |
drbd: get rid of atomic update on disk bitmap works
Just trigger the occasional lazy bitmap write-out during resync
from the central wait_for_work() helper.
Previously, during resync, bitmap pages would be written out separately,
synchronously, one at a time, at least 8 times each (every 512 bytes
worth of bitmap cleared).
Now we trigger "merge friendly" bulk write out of all cleared pages
every two seconds during resync, and once the resync is finished.
Most pages will be written out only once.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_worker.c')
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 595ab57aea96..59158858b17a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1804,6 +1804,58 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side) mutex_unlock(device->state_mutex); } +static void update_on_disk_bitmap(struct drbd_device *device) +{ + struct sib_info sib = { .sib_reason = SIB_SYNC_PROGRESS, }; + device->rs_last_bcast = jiffies; + + if (!get_ldev(device)) + return; + + drbd_bm_write_lazy(device, 0); + if (drbd_bm_total_weight(device) <= device->rs_failed) + drbd_resync_finished(device); + drbd_bcast_event(device, &sib); + /* update timestamp, in case it took a while to write out stuff */ + device->rs_last_bcast = jiffies; + put_ldev(device); +} + +bool wants_lazy_bitmap_update(struct drbd_device *device) +{ + enum drbd_conns connection_state = device->state.conn; + return + /* only do a lazy writeout, if device is in some resync state */ + (connection_state == C_SYNC_SOURCE + || connection_state == C_SYNC_TARGET + || connection_state == C_PAUSED_SYNC_S + || connection_state == C_PAUSED_SYNC_T) && + /* AND + * either we just finished, or the last lazy update + * was some time ago already. */ + (drbd_bm_total_weight(device) <= device->rs_failed + || time_after(jiffies, device->rs_last_bcast + 2*HZ)); +} + +static void try_update_all_on_disk_bitmaps(struct drbd_connection *connection) +{ + struct drbd_peer_device *peer_device; + int vnr; + + rcu_read_lock(); + idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { + struct drbd_device *device = peer_device->device; + if (!wants_lazy_bitmap_update(device)) + continue; + kref_get(&device->kref); + rcu_read_unlock(); + update_on_disk_bitmap(device); + kref_put(&device->kref, drbd_destroy_device); + rcu_read_lock(); + } + rcu_read_unlock(); +} + static bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list) { spin_lock_irq(&queue->q_lock); @@ -1882,6 +1934,8 @@ static void wait_for_work(struct drbd_connection *connection, struct list_head * /* may be woken up for other things but new work, too, * e.g. if the current epoch got closed. * In which case we send the barrier above. */ + + try_update_all_on_disk_bitmaps(connection); } finish_wait(&connection->sender_work.q_wait, &wait); |