return key;
 }
 
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
+static void __ieee80211_key_destroy(struct ieee80211_key *key,
+                                   bool delay_tailroom)
 {
        if (!key)
                return;
        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
        if (key->local) {
+               struct ieee80211_sub_if_data *sdata = key->sdata;
+
                ieee80211_debugfs_key_remove(key);
-               key->sdata->crypto_tx_tailroom_needed_cnt--;
+
+               if (delay_tailroom) {
+                       /* see ieee80211_delayed_tailroom_dec */
+                       sdata->crypto_tx_tailroom_pending_dec++;
+                       schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
+                                             HZ/2);
+               } else {
+                       sdata->crypto_tx_tailroom_needed_cnt--;
+               }
        }
 
        kfree(key);
        increment_tailroom_need_count(sdata);
 
        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
-       __ieee80211_key_destroy(old_key);
+       __ieee80211_key_destroy(old_key, true);
 
        ieee80211_debugfs_key_add(key);
 
        return ret;
 }
 
-void __ieee80211_key_free(struct ieee80211_key *key)
+void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
 {
        if (!key)
                return;
                __ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
-       __ieee80211_key_destroy(key);
+       __ieee80211_key_destroy(key, delay_tailroom);
 }
 
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key)
 {
        mutex_lock(&local->key_mtx);
-       __ieee80211_key_free(key);
+       __ieee80211_key_free(key, true);
        mutex_unlock(&local->key_mtx);
 }
 
 {
        struct ieee80211_key *key, *tmp;
 
+       cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
+
        mutex_lock(&sdata->local->key_mtx);
 
+       sdata->crypto_tx_tailroom_needed_cnt -=
+               sdata->crypto_tx_tailroom_pending_dec;
+       sdata->crypto_tx_tailroom_pending_dec = 0;
+
        ieee80211_debugfs_key_remove_mgmt_default(sdata);
 
        list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
-               __ieee80211_key_free(key);
+               __ieee80211_key_free(key, false);
 
        ieee80211_debugfs_key_update_default(sdata);
 
+       WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
+                    sdata->crypto_tx_tailroom_pending_dec);
+
        mutex_unlock(&sdata->local->key_mtx);
 }
 
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = container_of(wk, struct ieee80211_sub_if_data,
+                            dec_tailroom_needed_wk.work);
+
+       /*
+        * The reason for the delayed tailroom needed decrementing is to
+        * make roaming faster: during roaming, all keys are first deleted
+        * and then new keys are installed. The first new key causes the
+        * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
+        * the cost of synchronize_net() (which can be slow). Avoid this
+        * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
+        * key removal for a while, so if we roam the value is larger than
+        * zero and no 0->1 transition happens.
+        *
+        * The cost is that if the AP switching was from an AP with keys
+        * to one without, we still allocate tailroom while it would no
+        * longer be needed. However, in the typical (fast) roaming case
+        * within an ESS this usually won't happen.
+        */
+
+       mutex_lock(&sdata->local->key_mtx);
+       sdata->crypto_tx_tailroom_needed_cnt -=
+               sdata->crypto_tx_tailroom_pending_dec;
+       sdata->crypto_tx_tailroom_pending_dec = 0;
+       mutex_unlock(&sdata->local->key_mtx);
+}
 
 void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
                                const u8 *replay_ctr, gfp_t gfp)
 
 int __must_check ieee80211_key_link(struct ieee80211_key *key,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct sta_info *sta);
-void __ieee80211_key_free(struct ieee80211_key *key);
+void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
 #define key_mtx_dereference(local, ref) \
        rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
 
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
+
 #endif /* IEEE80211_KEY_H */