|
|
@@ -198,6 +198,41 @@ int inode_congested(struct inode *inode, int cong_bits)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(inode_congested);
|
|
|
|
|
|
+/**
|
|
|
+ * wb_split_bdi_pages - split nr_pages to write according to bandwidth
|
|
|
+ * @wb: target bdi_writeback to split @nr_pages to
|
|
|
+ * @nr_pages: number of pages to write for the whole bdi
|
|
|
+ *
|
|
|
+ * Split @wb's portion of @nr_pages according to @wb's write bandwidth in
|
|
|
+ * relation to the total write bandwidth of all wb's w/ dirty inodes on
|
|
|
+ * @wb->bdi.
|
|
|
+ */
|
|
|
+static long wb_split_bdi_pages(struct bdi_writeback *wb, long nr_pages)
|
|
|
+{
|
|
|
+ unsigned long this_bw = wb->avg_write_bandwidth;
|
|
|
+ unsigned long tot_bw = atomic_long_read(&wb->bdi->tot_write_bandwidth);
|
|
|
+
|
|
|
+ if (nr_pages == LONG_MAX)
|
|
|
+ return LONG_MAX;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This may be called on clean wb's and proportional distribution
|
|
|
+ * may not make sense, just use the original @nr_pages in those
|
|
|
+ * cases. In general, we wanna err on the side of writing more.
|
|
|
+ */
|
|
|
+ if (!tot_bw || this_bw >= tot_bw)
|
|
|
+ return nr_pages;
|
|
|
+ else
|
|
|
+ return DIV_ROUND_UP_ULL((u64)nr_pages * this_bw, tot_bw);
|
|
|
+}
|
|
|
+
|
|
|
+#else /* CONFIG_CGROUP_WRITEBACK */
|
|
|
+
|
|
|
+static long wb_split_bdi_pages(struct bdi_writeback *wb, long nr_pages)
|
|
|
+{
|
|
|
+ return nr_pages;
|
|
|
+}
|
|
|
+
|
|
|
#endif /* CONFIG_CGROUP_WRITEBACK */
|
|
|
|
|
|
void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
|
|
|
@@ -1187,8 +1222,17 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
|
|
|
nr_pages = get_nr_dirty_pages();
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- list_for_each_entry_rcu(bdi, &bdi_list, bdi_list)
|
|
|
- wb_start_writeback(&bdi->wb, nr_pages, false, reason);
|
|
|
+ list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
|
|
|
+ struct bdi_writeback *wb;
|
|
|
+ struct wb_iter iter;
|
|
|
+
|
|
|
+ if (!bdi_has_dirty_io(bdi))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ bdi_for_each_wb(wb, bdi, &iter, 0)
|
|
|
+ wb_start_writeback(wb, wb_split_bdi_pages(wb, nr_pages),
|
|
|
+ false, reason);
|
|
|
+ }
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|