Commit 970fb01a authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

writeback: add dirty_throttle_control->wb_bg_thresh

wb_bg_thresh is currently treated as a second-class citizen.  It's
only used when BDI_CAP_STRICTLIMIT is set and balance_dirty_pages()
doesn't calculate it unless the cap is set.  When the cap is set, the
calculated value is not passed around but instead recalculated
whenever it's used.

wb_position_ratio() calculates it by scaling wb_thresh proportional to
bg_thresh / thresh.  wb_update_dirty_ratelimit() uses wb_dirty_limit()
on bg_thresh, which should generally lead to a similar result as the
proportional scaling but can also be way off in the presence of
max/min_ratio settings.

Avoiding wb_bg_thresh calculation saves us one u64 multiplication and
divsion when BDI_CAP_STRICTLIMIT is not set.  Given that
balance_dirty_pages() is already ratelimited, this doesn't justify the
incurred extra complexity.

This patch adds wb_bg_thresh to dirty_throttle_control and makes
wb_dirty_limits() always calculate it and updates the users to use the
pre-calculated value.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jan Kara <jack@suse.cz>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Greg Thelen <gthelen@google.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 2bc00aef
...@@ -134,6 +134,7 @@ struct dirty_throttle_control { ...@@ -134,6 +134,7 @@ struct dirty_throttle_control {
unsigned long wb_dirty; /* per-wb counterparts */ unsigned long wb_dirty; /* per-wb counterparts */
unsigned long wb_thresh; unsigned long wb_thresh;
unsigned long wb_bg_thresh;
}; };
#define GDTC_INIT(__wb) .wb = (__wb) #define GDTC_INIT(__wb) .wb = (__wb)
...@@ -761,7 +762,6 @@ static unsigned long wb_position_ratio(struct dirty_throttle_control *dtc) ...@@ -761,7 +762,6 @@ static unsigned long wb_position_ratio(struct dirty_throttle_control *dtc)
*/ */
if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) { if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) {
long long wb_pos_ratio; long long wb_pos_ratio;
unsigned long wb_bg_thresh;
if (dtc->wb_dirty < 8) if (dtc->wb_dirty < 8)
return min_t(long long, pos_ratio * 2, return min_t(long long, pos_ratio * 2,
...@@ -770,9 +770,8 @@ static unsigned long wb_position_ratio(struct dirty_throttle_control *dtc) ...@@ -770,9 +770,8 @@ static unsigned long wb_position_ratio(struct dirty_throttle_control *dtc)
if (dtc->wb_dirty >= wb_thresh) if (dtc->wb_dirty >= wb_thresh)
return 0; return 0;
wb_bg_thresh = div_u64((u64)wb_thresh * dtc->bg_thresh, wb_setpoint = dirty_freerun_ceiling(wb_thresh,
dtc->thresh); dtc->wb_bg_thresh);
wb_setpoint = dirty_freerun_ceiling(wb_thresh, wb_bg_thresh);
if (wb_setpoint == 0 || wb_setpoint == wb_thresh) if (wb_setpoint == 0 || wb_setpoint == wb_thresh)
return 0; return 0;
...@@ -1104,15 +1103,14 @@ static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc, ...@@ -1104,15 +1103,14 @@ static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc,
* *
* We rampup dirty_ratelimit forcibly if wb_dirty is low because * We rampup dirty_ratelimit forcibly if wb_dirty is low because
* it's possible that wb_thresh is close to zero due to inactivity * it's possible that wb_thresh is close to zero due to inactivity
* of backing device (see the implementation of wb_calc_thresh()). * of backing device.
*/ */
if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) { if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) {
dirty = dtc->wb_dirty; dirty = dtc->wb_dirty;
if (dtc->wb_dirty < 8) if (dtc->wb_dirty < 8)
setpoint = dtc->wb_dirty + 1; setpoint = dtc->wb_dirty + 1;
else else
setpoint = (dtc->wb_thresh + setpoint = (dtc->wb_thresh + dtc->wb_bg_thresh) / 2;
wb_calc_thresh(wb, dtc->bg_thresh)) / 2;
} }
if (dirty < setpoint) { if (dirty < setpoint) {
...@@ -1307,8 +1305,7 @@ static long wb_min_pause(struct bdi_writeback *wb, ...@@ -1307,8 +1305,7 @@ static long wb_min_pause(struct bdi_writeback *wb,
return pages >= DIRTY_POLL_THRESH ? 1 + t / 2 : t; return pages >= DIRTY_POLL_THRESH ? 1 + t / 2 : t;
} }
static inline void wb_dirty_limits(struct dirty_throttle_control *dtc, static inline void wb_dirty_limits(struct dirty_throttle_control *dtc)
unsigned long *wb_bg_thresh)
{ {
struct bdi_writeback *wb = dtc->wb; struct bdi_writeback *wb = dtc->wb;
unsigned long wb_reclaimable; unsigned long wb_reclaimable;
...@@ -1327,11 +1324,8 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc, ...@@ -1327,11 +1324,8 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc,
* at some rate <= (write_bw / 2) for bringing down wb_dirty. * at some rate <= (write_bw / 2) for bringing down wb_dirty.
*/ */
dtc->wb_thresh = wb_calc_thresh(dtc->wb, dtc->thresh); dtc->wb_thresh = wb_calc_thresh(dtc->wb, dtc->thresh);
dtc->wb_bg_thresh = dtc->thresh ?
if (wb_bg_thresh) div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0;
*wb_bg_thresh = dtc->thresh ? div_u64((u64)dtc->wb_thresh *
dtc->bg_thresh,
dtc->thresh) : 0;
/* /*
* In order to avoid the stacked BDI deadlock we need * In order to avoid the stacked BDI deadlock we need
...@@ -1396,10 +1390,11 @@ static void balance_dirty_pages(struct address_space *mapping, ...@@ -1396,10 +1390,11 @@ static void balance_dirty_pages(struct address_space *mapping,
global_dirty_limits(&gdtc->bg_thresh, &gdtc->thresh); global_dirty_limits(&gdtc->bg_thresh, &gdtc->thresh);
if (unlikely(strictlimit)) { if (unlikely(strictlimit)) {
wb_dirty_limits(gdtc, &bg_thresh); wb_dirty_limits(gdtc);
dirty = gdtc->wb_dirty; dirty = gdtc->wb_dirty;
thresh = gdtc->wb_thresh; thresh = gdtc->wb_thresh;
bg_thresh = gdtc->wb_bg_thresh;
} else { } else {
dirty = gdtc->dirty; dirty = gdtc->dirty;
thresh = gdtc->thresh; thresh = gdtc->thresh;
...@@ -1427,7 +1422,7 @@ static void balance_dirty_pages(struct address_space *mapping, ...@@ -1427,7 +1422,7 @@ static void balance_dirty_pages(struct address_space *mapping,
wb_start_background_writeback(wb); wb_start_background_writeback(wb);
if (!strictlimit) if (!strictlimit)
wb_dirty_limits(gdtc, NULL); wb_dirty_limits(gdtc);
dirty_exceeded = (gdtc->wb_dirty > gdtc->wb_thresh) && dirty_exceeded = (gdtc->wb_dirty > gdtc->wb_thresh) &&
((gdtc->dirty > gdtc->thresh) || strictlimit); ((gdtc->dirty > gdtc->thresh) || strictlimit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment