writeback, cgroup: Adjust WB_FRN_TIME_CUT_DIV to accelerate foreign inode switching
authorTejun Heo <tj@kernel.org>
Thu, 15 Aug 2019 19:25:28 +0000 (12:25 -0700)
committerJens Axboe <axboe@kernel.dk>
Thu, 15 Aug 2019 19:30:44 +0000 (13:30 -0600)
WB_FRN_TIME_CUT_DIV is used to tell the foreign inode detection logic
to ignore short writeback rounds to prevent getting confused by a
burst of short writebacks.  The parameter is currently 2 meaning that
anything smaller than half of the running average writback duration
will be ignored.

This is unnecessarily aggressive.  The detection logic uses 16 history
slots and is already reasonably protected against some short bursts
confusing it and the current parameter can lead to tens of seconds of
missed detection depending on the writeback pattern.

Let's change the parameter to 8, so that it only ignores writeback
with are smaller than 12.5% of the current running average.

v2: Add comment explaining what's going on with the foreign detection
    parameters.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/fs-writeback.c

index 542b02d170f8bb99408aa7537bde91c10f977099..025a63894cf00fb83aecda6fe246ac4be63e84a2 100644 (file)
@@ -224,10 +224,28 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi,
 
 #ifdef CONFIG_CGROUP_WRITEBACK
 
-/* parameters for foreign inode detection, see wb_detach_inode() */
+/*
+ * Parameters for foreign inode detection, see wbc_detach_inode() to see
+ * how they're used.
+ *
+ * These paramters are inherently heuristical as the detection target
+ * itself is fuzzy.  All we want to do is detaching an inode from the
+ * current owner if it's being written to by some other cgroups too much.
+ *
+ * The current cgroup writeback is built on the assumption that multiple
+ * cgroups writing to the same inode concurrently is very rare and a mode
+ * of operation which isn't well supported.  As such, the goal is not
+ * taking too long when a different cgroup takes over an inode while
+ * avoiding too aggressive flip-flops from occasional foreign writes.
+ *
+ * We record, very roughly, 2s worth of IO time history and if more than
+ * half of that is foreign, trigger the switch.  The recording is quantized
+ * to 16 slots.  To avoid tiny writes from swinging the decision too much,
+ * writes smaller than 1/8 of avg size are ignored.
+ */
 #define WB_FRN_TIME_SHIFT      13      /* 1s = 2^13, upto 8 secs w/ 16bit */
 #define WB_FRN_TIME_AVG_SHIFT  3       /* avg = avg * 7/8 + new * 1/8 */
-#define WB_FRN_TIME_CUT_DIV    2       /* ignore rounds < avg / 2 */
+#define WB_FRN_TIME_CUT_DIV    8       /* ignore rounds < avg / 8 */
 #define WB_FRN_TIME_PERIOD     (2 * (1 << WB_FRN_TIME_SHIFT))  /* 2s */
 
 #define WB_FRN_HIST_SLOTS      16      /* inode->i_wb_frn_history is 16bit */