From patchwork Mon May 4 23:09:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 467867 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id EF60A140295 for ; Tue, 5 May 2015 09:09:50 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751200AbbEDXJr (ORCPT ); Mon, 4 May 2015 19:09:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39699 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750832AbbEDXJp (ORCPT ); Mon, 4 May 2015 19:09:45 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id 308E58EA51; Mon, 4 May 2015 23:09:45 +0000 (UTC) Received: from [192.168.122.149] (vpn-227-11.phx2.redhat.com [10.3.227.11]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t44N9ij4001201; Mon, 4 May 2015 19:09:44 -0400 Subject: [net-next PATCH 1/6] net: Add skb_free_frag to replace use of put_page in freeing skb->head From: Alexander Duyck To: linux-mm@kvack.org, netdev@vger.kernel.org Cc: akpm@linux-foundation.org, davem@davemloft.net Date: Mon, 04 May 2015 16:09:43 -0700 Message-ID: <20150504230943.1496.11131.stgit@ahduyck-vm-fedora22> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This change adds a function called skb_free_frag which is meant to compliment the function __alloc_page_frag. The general idea is to enable a more lightweight version of page freeing since we don't actually need all the overhead of a put_page, and we don't quite fit the model of __free_pages. The model for this is based off of __free_pages since we don't actually need to deal with all of the cases that put_page handles. I incorporated the virt_to_head_page call and compound_order into the function as it actually allows for a signficant size reduction by reducing code duplication. In order to enable the function it was necessary to move __free_pages_ok from being a statically defined function so that I could use it in skbuff.c. Signed-off-by: Alexander Duyck --- include/linux/gfp.h | 1 + include/linux/skbuff.h | 1 + mm/page_alloc.c | 4 +--- net/core/skbuff.c | 29 ++++++++++++++++++++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 97a9373e61e8..edd19a06e2ac 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -365,6 +365,7 @@ extern void __free_pages(struct page *page, unsigned int order); extern void free_pages(unsigned long addr, unsigned int order); extern void free_hot_cold_page(struct page *page, bool cold); extern void free_hot_cold_page_list(struct list_head *list, bool cold); +extern void __free_pages_ok(struct page *page, unsigned int order); extern void __free_kmem_pages(struct page *page, unsigned int order); extern void free_kmem_pages(unsigned long addr, unsigned int order); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9c2f793573fa..3bfe3340929e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2186,6 +2186,7 @@ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC); } +void skb_free_frag(void *head); void *napi_alloc_frag(unsigned int fragsz); struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int length, gfp_t gfp_mask); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ebffa0e4a9c0..ab9ba9360730 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -165,8 +165,6 @@ bool pm_suspended_storage(void) int pageblock_order __read_mostly; #endif -static void __free_pages_ok(struct page *page, unsigned int order); - /* * results with 256, 32 in the lowmem_reserve sysctl: * 1G machine -> (16M dma, 800M-16M normal, 1G-800M high) @@ -815,7 +813,7 @@ static bool free_pages_prepare(struct page *page, unsigned int order) return true; } -static void __free_pages_ok(struct page *page, unsigned int order) +void __free_pages_ok(struct page *page, unsigned int order) { unsigned long flags; int migratetype; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1e4278a4dd7e..754842557fb0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -428,6 +428,27 @@ refill: return page_address(page) + offset; } +/** + * skb_free_frag - free a page fragment + * @head: virtual address of page fragment + * + * Frees a page fragment allocated out of either a compound or order 0 page. + * The function itself is a hybrid between free_pages and free_compound_page + * which can be found in mm/page_alloc.c + */ +void skb_free_frag(void *head) +{ + struct page *page = virt_to_head_page(head); + + if (unlikely(put_page_testzero(page))) { + if (likely(PageHead(page))) + __free_pages_ok(page, compound_order(page)); + else + free_hot_cold_page(page, false); + } +} +EXPORT_SYMBOL(skb_free_frag); + static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) { unsigned long flags; @@ -499,7 +520,7 @@ static struct sk_buff *__alloc_rx_skb(unsigned int length, gfp_t gfp_mask, if (likely(data)) { skb = build_skb(data, fragsz); if (unlikely(!skb)) - put_page(virt_to_head_page(data)); + skb_free_frag(data); } } else { skb = __alloc_skb(length, gfp_mask, @@ -611,10 +632,12 @@ static void skb_clone_fraglist(struct sk_buff *skb) static void skb_free_head(struct sk_buff *skb) { + unsigned char *head = skb->head; + if (skb->head_frag) - put_page(virt_to_head_page(skb->head)); + skb_free_frag(head); else - kfree(skb->head); + kfree(head); } static void skb_release_data(struct sk_buff *skb)