Commit d1ae8ffdfaa16b2ab2e9346e81cf0ab6eaaae347

Authored by Vivek Goyal
Committed by Jens Axboe
1 parent 5478755616

blk-throttle: Trim/adjust slice_end once a bio has been dispatched

o During some testing I did following and noticed throttling stops working.

        - Put a very low limit on a cgroup, say 1 byte per second.
        - Start some reads, this will set slice_end to a very high value.
        - Change the limit to higher value say 1MB/s
        - Now IO unthrottles and finishes as expected.
        - Try to do the read again but IO is not limited to 1MB/s as expected.

o What is happening.
        - Initially low value of limit sets slice_end to a very high value.
        - During updation of limit, slice_end is not being truncated.
        - Very high value of slice_end leads to keeping the existing slice
          valid for a very long time and new slice does not start.
        - tg_may_dispatch() is called in blk_throtle_bio(), and trim_slice()
          is not called in this path. So slice_start is some old value and
          practically we are able to do huge amount of IO.

o There are many ways it can be fixed. I have fixed it by trying to
  adjust/cleanup slice_end in trim_slice(). Generally we extend slices if bio
  is big and can't be dispatched in one slice. After dispatch of bio, readjust
  the slice_end to make sure we don't end up with huge values.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>

Showing 1 changed file with 16 additions and 0 deletions Side-by-side Diff

block/blk-throttle.c
... ... @@ -355,6 +355,12 @@
355 355 tg->slice_end[rw], jiffies);
356 356 }
357 357  
  358 +static inline void throtl_set_slice_end(struct throtl_data *td,
  359 + struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
  360 +{
  361 + tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
  362 +}
  363 +
358 364 static inline void throtl_extend_slice(struct throtl_data *td,
359 365 struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
360 366 {
... ... @@ -390,6 +396,16 @@
390 396 */
391 397 if (throtl_slice_used(td, tg, rw))
392 398 return;
  399 +
  400 + /*
  401 + * A bio has been dispatched. Also adjust slice_end. It might happen
  402 + * that initially cgroup limit was very low resulting in high
  403 + * slice_end, but later limit was bumped up and bio was dispached
  404 + * sooner, then we need to reduce slice_end. A high bogus slice_end
  405 + * is bad because it does not allow new slice to start.
  406 + */
  407 +
  408 + throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice);
393 409  
394 410 time_elapsed = jiffies - tg->slice_start[rw];
395 411