lkml.org 
[lkml]   [2014]   [Mar]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 47/85] firewire: dont use PREPARE_DELAYED_WORK
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

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

    From: Tejun Heo <tj@kernel.org>

    commit 70044d71d31d6973665ced5be04ef39ac1c09a48 upstream.

    PREPARE_[DELAYED_]WORK() are being phased out. They have few users
    and a nasty surprise in terms of reentrancy guarantee as workqueue
    considers work items to be different if they don't have the same work
    function.

    firewire core-device and sbp2 have been been multiplexing work items
    with multiple work functions. Introduce fw_device_workfn() and
    sbp2_lu_workfn() which invoke fw_device->workfn and
    sbp2_logical_unit->workfn respectively and always use the two
    functions as the work functions and update the users to set the
    ->workfn fields instead of overriding work functions using
    PREPARE_DELAYED_WORK().

    This fixes a variety of possible regressions since a2c1c57be8d9
    "workqueue: consider work function when searching for busy work items"
    due to which fw_workqueue lost its required non-reentrancy property.

    Signed-off-by: Tejun Heo <tj@kernel.org>
    Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
    Cc: linux1394-devel@lists.sourceforge.net
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/firewire/core-device.c | 22 +++++++++++++++-------
    drivers/firewire/sbp2.c | 17 +++++++++++++----
    include/linux/firewire.h | 1 +
    3 files changed, 29 insertions(+), 11 deletions(-)

    --- a/drivers/firewire/core-device.c
    +++ b/drivers/firewire/core-device.c
    @@ -895,7 +895,7 @@ static int lookup_existing_device(struct
    old->config_rom_retries = 0;
    fw_notice(card, "rediscovered device %s\n", dev_name(dev));

    - PREPARE_DELAYED_WORK(&old->work, fw_device_update);
    + old->workfn = fw_device_update;
    fw_schedule_device_work(old, 0);

    if (current_node == card->root_node)
    @@ -1054,7 +1054,7 @@ static void fw_device_init(struct work_s
    if (atomic_cmpxchg(&device->state,
    FW_DEVICE_INITIALIZING,
    FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
    - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
    + device->workfn = fw_device_shutdown;
    fw_schedule_device_work(device, SHUTDOWN_DELAY);
    } else {
    fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
    @@ -1175,13 +1175,20 @@ static void fw_device_refresh(struct wor
    dev_name(&device->device), fw_rcode_string(ret));
    gone:
    atomic_set(&device->state, FW_DEVICE_GONE);
    - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
    + device->workfn = fw_device_shutdown;
    fw_schedule_device_work(device, SHUTDOWN_DELAY);
    out:
    if (node_id == card->root_node->node_id)
    fw_schedule_bm_work(card, 0);
    }

    +static void fw_device_workfn(struct work_struct *work)
    +{
    + struct fw_device *device = container_of(to_delayed_work(work),
    + struct fw_device, work);
    + device->workfn(work);
    +}
    +
    void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
    {
    struct fw_device *device;
    @@ -1231,7 +1238,8 @@ void fw_node_event(struct fw_card *card,
    * power-up after getting plugged in. We schedule the
    * first config rom scan half a second after bus reset.
    */
    - INIT_DELAYED_WORK(&device->work, fw_device_init);
    + device->workfn = fw_device_init;
    + INIT_DELAYED_WORK(&device->work, fw_device_workfn);
    fw_schedule_device_work(device, INITIAL_DELAY);
    break;

    @@ -1247,7 +1255,7 @@ void fw_node_event(struct fw_card *card,
    if (atomic_cmpxchg(&device->state,
    FW_DEVICE_RUNNING,
    FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
    - PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
    + device->workfn = fw_device_refresh;
    fw_schedule_device_work(device,
    device->is_local ? 0 : INITIAL_DELAY);
    }
    @@ -1262,7 +1270,7 @@ void fw_node_event(struct fw_card *card,
    smp_wmb(); /* update node_id before generation */
    device->generation = card->generation;
    if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
    - PREPARE_DELAYED_WORK(&device->work, fw_device_update);
    + device->workfn = fw_device_update;
    fw_schedule_device_work(device, 0);
    }
    break;
    @@ -1287,7 +1295,7 @@ void fw_node_event(struct fw_card *card,
    device = node->data;
    if (atomic_xchg(&device->state,
    FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
    - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
    + device->workfn = fw_device_shutdown;
    fw_schedule_device_work(device,
    list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
    }
    --- a/drivers/firewire/sbp2.c
    +++ b/drivers/firewire/sbp2.c
    @@ -146,6 +146,7 @@ struct sbp2_logical_unit {
    */
    int generation;
    int retries;
    + work_func_t workfn;
    struct delayed_work work;
    bool has_sdev;
    bool blocked;
    @@ -864,7 +865,7 @@ static void sbp2_login(struct work_struc
    /* set appropriate retry limit(s) in BUSY_TIMEOUT register */
    sbp2_set_busy_timeout(lu);

    - PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
    + lu->workfn = sbp2_reconnect;
    sbp2_agent_reset(lu);

    /* This was a re-login. */
    @@ -918,7 +919,7 @@ static void sbp2_login(struct work_struc
    * If a bus reset happened, sbp2_update will have requeued
    * lu->work already. Reset the work from reconnect to login.
    */
    - PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
    + lu->workfn = sbp2_login;
    }

    static void sbp2_reconnect(struct work_struct *work)
    @@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_s
    lu->retries++ >= 5) {
    dev_err(tgt_dev(tgt), "failed to reconnect\n");
    lu->retries = 0;
    - PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
    + lu->workfn = sbp2_login;
    }
    sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));

    @@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_s
    sbp2_conditionally_unblock(lu);
    }

    +static void sbp2_lu_workfn(struct work_struct *work)
    +{
    + struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
    + struct sbp2_logical_unit, work);
    + lu->workfn(work);
    +}
    +
    static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
    {
    struct sbp2_logical_unit *lu;
    @@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct
    lu->blocked = false;
    ++tgt->dont_block;
    INIT_LIST_HEAD(&lu->orb_list);
    - INIT_DELAYED_WORK(&lu->work, sbp2_login);
    + lu->workfn = sbp2_login;
    + INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);

    list_add_tail(&lu->link, &tgt->lu_list);
    return 0;
    --- a/include/linux/firewire.h
    +++ b/include/linux/firewire.h
    @@ -200,6 +200,7 @@ struct fw_device {
    unsigned irmc:1;
    unsigned bc_implemented:2;

    + work_func_t workfn;
    struct delayed_work work;
    struct fw_attribute_group attribute_group;
    };



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