mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
iwlwifi: fix skb truesize underestimation
By default, iwlwifi uses order-1 pages (8 KB) to store incoming frames, but doesnt say so in skb->truesize. This makes very possible to exhaust kernel memory since these skb evade normal socket memory accounting. As struct ieee80211_hdr is going to be pulled before calling IP stack, there is no need to use dev_alloc_skb() to reserve NET_SKB_PAD bytes. alloc_skb() is ok in this driver, allowing more tailroom. Pull beginning of frame in skb header, in the hope we can reuse order-1 pages in the driver immediately for small frames and reduce their truesize to the minimum (linear skbs) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Wey-Yi Guy <wey-yi.w.guy@intel.com> Cc: "John W. Linville" <linville@tuxdriver.com> Cc: Neal Cardwell <ncardwell@google.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
9d1ceac5c6
commit
ed90542b0c
3 changed files with 17 additions and 8 deletions
|
@ -773,8 +773,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
struct sk_buff *skb;
|
||||
__le16 fc = hdr->frame_control;
|
||||
struct iwl_rxon_context *ctx;
|
||||
struct page *p;
|
||||
int offset;
|
||||
unsigned int hdrlen, fraglen;
|
||||
|
||||
/* We only process data packets if the interface is open */
|
||||
if (unlikely(!priv->is_open)) {
|
||||
|
@ -788,16 +787,24 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
|
||||
return;
|
||||
|
||||
skb = dev_alloc_skb(128);
|
||||
/* Dont use dev_alloc_skb(), we'll have enough headroom once
|
||||
* ieee80211_hdr pulled.
|
||||
*/
|
||||
skb = alloc_skb(128, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
IWL_ERR(priv, "dev_alloc_skb failed\n");
|
||||
IWL_ERR(priv, "alloc_skb failed\n");
|
||||
return;
|
||||
}
|
||||
hdrlen = min_t(unsigned int, len, skb_tailroom(skb));
|
||||
memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
|
||||
fraglen = len - hdrlen;
|
||||
|
||||
offset = (void *)hdr - rxb_addr(rxb);
|
||||
p = rxb_steal_page(rxb);
|
||||
skb_add_rx_frag(skb, 0, p, offset, len, len);
|
||||
if (fraglen) {
|
||||
int offset = (void *)hdr + hdrlen - rxb_addr(rxb);
|
||||
|
||||
skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
|
||||
fraglen, rxb->truesize);
|
||||
}
|
||||
iwl_update_stats(priv, false, fc, len);
|
||||
|
||||
/*
|
||||
|
|
|
@ -374,8 +374,9 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
|
|||
if (WARN_ON(!rxb))
|
||||
return;
|
||||
|
||||
rxcb.truesize = PAGE_SIZE << hw_params(trans).rx_page_order;
|
||||
dma_unmap_page(trans->dev, rxb->page_dma,
|
||||
PAGE_SIZE << hw_params(trans).rx_page_order,
|
||||
rxcb.truesize,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
rxcb._page = rxb->page;
|
||||
|
|
|
@ -260,6 +260,7 @@ static inline void iwl_free_resp(struct iwl_host_cmd *cmd)
|
|||
|
||||
struct iwl_rx_cmd_buffer {
|
||||
struct page *_page;
|
||||
unsigned int truesize;
|
||||
};
|
||||
|
||||
static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r)
|
||||
|
|
Loading…
Reference in a new issue