lkml.org 
[lkml]   [2015]   [Mar]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.19 107/175] cfq-iosched: fix incorrect filing of rt async cfqq
    Date
    3.19-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jeff Moyer <jmoyer@redhat.com>

    commit c6ce194325cef342313e3d27620411ce90a89c50 upstream.

    Hi,

    If you can manage to submit an async write as the first async I/O from
    the context of a process with realtime scheduling priority, then a
    cfq_queue is allocated, but filed into the wrong async_cfqq bucket. It
    ends up in the best effort array, but actually has realtime I/O
    scheduling priority set in cfqq->ioprio.

    The reason is that cfq_get_queue assumes the default scheduling class and
    priority when there is no information present (i.e. when the async cfqq
    is created):

    static struct cfq_queue *
    cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic,
    struct bio *bio, gfp_t gfp_mask)
    {
    const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio);
    const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio);

    cic->ioprio starts out as 0, which is "invalid". So, class of 0
    (IOPRIO_CLASS_NONE) is passed to cfq_async_queue_prio like so:

    async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);

    static struct cfq_queue **
    cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
    {
    switch (ioprio_class) {
    case IOPRIO_CLASS_RT:
    return &cfqd->async_cfqq[0][ioprio];
    case IOPRIO_CLASS_NONE:
    ioprio = IOPRIO_NORM;
    /* fall through */
    case IOPRIO_CLASS_BE:
    return &cfqd->async_cfqq[1][ioprio];
    case IOPRIO_CLASS_IDLE:
    return &cfqd->async_idle_cfqq;
    default:
    BUG();
    }
    }

    Here, instead of returning a class mapped from the process' scheduling
    priority, we get back the bucket associated with IOPRIO_CLASS_BE.

    Now, there is no queue allocated there yet, so we create it:

    cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask);

    That function ends up doing this:

    cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync);
    cfq_init_prio_data(cfqq, cic);

    cfq_init_cfqq marks the priority as having changed. Then, cfq_init_prio
    data does this:

    ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio);
    switch (ioprio_class) {
    default:
    printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
    case IOPRIO_CLASS_NONE:
    /*
    * no prio set, inherit CPU scheduling settings
    */
    cfqq->ioprio = task_nice_ioprio(tsk);
    cfqq->ioprio_class = task_nice_ioclass(tsk);
    break;

    So we basically have two code paths that treat IOPRIO_CLASS_NONE
    differently, which results in an RT async cfqq filed into a best effort
    bucket.

    Attached is a patch which fixes the problem. I'm not sure how to make
    it cleaner. Suggestions would be welcome.

    Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
    Tested-by: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
    Signed-off-by: Jens Axboe <axboe@fb.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    block/cfq-iosched.c | 9 +++++++--
    1 file changed, 7 insertions(+), 2 deletions(-)

    --- a/block/cfq-iosched.c
    +++ b/block/cfq-iosched.c
    @@ -3661,12 +3661,17 @@ static struct cfq_queue *
    cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic,
    struct bio *bio, gfp_t gfp_mask)
    {
    - const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio);
    - const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio);
    + int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio);
    + int ioprio = IOPRIO_PRIO_DATA(cic->ioprio);
    struct cfq_queue **async_cfqq = NULL;
    struct cfq_queue *cfqq = NULL;

    if (!is_sync) {
    + if (!ioprio_valid(cic->ioprio)) {
    + struct task_struct *tsk = current;
    + ioprio = task_nice_ioprio(tsk);
    + ioprio_class = task_nice_ioclass(tsk);
    + }
    async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
    cfqq = *async_cfqq;
    }



    \
     
     \ /
      Last update: 2015-03-04 08:21    [W:7.980 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site