Commit 6a0c0549 authored by Duoming Zhou's avatar Duoming Zhou Committed by Greg Kroah-Hartman

staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback

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: 8fc8598e ("Staging: Added Realtek rtl8192u driver to staging")
Signed-off-by: default avatarDuoming Zhou <duoming@zju.edu.cn>
Link: https://lore.kernel.org/r/20220710103002.63283-1-duoming@zju.edu.cnSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 39c1b1af
...@@ -1013,7 +1013,7 @@ typedef struct r8192_priv { ...@@ -1013,7 +1013,7 @@ typedef struct r8192_priv {
bool bis_any_nonbepkts; bool bis_any_nonbepkts;
bool bcurrent_turbo_EDCA; bool bcurrent_turbo_EDCA;
bool bis_cur_rdlstate; bool bis_cur_rdlstate;
struct timer_list fsync_timer; struct delayed_work fsync_work;
bool bfsync_processing; /* 500ms Fsync timer is active or not */ bool bfsync_processing; /* 500ms Fsync timer is active or not */
u32 rate_record; u32 rate_record;
u32 rateCountDiffRecord; u32 rateCountDiffRecord;
......
...@@ -2578,19 +2578,20 @@ static void dm_init_fsync(struct net_device *dev) ...@@ -2578,19 +2578,20 @@ static void dm_init_fsync(struct net_device *dev)
priv->ieee80211->fsync_seconddiff_ratethreshold = 200; priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
priv->ieee80211->fsync_state = Default_Fsync; priv->ieee80211->fsync_state = Default_Fsync;
priv->framesyncMonitor = 1; /* current default 0xc38 monitor on */ 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) static void dm_deInit_fsync(struct net_device *dev)
{ {
struct r8192_priv *priv = ieee80211_priv(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; struct net_device *dev = priv->ieee80211->dev;
u32 rate_index, rate_count = 0, rate_count_diff = 0; u32 rate_index, rate_count = 0, rate_count_diff = 0;
bool bSwitchFromCountDiff = false; bool bSwitchFromCountDiff = false;
...@@ -2657,17 +2658,16 @@ void dm_fsync_timer_callback(struct timer_list *t) ...@@ -2657,17 +2658,16 @@ void dm_fsync_timer_callback(struct timer_list *t)
} }
} }
if (bDoubleTimeInterval) { if (bDoubleTimeInterval) {
if (timer_pending(&priv->fsync_timer)) cancel_delayed_work_sync(&priv->fsync_work);
del_timer_sync(&priv->fsync_timer); schedule_delayed_work(&priv->fsync_work,
priv->fsync_timer.expires = jiffies + msecs_to_jiffies(priv
msecs_to_jiffies(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval); ->ieee80211->fsync_time_interval *
add_timer(&priv->fsync_timer); priv->ieee80211->fsync_multiple_timeinterval));
} else { } else {
if (timer_pending(&priv->fsync_timer)) cancel_delayed_work_sync(&priv->fsync_work);
del_timer_sync(&priv->fsync_timer); schedule_delayed_work(&priv->fsync_work,
priv->fsync_timer.expires = jiffies + msecs_to_jiffies(priv
msecs_to_jiffies(priv->ieee80211->fsync_time_interval); ->ieee80211->fsync_time_interval));
add_timer(&priv->fsync_timer);
} }
} else { } else {
/* Let Register return to default value; */ /* Let Register return to default value; */
...@@ -2695,7 +2695,7 @@ static void dm_EndSWFsync(struct net_device *dev) ...@@ -2695,7 +2695,7 @@ static void dm_EndSWFsync(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev); struct r8192_priv *priv = ieee80211_priv(dev);
RT_TRACE(COMP_HALDM, "%s\n", __func__); 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; */ /* Let Register return to default value; */
if (priv->bswitch_fsync) { if (priv->bswitch_fsync) {
...@@ -2736,11 +2736,9 @@ static void dm_StartSWFsync(struct net_device *dev) ...@@ -2736,11 +2736,9 @@ static void dm_StartSWFsync(struct net_device *dev)
if (priv->ieee80211->fsync_rate_bitmap & rateBitmap) if (priv->ieee80211->fsync_rate_bitmap & rateBitmap)
priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex]; priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex];
} }
if (timer_pending(&priv->fsync_timer)) cancel_delayed_work_sync(&priv->fsync_work);
del_timer_sync(&priv->fsync_timer); schedule_delayed_work(&priv->fsync_work,
priv->fsync_timer.expires = jiffies + msecs_to_jiffies(priv->ieee80211->fsync_time_interval));
msecs_to_jiffies(priv->ieee80211->fsync_time_interval);
add_timer(&priv->fsync_timer);
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd);
} }
......
...@@ -166,7 +166,7 @@ void dm_force_tx_fw_info(struct net_device *dev, ...@@ -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_init_edca_turbo(struct net_device *dev);
void dm_rf_operation_test_callback(unsigned long data); void dm_rf_operation_test_callback(unsigned long data);
void dm_rf_pathcheck_workitemcallback(struct work_struct *work); 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_cck_txpower_adjust(struct net_device *dev, bool binch14);
void dm_shadow_init(struct net_device *dev); void dm_shadow_init(struct net_device *dev);
void dm_initialize_txpower_tracking(struct net_device *dev); void dm_initialize_txpower_tracking(struct net_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment