|
@@ -145,9 +145,6 @@ struct dirty_throttle_control {
|
|
|
unsigned long pos_ratio;
|
|
|
};
|
|
|
|
|
|
-#define DTC_INIT_COMMON(__wb) .wb = (__wb), \
|
|
|
- .wb_completions = &(__wb)->completions
|
|
|
-
|
|
|
/*
|
|
|
* Length of period for aging writeout fractions of bdis. This is an
|
|
|
* arbitrarily chosen number. The longer the period, the slower fractions will
|
|
@@ -157,12 +154,16 @@ struct dirty_throttle_control {
|
|
|
|
|
|
#ifdef CONFIG_CGROUP_WRITEBACK
|
|
|
|
|
|
-#define GDTC_INIT(__wb) .dom = &global_wb_domain, \
|
|
|
- DTC_INIT_COMMON(__wb)
|
|
|
+#define GDTC_INIT(__wb) .wb = (__wb), \
|
|
|
+ .dom = &global_wb_domain, \
|
|
|
+ .wb_completions = &(__wb)->completions
|
|
|
+
|
|
|
#define GDTC_INIT_NO_WB .dom = &global_wb_domain
|
|
|
-#define MDTC_INIT(__wb, __gdtc) .dom = mem_cgroup_wb_domain(__wb), \
|
|
|
- .gdtc = __gdtc, \
|
|
|
- DTC_INIT_COMMON(__wb)
|
|
|
+
|
|
|
+#define MDTC_INIT(__wb, __gdtc) .wb = (__wb), \
|
|
|
+ .dom = mem_cgroup_wb_domain(__wb), \
|
|
|
+ .wb_completions = &(__wb)->memcg_completions, \
|
|
|
+ .gdtc = __gdtc
|
|
|
|
|
|
static bool mdtc_valid(struct dirty_throttle_control *dtc)
|
|
|
{
|
|
@@ -213,7 +214,8 @@ static void wb_min_max_ratio(struct bdi_writeback *wb,
|
|
|
|
|
|
#else /* CONFIG_CGROUP_WRITEBACK */
|
|
|
|
|
|
-#define GDTC_INIT(__wb) DTC_INIT_COMMON(__wb)
|
|
|
+#define GDTC_INIT(__wb) .wb = (__wb), \
|
|
|
+ .wb_completions = &(__wb)->completions
|
|
|
#define GDTC_INIT_NO_WB
|
|
|
#define MDTC_INIT(__wb, __gdtc)
|
|
|
|
|
@@ -682,13 +684,19 @@ static unsigned long hard_dirty_limit(struct wb_domain *dom,
|
|
|
return max(thresh, dom->dirty_limit);
|
|
|
}
|
|
|
|
|
|
-/* memory available to a memcg domain is capped by system-wide clean memory */
|
|
|
-static void mdtc_cap_avail(struct dirty_throttle_control *mdtc)
|
|
|
+/*
|
|
|
+ * Memory which can be further allocated to a memcg domain is capped by
|
|
|
+ * system-wide clean memory excluding the amount being used in the domain.
|
|
|
+ */
|
|
|
+static void mdtc_calc_avail(struct dirty_throttle_control *mdtc,
|
|
|
+ unsigned long filepages, unsigned long headroom)
|
|
|
{
|
|
|
struct dirty_throttle_control *gdtc = mdtc_gdtc(mdtc);
|
|
|
- unsigned long clean = gdtc->avail - min(gdtc->avail, gdtc->dirty);
|
|
|
+ unsigned long clean = filepages - min(filepages, mdtc->dirty);
|
|
|
+ unsigned long global_clean = gdtc->avail - min(gdtc->avail, gdtc->dirty);
|
|
|
+ unsigned long other_clean = global_clean - min(global_clean, clean);
|
|
|
|
|
|
- mdtc->avail = min(mdtc->avail, clean);
|
|
|
+ mdtc->avail = filepages + min(headroom, other_clean);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1562,16 +1570,16 @@ static void balance_dirty_pages(struct address_space *mapping,
|
|
|
}
|
|
|
|
|
|
if (mdtc) {
|
|
|
- unsigned long writeback;
|
|
|
+ unsigned long filepages, headroom, writeback;
|
|
|
|
|
|
/*
|
|
|
* If @wb belongs to !root memcg, repeat the same
|
|
|
* basic calculations for the memcg domain.
|
|
|
*/
|
|
|
- mem_cgroup_wb_stats(wb, &mdtc->avail, &mdtc->dirty,
|
|
|
- &writeback);
|
|
|
- mdtc_cap_avail(mdtc);
|
|
|
+ mem_cgroup_wb_stats(wb, &filepages, &headroom,
|
|
|
+ &mdtc->dirty, &writeback);
|
|
|
mdtc->dirty += writeback;
|
|
|
+ mdtc_calc_avail(mdtc, filepages, headroom);
|
|
|
|
|
|
domain_dirty_limits(mdtc);
|
|
|
|
|
@@ -1893,10 +1901,11 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
|
|
|
return true;
|
|
|
|
|
|
if (mdtc) {
|
|
|
- unsigned long writeback;
|
|
|
+ unsigned long filepages, headroom, writeback;
|
|
|
|
|
|
- mem_cgroup_wb_stats(wb, &mdtc->avail, &mdtc->dirty, &writeback);
|
|
|
- mdtc_cap_avail(mdtc);
|
|
|
+ mem_cgroup_wb_stats(wb, &filepages, &headroom, &mdtc->dirty,
|
|
|
+ &writeback);
|
|
|
+ mdtc_calc_avail(mdtc, filepages, headroom);
|
|
|
domain_dirty_limits(mdtc); /* ditto, ignore writeback */
|
|
|
|
|
|
if (mdtc->dirty > mdtc->bg_thresh)
|
|
@@ -1956,7 +1965,6 @@ void laptop_mode_timer_fn(unsigned long data)
|
|
|
int nr_pages = global_page_state(NR_FILE_DIRTY) +
|
|
|
global_page_state(NR_UNSTABLE_NFS);
|
|
|
struct bdi_writeback *wb;
|
|
|
- struct wb_iter iter;
|
|
|
|
|
|
/*
|
|
|
* We want to write everything out, not just down to the dirty
|
|
@@ -1965,10 +1973,12 @@ void laptop_mode_timer_fn(unsigned long data)
|
|
|
if (!bdi_has_dirty_io(&q->backing_dev_info))
|
|
|
return;
|
|
|
|
|
|
- bdi_for_each_wb(wb, &q->backing_dev_info, &iter, 0)
|
|
|
+ rcu_read_lock();
|
|
|
+ list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node)
|
|
|
if (wb_has_dirty_io(wb))
|
|
|
wb_start_writeback(wb, nr_pages, true,
|
|
|
WB_REASON_LAPTOP_TIMER);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
/*
|