lkml.org 
[lkml]   [2018]   [Jul]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.17 022/101] net/mlx5: Fix command interface race in polling mode
    Date
    4.17-stable review patch.  If anyone has any objections, please let me know.

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

    From: Alex Vesker <valex@mellanox.com>

    [ Upstream commit d412c31dae053bf30a1bc15582a9990df297a660 ]

    The command interface can work in two modes: Events and Polling.
    In the general case, each time we invoke a command, a work is
    queued to handle it.

    When working in events, the interrupt handler completes the
    command execution. On the other hand, when working in polling
    mode, the work itself completes it.

    Due to a bug in the work handler, a command could have been
    completed by the interrupt handler, while the work handler
    hasn't finished yet, causing the it to complete once again
    if the command interface mode was changed from Events to
    polling after the interrupt handler was called.

    mlx5_unload_one()
    mlx5_stop_eqs()
    // Destroy the EQ before cmd EQ
    ...cmd_work_handler()
    write_doorbell()
    --> EVENT_TYPE_CMD
    mlx5_cmd_comp_handler() // First free
    free_ent(cmd, ent->idx)
    complete(&ent->done)

    <-- mlx5_stop_eqs //cmd was complete
    // move to polling before destroying the last cmd EQ
    mlx5_cmd_use_polling()
    cmd->mode = POLL;

    --> cmd_work_handler (continues)
    if (cmd->mode == POLL)
    mlx5_cmd_comp_handler() // Double free

    The solution is to store the cmd->mode before writing the doorbell.

    Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters")
    Signed-off-by: Alex Vesker <valex@mellanox.com>
    Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +++-
    1 file changed, 3 insertions(+), 1 deletion(-)

    --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
    +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
    @@ -803,6 +803,7 @@ static void cmd_work_handler(struct work
    unsigned long flags;
    bool poll_cmd = ent->polling;
    int alloc_ret;
    + int cmd_mode;

    sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
    down(sem);
    @@ -849,6 +850,7 @@ static void cmd_work_handler(struct work
    set_signature(ent, !cmd->checksum_disabled);
    dump_command(dev, ent, 1);
    ent->ts1 = ktime_get_ns();
    + cmd_mode = cmd->mode;

    if (ent->callback)
    schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
    @@ -873,7 +875,7 @@ static void cmd_work_handler(struct work
    iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
    mmiowb();
    /* if not in polling don't use ent after this point */
    - if (cmd->mode == CMD_MODE_POLLING || poll_cmd) {
    + if (cmd_mode == CMD_MODE_POLLING || poll_cmd) {
    poll_timeout(ent);
    /* make sure we read the descriptor after ownership is SW */
    rmb();

    \
     
     \ /
      Last update: 2018-07-20 14:52    [W:4.051 / U:0.548 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site