diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f6d6276974eef..908475fd4dd39 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -886,8 +886,6 @@ struct drbd_device { atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */ atomic_t rs_sect_ev; /* for submitted resync data rate, both */ int rs_last_sect_ev; /* counter to compare with */ - int rs_last_events; /* counter of read or write "events" (unit sectors) - * on the lower level device when we last looked. */ int c_sync_rate; /* current resync rate after syncer throttle magic */ struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, connection->conn_update) */ int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b1a721dd04969..b370b173259b9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2018,7 +2018,6 @@ void drbd_device_cleanup(struct drbd_device *device) device->rs_start = device->rs_total = device->rs_failed = 0; - device->rs_last_events = 0; device->rs_last_sect_ev = 0; for (i = 0; i < DRBD_SYNC_MARKS; i++) { device->rs_mark_left[i] = 0; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 58b95bf4bdca6..93ca35e7a960a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2569,50 +2569,56 @@ bool drbd_rs_should_slow_down(struct drbd_peer_device *peer_device, sector_t sec return throttle; } +/* + * Throttle resync when application I/O is in flight on the backing + * device and the resync is running faster than c-min-rate. + * + * The previous heuristic compared the backing device's part_stat + * sectors counter against our own rs_sect_ev counter (similar to + * MD RAID is_mddev_idle()) and fired on a delta > 64 sectors. That + * comparison is racy: rs_sect_ev is bumped at submission while + * part_stat is updated on bio completion (and is per-cpu), and the + * receiver path bumps rs_sect_ev *after* the throttle check. On + * fast hardware the transient skew routinely exceeds 64 sectors + * even with no application I/O, capping resync throughput at + * c-min-rate. + * + * ap_bio_cnt is incremented unconditionally for every application + * request in drbd_make_request(), so it is the authoritative + * "is application I/O in flight" signal. + */ bool drbd_rs_c_min_rate_throttle(struct drbd_device *device) { - struct gendisk *disk = device->ldev->backing_bdev->bd_disk; unsigned long db, dt, dbdt; unsigned int c_min_rate; - int curr_events; + unsigned long rs_left; + int i; rcu_read_lock(); c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate; rcu_read_unlock(); - /* feature disabled? */ if (c_min_rate == 0) return false; - curr_events = (int)part_stat_read_accum(disk->part0, sectors) - - atomic_read(&device->rs_sect_ev); - - if (atomic_read(&device->ap_actlog_cnt) - || curr_events - device->rs_last_events > 64) { - unsigned long rs_left; - int i; - - device->rs_last_events = curr_events; + if (!atomic_read(&device->ap_bio_cnt)) + return false; - /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, - * approx. */ - i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; + /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, approx. */ + i = (device->rs_last_mark + DRBD_SYNC_MARKS - 1) % DRBD_SYNC_MARKS; - if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T) - rs_left = device->ov_left; - else - rs_left = drbd_bm_total_weight(device) - device->rs_failed; + if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T) + rs_left = device->ov_left; + else + rs_left = drbd_bm_total_weight(device) - device->rs_failed; - dt = ((long)jiffies - (long)device->rs_mark_time[i]) / HZ; - if (!dt) - dt++; - db = device->rs_mark_left[i] - rs_left; - dbdt = Bit2KB(db/dt); + dt = ((long)jiffies - (long)device->rs_mark_time[i]) / HZ; + if (!dt) + dt++; + db = device->rs_mark_left[i] - rs_left; + dbdt = Bit2KB(db / dt); - if (dbdt > c_min_rate) - return true; - } - return false; + return dbdt > c_min_rate; } static int receive_DataRequest(struct drbd_connection *connection, struct packet_info *pi) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 0697f99fed18d..cf7f322103abb 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1657,14 +1657,11 @@ void drbd_resync_after_changed(struct drbd_device *device) void drbd_rs_controller_reset(struct drbd_peer_device *peer_device) { struct drbd_device *device = peer_device->device; - struct gendisk *disk = device->ldev->backing_bdev->bd_disk; struct fifo_buffer *plan; atomic_set(&device->rs_sect_in, 0); atomic_set(&device->rs_sect_ev, 0); device->rs_in_flight = 0; - device->rs_last_events = - (int)part_stat_read_accum(disk->part0, sectors); /* Updating the RCU protected object in place is necessary since this function gets called from atomic context.