Search Linux Wireless

Re: [PATCH] mac80211: annotate sleeping driver ops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 2009-11-28 at 22:19 +0200, Kalle Valo wrote:
> To make it easier to notice cases of calling sleeping ops in atomic context,
> annotate driver-ops.h with appropiate might_sleep() calls. At the same time,
> also document in mac80211.h the op functions with missing contexts.
> 
> mac80211 doesn't seem to use get_tx_stats anywhere currently. Just to be on
> the safe side, I documented it to be atomic, but hopefully the op can be
> removed in the future.
> 
> Compile-tested only.

Nice, thanks. Haven't reviewed it in detail, but I'll trust you :)

Acked-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>

> Signed-off-by: Kalle Valo <kalle.valo@xxxxxx>
> ---
>  include/net/mac80211.h    |   41 +++++++++++++++++++++++--------
>  net/mac80211/driver-ops.h |   58 +++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 84 insertions(+), 15 deletions(-)
> 
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 2e484bc..fafc503 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -1342,155 +1342,174 @@ enum ieee80211_ampdu_mlme_action {
>   *	Must be implemented and atomic.
>   *
>   * @start: Called before the first netdevice attached to the hardware
>   *	is enabled. This should turn on the hardware and must turn on
>   *	frame reception (for possibly enabled monitor interfaces.)
>   *	Returns negative error codes, these may be seen in userspace,
>   *	or zero.
>   *	When the device is started it should not have a MAC address
>   *	to avoid acknowledging frames before a non-monitor device
>   *	is added.
> - *	Must be implemented.
> + *	Must be implemented and can sleep.
>   *
>   * @stop: Called after last netdevice attached to the hardware
>   *	is disabled. This should turn off the hardware (at least
>   *	it must turn off frame reception.)
>   *	May be called right after add_interface if that rejects
>   *	an interface. If you added any work onto the mac80211 workqueue
>   *	you should ensure to cancel it on this callback.
> - *	Must be implemented.
> + *	Must be implemented and can sleep.
>   *
>   * @add_interface: Called when a netdevice attached to the hardware is
>   *	enabled. Because it is not called for monitor mode devices, @start
>   *	and @stop must be implemented.
>   *	The driver should perform any initialization it needs before
>   *	the device can be enabled. The initial configuration for the
>   *	interface is given in the conf parameter.
>   *	The callback may refuse to add an interface by returning a
>   *	negative error code (which will be seen in userspace.)
> - *	Must be implemented.
> + *	Must be implemented and can sleep.
>   *
>   * @remove_interface: Notifies a driver that an interface is going down.
>   *	The @stop callback is called after this if it is the last interface
>   *	and no monitor interfaces are present.
>   *	When all interfaces are removed, the MAC address in the hardware
>   *	must be cleared so the device no longer acknowledges packets,
>   *	the mac_addr member of the conf structure is, however, set to the
>   *	MAC address of the device going away.
> - *	Hence, this callback must be implemented.
> + *	Hence, this callback must be implemented. It can sleep.
>   *
>   * @config: Handler for configuration requests. IEEE 802.11 code calls this
>   *	function to change hardware configuration, e.g., channel.
>   *	This function should never fail but returns a negative error code
> - *	if it does.
> + *	if it does. The callback can sleep.
>   *
>   * @bss_info_changed: Handler for configuration requests related to BSS
>   *	parameters that may vary during BSS's lifespan, and may affect low
>   *	level driver (e.g. assoc/disassoc status, erp parameters).
>   *	This function should not be used if no BSS has been set, unless
>   *	for association indication. The @changed parameter indicates which
> - *	of the bss parameters has changed when a call is made.
> + *	of the bss parameters has changed when a call is made. The callback
> + *	can sleep.
>   *
>   * @prepare_multicast: Prepare for multicast filter configuration.
>   *	This callback is optional, and its return value is passed
>   *	to configure_filter(). This callback must be atomic.
>   *
>   * @configure_filter: Configure the device's RX filter.
>   *	See the section "Frame filtering" for more information.
> - *	This callback must be implemented.
> + *	This callback must be implemented and can sleep.
>   *
>   * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
>   * 	must be set or cleared for a given STA. Must be atomic.
>   *
>   * @set_key: See the section "Hardware crypto acceleration"
> - *	This callback can sleep, and is only called between add_interface
> - *	and remove_interface calls, i.e. while the given virtual interface
> + *	This callback is only called between add_interface and
> + *	remove_interface calls, i.e. while the given virtual interface
>   *	is enabled.
>   *	Returns a negative error code if the key can't be added.
> + *	The callback can sleep.
>   *
>   * @update_tkip_key: See the section "Hardware crypto acceleration"
>   * 	This callback will be called in the context of Rx. Called for drivers
>   * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
> + *	The callback can sleep.
>   *
>   * @hw_scan: Ask the hardware to service the scan request, no need to start
>   *	the scan state machine in stack. The scan must honour the channel
>   *	configuration done by the regulatory agent in the wiphy's
>   *	registered bands. The hardware (or the driver) needs to make sure
>   *	that power save is disabled.
>   *	The @req ie/ie_len members are rewritten by mac80211 to contain the
>   *	entire IEs after the SSID, so that drivers need not look at these
>   *	at all but just send them after the SSID -- mac80211 includes the
>   *	(extended) supported rates and HT information (where applicable).
>   *	When the scan finishes, ieee80211_scan_completed() must be called;
>   *	note that it also must be called when the scan cannot finish due to
>   *	any error unless this callback returned a negative error code.
> + *	The callback can sleep.
>   *
>   * @sw_scan_start: Notifier function that is called just before a software scan
>   *	is started. Can be NULL, if the driver doesn't need this notification.
> + *	The callback can sleep.
>   *
> - * @sw_scan_complete: Notifier function that is called just after a software scan
> - *	finished. Can be NULL, if the driver doesn't need this notification.
> + * @sw_scan_complete: Notifier function that is called just after a
> + *	software scan finished. Can be NULL, if the driver doesn't need
> + *	this notification.
> + *	The callback can sleep.
>   *
>   * @get_stats: Return low-level statistics.
>   * 	Returns zero if statistics are available.
> + *	The callback can sleep.
>   *
>   * @get_tkip_seq: If your device implements TKIP encryption in hardware this
>   *	callback should be provided to read the TKIP transmit IVs (both IV32
>   *	and IV16) for the given key from hardware.
> + *	The callback must be atomic.
>   *
>   * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
> + *	The callback can sleep.
>   *
>   * @sta_notify: Notifies low level driver about addition, removal or power
>   *	state transition of an associated station, AP,  IBSS/WDS/mesh peer etc.
>   *	Must be atomic.
>   *
>   * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
>   *	bursting) for a hardware TX queue.
>   *	Returns a negative error code on failure.
> + *	The callback can sleep.
>   *
>   * @get_tx_stats: Get statistics of the current TX queue status. This is used
>   *	to get number of currently queued packets (queue length), maximum queue
>   *	size (limit), and total number of packets sent using each TX queue
>   *	(count). The 'stats' pointer points to an array that has hw->queues
>   *	items.
> + *	The callback must be atomic.
>   *
>   * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
>   *	this is only used for IBSS mode BSSID merging and debugging. Is not a
>   *	required function.
> + *	The callback can sleep.
>   *
>   * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
>   *      Currently, this is only used for IBSS mode debugging. Is not a
>   *	required function.
> + *	The callback can sleep.
>   *
>   * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
>   *	with other STAs in the IBSS. This is only used in IBSS mode. This
>   *	function is optional if the firmware/hardware takes full care of
>   *	TSF synchronization.
> + *	The callback can sleep.
>   *
>   * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
>   *	This is needed only for IBSS mode and the result of this function is
>   *	used to determine whether to reply to Probe Requests.
>   *	Returns non-zero if this device sent the last beacon.
> + *	The callback can sleep.
>   *
>   * @ampdu_action: Perform a certain A-MPDU action
>   * 	The RA/TID combination determines the destination and TID we want
>   * 	the ampdu action to be performed for. The action is defined through
>   * 	ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
>   * 	is the first frame we expect to perform the action on. Notice
>   * 	that TX/RX_STOP can pass NULL for this parameter.
>   *	Returns a negative error code on failure.
> + *	The callback must be atomic.
>   *
>   * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
>   *	need to set wiphy->rfkill_poll to %true before registration,
>   *	and need to call wiphy_rfkill_set_hw_state() in the callback.
> + *	The callback can sleep.
>   *
>   * @testmode_cmd: Implement a cfg80211 test mode command.
> + *	The callback can sleep.
>   */
>  struct ieee80211_ops {
>  	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
>  	int (*start)(struct ieee80211_hw *hw);
>  	void (*stop)(struct ieee80211_hw *hw);
>  	int (*add_interface)(struct ieee80211_hw *hw,
>  			     struct ieee80211_if_init_conf *conf);
>  	void (*remove_interface)(struct ieee80211_hw *hw,
>  				 struct ieee80211_if_init_conf *conf);
>  	int (*config)(struct ieee80211_hw *hw, u32 changed);
> diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
> index 921dd9c..0fdca07 100644
> --- a/net/mac80211/driver-ops.h
> +++ b/net/mac80211/driver-ops.h
> @@ -7,68 +7,84 @@
>  
>  static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
>  {
>  	return local->ops->tx(&local->hw, skb);
>  }
>  
>  static inline int drv_start(struct ieee80211_local *local)
>  {
>  	int ret;
>  
> +	might_sleep();
> +
>  	local->started = true;
>  	smp_mb();
>  	ret = local->ops->start(&local->hw);
>  	trace_drv_start(local, ret);
>  	return ret;
>  }
>  
>  static inline void drv_stop(struct ieee80211_local *local)
>  {
> +	might_sleep();
> +
>  	local->ops->stop(&local->hw);
>  	trace_drv_stop(local);
>  
>  	/* sync away all work on the tasklet before clearing started */
>  	tasklet_disable(&local->tasklet);
>  	tasklet_enable(&local->tasklet);
>  
>  	barrier();
>  
>  	local->started = false;
>  }
>  
>  static inline int drv_add_interface(struct ieee80211_local *local,
>  				    struct ieee80211_if_init_conf *conf)
>  {
> -	int ret = local->ops->add_interface(&local->hw, conf);
> +	int ret;
> +
> +	might_sleep();
> +
> +	ret = local->ops->add_interface(&local->hw, conf);
>  	trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
>  	return ret;
>  }
>  
>  static inline void drv_remove_interface(struct ieee80211_local *local,
>  					struct ieee80211_if_init_conf *conf)
>  {
> +	might_sleep();
> +
>  	local->ops->remove_interface(&local->hw, conf);
>  	trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
>  }
>  
>  static inline int drv_config(struct ieee80211_local *local, u32 changed)
>  {
> -	int ret = local->ops->config(&local->hw, changed);
> +	int ret;
> +
> +	might_sleep();
> +
> +	ret = local->ops->config(&local->hw, changed);
>  	trace_drv_config(local, changed, ret);
>  	return ret;
>  }
>  
>  static inline void drv_bss_info_changed(struct ieee80211_local *local,
>  					struct ieee80211_vif *vif,
>  					struct ieee80211_bss_conf *info,
>  					u32 changed)
>  {
> +	might_sleep();
> +
>  	if (local->ops->bss_info_changed)
>  		local->ops->bss_info_changed(&local->hw, vif, info, changed);
>  	trace_drv_bss_info_changed(local, vif, info, changed);
>  }
>  
>  static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
>  					int mc_count,
>  					struct dev_addr_list *mc_list)
>  {
>  	u64 ret = 0;
> @@ -103,142 +119,174 @@ static inline int drv_set_tim(struct ieee80211_local *local,
>  		ret = local->ops->set_tim(&local->hw, sta, set);
>  	trace_drv_set_tim(local, sta, set, ret);
>  	return ret;
>  }
>  
>  static inline int drv_set_key(struct ieee80211_local *local,
>  			      enum set_key_cmd cmd, struct ieee80211_vif *vif,
>  			      struct ieee80211_sta *sta,
>  			      struct ieee80211_key_conf *key)
>  {
> -	int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
> +	int ret;
> +
> +	might_sleep();
> +
> +	ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
>  	trace_drv_set_key(local, cmd, vif, sta, key, ret);
>  	return ret;
>  }
>  
>  static inline void drv_update_tkip_key(struct ieee80211_local *local,
>  				       struct ieee80211_key_conf *conf,
>  				       const u8 *address, u32 iv32,
>  				       u16 *phase1key)
>  {
> +	might_sleep();
> +
>  	if (local->ops->update_tkip_key)
>  		local->ops->update_tkip_key(&local->hw, conf, address,
>  					    iv32, phase1key);
>  	trace_drv_update_tkip_key(local, conf, address, iv32);
>  }
>  
>  static inline int drv_hw_scan(struct ieee80211_local *local,
>  			      struct cfg80211_scan_request *req)
>  {
> -	int ret = local->ops->hw_scan(&local->hw, req);
> +	int ret;
> +
> +	might_sleep();
> +
> +	ret = local->ops->hw_scan(&local->hw, req);
>  	trace_drv_hw_scan(local, req, ret);
>  	return ret;
>  }
>  
>  static inline void drv_sw_scan_start(struct ieee80211_local *local)
>  {
> +	might_sleep();
> +
>  	if (local->ops->sw_scan_start)
>  		local->ops->sw_scan_start(&local->hw);
>  	trace_drv_sw_scan_start(local);
>  }
>  
>  static inline void drv_sw_scan_complete(struct ieee80211_local *local)
>  {
> +	might_sleep();
> +
>  	if (local->ops->sw_scan_complete)
>  		local->ops->sw_scan_complete(&local->hw);
>  	trace_drv_sw_scan_complete(local);
>  }
>  
>  static inline int drv_get_stats(struct ieee80211_local *local,
>  				struct ieee80211_low_level_stats *stats)
>  {
>  	int ret = -EOPNOTSUPP;
>  
> +	might_sleep();
> +
>  	if (local->ops->get_stats)
>  		ret = local->ops->get_stats(&local->hw, stats);
>  	trace_drv_get_stats(local, stats, ret);
>  
>  	return ret;
>  }
>  
>  static inline void drv_get_tkip_seq(struct ieee80211_local *local,
>  				    u8 hw_key_idx, u32 *iv32, u16 *iv16)
>  {
>  	if (local->ops->get_tkip_seq)
>  		local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
>  	trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
>  }
>  
>  static inline int drv_set_rts_threshold(struct ieee80211_local *local,
>  					u32 value)
>  {
>  	int ret = 0;
> +
> +	might_sleep();
> +
>  	if (local->ops->set_rts_threshold)
>  		ret = local->ops->set_rts_threshold(&local->hw, value);
>  	trace_drv_set_rts_threshold(local, value, ret);
>  	return ret;
>  }
>  
>  static inline void drv_sta_notify(struct ieee80211_local *local,
>  				  struct ieee80211_vif *vif,
>  				  enum sta_notify_cmd cmd,
>  				  struct ieee80211_sta *sta)
>  {
>  	if (local->ops->sta_notify)
>  		local->ops->sta_notify(&local->hw, vif, cmd, sta);
>  	trace_drv_sta_notify(local, vif, cmd, sta);
>  }
>  
>  static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
>  			      const struct ieee80211_tx_queue_params *params)
>  {
>  	int ret = -EOPNOTSUPP;
> +
> +	might_sleep();
> +
>  	if (local->ops->conf_tx)
>  		ret = local->ops->conf_tx(&local->hw, queue, params);
>  	trace_drv_conf_tx(local, queue, params, ret);
>  	return ret;
>  }
>  
>  static inline int drv_get_tx_stats(struct ieee80211_local *local,
>  				   struct ieee80211_tx_queue_stats *stats)
>  {
>  	int ret = local->ops->get_tx_stats(&local->hw, stats);
>  	trace_drv_get_tx_stats(local, stats, ret);
>  	return ret;
>  }
>  
>  static inline u64 drv_get_tsf(struct ieee80211_local *local)
>  {
>  	u64 ret = -1ULL;
> +
> +	might_sleep();
> +
>  	if (local->ops->get_tsf)
>  		ret = local->ops->get_tsf(&local->hw);
>  	trace_drv_get_tsf(local, ret);
>  	return ret;
>  }
>  
>  static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
>  {
> +	might_sleep();
> +
>  	if (local->ops->set_tsf)
>  		local->ops->set_tsf(&local->hw, tsf);
>  	trace_drv_set_tsf(local, tsf);
>  }
>  
>  static inline void drv_reset_tsf(struct ieee80211_local *local)
>  {
> +	might_sleep();
> +
>  	if (local->ops->reset_tsf)
>  		local->ops->reset_tsf(&local->hw);
>  	trace_drv_reset_tsf(local);
>  }
>  
>  static inline int drv_tx_last_beacon(struct ieee80211_local *local)
>  {
>  	int ret = 1;
> +
> +	might_sleep();
> +
>  	if (local->ops->tx_last_beacon)
>  		ret = local->ops->tx_last_beacon(&local->hw);
>  	trace_drv_tx_last_beacon(local, ret);
>  	return ret;
>  }
>  
>  static inline int drv_ampdu_action(struct ieee80211_local *local,
>  				   struct ieee80211_vif *vif,
>  				   enum ieee80211_ampdu_mlme_action action,
>  				   struct ieee80211_sta *sta, u16 tid,
> @@ -248,14 +296,16 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
>  	if (local->ops->ampdu_action)
>  		ret = local->ops->ampdu_action(&local->hw, vif, action,
>  					       sta, tid, ssn);
>  	trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
>  	return ret;
>  }
>  
> 
>  static inline void drv_rfkill_poll(struct ieee80211_local *local)
>  {
> +	might_sleep();
> +
>  	if (local->ops->rfkill_poll)
>  		local->ops->rfkill_poll(&local->hw);
>  }
>  #endif /* __MAC80211_DRIVER_OPS */

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux