Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bb0f109 authored by Duoming Zhou's avatar Duoming Zhou Committed by Greg Kroah-Hartman
Browse files

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



[ 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: 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.cn


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent b5d924cb
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;
+18 −20
Original line number Original line Diff line number Diff line
@@ -2585,19 +2585,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;
@@ -2664,17 +2665,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; */
@@ -2702,7 +2702,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) {
@@ -2744,11 +2744,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);


+1 −1
Original line number Original line Diff line number Diff line
@@ -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);