lkml.org 
[lkml]   [2022]   [Aug]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 312/545] staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback
    Date
    From: Duoming Zhou <duoming@zju.edu.cn>

    [ Upstream commit 6a0c054930d554ad8f8044ef1fc856d9da391c81 ]

    There are sleep in atomic context bugs when dm_fsync_timer_callback is
    executing. The root cause is that the memory allocation functions with
    GFP_KERNEL or GFP_NOIO parameters are called in dm_fsync_timer_callback
    which is a timer handler. The call paths that could trigger bugs are
    shown below:

    (interrupt context)
    dm_fsync_timer_callback
    write_nic_byte
    kzalloc(sizeof(data), GFP_KERNEL); //may sleep
    usb_control_msg
    kmalloc(.., GFP_NOIO); //may sleep
    write_nic_dword
    kzalloc(sizeof(data), GFP_KERNEL); //may sleep
    usb_control_msg
    kmalloc(.., GFP_NOIO); //may sleep

    This patch uses delayed work to replace timer and moves the operations
    that may sleep into the delayed work in order to mitigate bugs.

    Fixes: 8fc8598e61f6 ("Staging: Added Realtek rtl8192u driver to staging")
    Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
    Link: https://lore.kernel.org/r/20220710103002.63283-1-duoming@zju.edu.cn
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/staging/rtl8192u/r8192U.h | 2 +-
    drivers/staging/rtl8192u/r8192U_dm.c | 38 +++++++++++++---------------
    drivers/staging/rtl8192u/r8192U_dm.h | 2 +-
    3 files changed, 20 insertions(+), 22 deletions(-)

    diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
    index ec33fb9122e9..57badc1e91e3 100644
    --- a/drivers/staging/rtl8192u/r8192U.h
    +++ b/drivers/staging/rtl8192u/r8192U.h
    @@ -1013,7 +1013,7 @@ typedef struct r8192_priv {
    bool bis_any_nonbepkts;
    bool bcurrent_turbo_EDCA;
    bool bis_cur_rdlstate;
    - struct timer_list fsync_timer;
    + struct delayed_work fsync_work;
    bool bfsync_processing; /* 500ms Fsync timer is active or not */
    u32 rate_record;
    u32 rateCountDiffRecord;
    diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
    index bac402b40121..6aa424a31569 100644
    --- a/drivers/staging/rtl8192u/r8192U_dm.c
    +++ b/drivers/staging/rtl8192u/r8192U_dm.c
    @@ -2578,19 +2578,20 @@ static void dm_init_fsync(struct net_device *dev)
    priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
    priv->ieee80211->fsync_state = Default_Fsync;
    priv->framesyncMonitor = 1; /* current default 0xc38 monitor on */
    - timer_setup(&priv->fsync_timer, dm_fsync_timer_callback, 0);
    + INIT_DELAYED_WORK(&priv->fsync_work, dm_fsync_work_callback);
    }

    static void dm_deInit_fsync(struct net_device *dev)
    {
    struct r8192_priv *priv = ieee80211_priv(dev);

    - del_timer_sync(&priv->fsync_timer);
    + cancel_delayed_work_sync(&priv->fsync_work);
    }

    -void dm_fsync_timer_callback(struct timer_list *t)
    +void dm_fsync_work_callback(struct work_struct *work)
    {
    - struct r8192_priv *priv = from_timer(priv, t, fsync_timer);
    + struct r8192_priv *priv =
    + container_of(work, struct r8192_priv, fsync_work.work);
    struct net_device *dev = priv->ieee80211->dev;
    u32 rate_index, rate_count = 0, rate_count_diff = 0;
    bool bSwitchFromCountDiff = false;
    @@ -2657,17 +2658,16 @@ void dm_fsync_timer_callback(struct timer_list *t)
    }
    }
    if (bDoubleTimeInterval) {
    - if (timer_pending(&priv->fsync_timer))
    - del_timer_sync(&priv->fsync_timer);
    - priv->fsync_timer.expires = jiffies +
    - msecs_to_jiffies(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval);
    - add_timer(&priv->fsync_timer);
    + cancel_delayed_work_sync(&priv->fsync_work);
    + schedule_delayed_work(&priv->fsync_work,
    + msecs_to_jiffies(priv
    + ->ieee80211->fsync_time_interval *
    + priv->ieee80211->fsync_multiple_timeinterval));
    } else {
    - if (timer_pending(&priv->fsync_timer))
    - del_timer_sync(&priv->fsync_timer);
    - priv->fsync_timer.expires = jiffies +
    - msecs_to_jiffies(priv->ieee80211->fsync_time_interval);
    - add_timer(&priv->fsync_timer);
    + cancel_delayed_work_sync(&priv->fsync_work);
    + schedule_delayed_work(&priv->fsync_work,
    + msecs_to_jiffies(priv
    + ->ieee80211->fsync_time_interval));
    }
    } else {
    /* Let Register return to default value; */
    @@ -2695,7 +2695,7 @@ static void dm_EndSWFsync(struct net_device *dev)
    struct r8192_priv *priv = ieee80211_priv(dev);

    RT_TRACE(COMP_HALDM, "%s\n", __func__);
    - del_timer_sync(&(priv->fsync_timer));
    + cancel_delayed_work_sync(&priv->fsync_work);

    /* Let Register return to default value; */
    if (priv->bswitch_fsync) {
    @@ -2736,11 +2736,9 @@ static void dm_StartSWFsync(struct net_device *dev)
    if (priv->ieee80211->fsync_rate_bitmap & rateBitmap)
    priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex];
    }
    - if (timer_pending(&priv->fsync_timer))
    - del_timer_sync(&priv->fsync_timer);
    - priv->fsync_timer.expires = jiffies +
    - msecs_to_jiffies(priv->ieee80211->fsync_time_interval);
    - add_timer(&priv->fsync_timer);
    + cancel_delayed_work_sync(&priv->fsync_work);
    + schedule_delayed_work(&priv->fsync_work,
    + msecs_to_jiffies(priv->ieee80211->fsync_time_interval));

    write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd);
    }
    diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h
    index 0b2a1c688597..2159018b4e38 100644
    --- a/drivers/staging/rtl8192u/r8192U_dm.h
    +++ b/drivers/staging/rtl8192u/r8192U_dm.h
    @@ -166,7 +166,7 @@ void dm_force_tx_fw_info(struct net_device *dev,
    void dm_init_edca_turbo(struct net_device *dev);
    void dm_rf_operation_test_callback(unsigned long data);
    void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
    -void dm_fsync_timer_callback(struct timer_list *t);
    +void dm_fsync_work_callback(struct work_struct *work);
    void dm_cck_txpower_adjust(struct net_device *dev, bool binch14);
    void dm_shadow_init(struct net_device *dev);
    void dm_initialize_txpower_tracking(struct net_device *dev);
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-19 18:27    [W:4.085 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site