From patchwork Fri Jul 15 11:07:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Campbell X-Patchwork-Id: 977882 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p6FBGnBl031111 for ; Fri, 15 Jul 2011 11:16:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750745Ab1GOLQr (ORCPT ); Fri, 15 Jul 2011 07:16:47 -0400 Received: from smtp.citrix.com ([66.165.176.89]:32675 "EHLO SMTP.CITRIX.COM" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750722Ab1GOLQr (ORCPT ); Fri, 15 Jul 2011 07:16:47 -0400 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 15 Jul 2011 11:16:49 +0000 (UTC) X-Greylist: delayed 572 seconds by postgrey-1.27 at vger.kernel.org; Fri, 15 Jul 2011 07:16:46 EDT X-IronPort-AV: E=Sophos;i="4.65,534,1304308800"; d="scan'208";a="15102448" Received: from ftlpmailmx02.citrite.net ([10.13.107.66]) by FTLPIPO01.CITRIX.COM with ESMTP/TLS/RC4-MD5; 15 Jul 2011 07:07:16 -0400 Received: from smtp01.ad.xensource.com (10.219.128.104) by smtprelay.citrix.com (10.13.107.66) with Microsoft SMTP Server id 8.3.137.0; Fri, 15 Jul 2011 07:07:16 -0400 Received: from cosworth.uk.xensource.com (cosworth.uk.xensource.com [10.80.16.52]) by smtp01.ad.xensource.com (8.13.1/8.13.1) with ESMTP id p6FB7CB2018064; Fri, 15 Jul 2011 04:07:15 -0700 From: Ian Campbell To: netdev@vger.kernel.org CC: linux-nfs@vger.kernel.org, Ian Campbell Subject: [PATCH 03/10] net: add APIs for manipulating skb page fragments. Date: Fri, 15 Jul 2011 12:07:04 +0100 Message-ID: <1310728031-19569-3-git-send-email-ian.campbell@citrix.com> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1310728006.20648.3.camel@zakaz.uk.xensource.com> References: <1310728006.20648.3.camel@zakaz.uk.xensource.com> MIME-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org The primary aim is to add skb_frag_(ref|unref) in order to remove the use of bare get/put_page on SKB pages fragments and to isolate users from subsequent changes to the skb_frag_t data structure. The API also includes an accessor for the struct page itself. The default variant of this returns a *const* struct page in an attempt to catch bare uses of get/put_page (which take a non-const struct page). Also included are helper APIs for passing a paged fragment to kmap and (pci|dma)_map_page since I was seeing the same pattern a lot. Signed-off-by: Ian Campbell --- include/linux/skbuff.h | 225 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 223 insertions(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c0a4f3a..c061257 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include /* Don't change this without changing skb_csum_unnecessary! */ #define CHECKSUM_NONE 0 @@ -1109,14 +1111,47 @@ static inline int skb_pagelen(const struct sk_buff *skb) return len + skb_headlen(skb); } -static inline void skb_fill_page_desc(struct sk_buff *skb, int i, - struct page *page, int off, int size) +/** + * __skb_fill_page_desc - initialise a paged fragment in an skb + * @skb: buffer containing fragment to be initialised + * @i: paged fragment index to initialise + * @page: the page to use for this fragment + * @off: the offset to the data with @page + * @size: the length of the data + * + * Initialises the @i'th fragment of @skb to point to &size bytes at + * offset @off within @page. + * + * Does not take any additional reference on the fragment. + */ +static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, + struct page *page, int off, int size) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; frag->page = page; frag->page_offset = off; frag->size = size; +} + +/** + * skb_fill_page_desc - initialise a paged fragment in an skb + * @skb: buffer containing fragment to be initialised + * @i: paged fragment index to initialise + * @page: the page to use for this fragment + * @off: the offset to the data with @page + * @size: the length of the data + * + * As per __skb_fill_page_desc() -- initialises the @i'th fragment of + * @skb to point to &size bytes at offset @off within @page. In + * addition updates @skb such that @i is the last fragment. + * + * Does not take any additional reference on the fragment. + */ +static inline void skb_fill_page_desc(struct sk_buff *skb, int i, + struct page *page, int off, int size) +{ + __skb_fill_page_desc(skb, i, page, off, size); skb_shinfo(skb)->nr_frags = i + 1; } @@ -1605,6 +1640,192 @@ static inline void netdev_free_page(struct net_device *dev, struct page *page) } /** + * __skb_frag_page - retrieve the page refered to by a paged fragment + * @frag: the paged fragment + * + * Returns the &struct page associated with @frag. Where possible you + * should use skb_frag_page() which returns a const &struct page. + */ +static inline struct page *__skb_frag_page(const skb_frag_t *frag) +{ + return frag->page; +} + +/** + * __skb_frag_page - retrieve the page refered to by a paged fragment + * @frag: the paged fragment + * + * Returns the &struct page associated with @frag as a const. + */ +static inline const struct page *skb_frag_page(const skb_frag_t *frag) +{ + return frag->page; +} + +/** + * __skb_frag_ref - take an addition reference on a paged fragment. + * @frag: the paged fragment + * + * Takes an additional reference on the paged fragment @frag. + */ +static inline void __skb_frag_ref(skb_frag_t *frag) +{ + get_page(__skb_frag_page(frag)); +} + +/** + * skb_frag_ref - take an addition reference on a paged fragment of an skb. + * @skb: the buffer + * @f: the fragment offset. + * + * Takes an additional reference on the @f'th paged fragment of @skb. + */ +static inline void skb_frag_ref(struct sk_buff *skb, int f) +{ + __skb_frag_ref(&skb_shinfo(skb)->frags[f]); +} + +/** + * __skb_frag_unref - release a reference on a paged fragment. + * @frag: the paged fragment + * + * Releases a reference on the paged fragment @frag. + */ +static inline void __skb_frag_unref(skb_frag_t *frag) +{ + put_page(__skb_frag_page(frag)); +} + +/** + * skb_frag_unref - release a reference on a paged fragment of an skb. + * @skb: the buffer + * @f: the fragment offset + * + * Releases a reference on the @f'th paged fragment of @skb. + */ +static inline void skb_frag_unref(struct sk_buff *skb, int f) +{ + __skb_frag_unref(&skb_shinfo(skb)->frags[f]); +} + +/** + * skb_frag_address - gets the address of the data contained in a paged fragment + * @frag: the paged fragment buffer + * + * Returns the address of the data within @frag. The page must already + * be mapped. + */ +static inline void *skb_frag_address(const skb_frag_t *frag) +{ + return page_address(skb_frag_page(frag)) + frag->page_offset; +} + +/** + * skb_frag_address_safe - gets the address of the data contained in a paged fragment + * @frag: the paged fragment buffer + * + * Returns the address of the data within @frag. Checks that the page + * is mapped and returns %NULL otherwise. + */ +static inline void *skb_frag_address_safe(const skb_frag_t *frag) +{ + void *ptr = page_address(skb_frag_page(frag)); + if (unlikely(!ptr)) + return NULL; + + return ptr + frag->page_offset; +} + +/** + * __skb_frag_set_page - sets the page contained in a paged fragment + * @frag: the paged fragment + * @page: the page to set + * + * Sets the fragment @frag to contain @page. + */ +static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page) +{ + frag->page = page; + __skb_frag_ref(frag); +} + +/** + * skb_frag_set_page - sets the page contained in a paged fragment of an skb + * @skb: the buffer + * @f: the fragment offset + * @page: the page to set + * + * Sets the @f'th fragment of @skb to contain @page. + */ +static inline void skb_frag_set_page(struct sk_buff *skb, int f, + struct page *page) +{ + __skb_frag_set_page(&skb_shinfo(skb)->frags[f], page); +} + +/** + * skb_frag_kmap - kmaps a paged fragment + * @frag: the paged fragment + * + * kmap()s the paged fragment @frag and returns the virtual address. + */ +static inline void *skb_frag_kmap(skb_frag_t *frag) +{ + return kmap(__skb_frag_page(frag)); +} + +/** + * skb_frag_kmap - kunmaps a paged fragment + * @frag: the paged fragment + * + * kunmap()s the paged fragment @frag. + */ +static inline void skb_frag_kunmap(skb_frag_t *frag) +{ + kunmap(__skb_frag_page(frag)); +} + +/** + * skb_frag_pci_map - maps a paged fragment to a PCI device + * @hwdev: the PCI device to map the fragment to + * @frag: the paged fragment to map + * @offset: the offset within the fragment (starting at the fragments own offset) + * @size: the number of bytes to map + * @direction: the direction of the mapping (%PCI_DMA_*) + * + * Maps the page associated with @frag to the PCI device @hwdev. + */ +static inline dma_addr_t skb_frag_pci_map(struct pci_dev *hwdev, + const skb_frag_t *frag, + unsigned long offset, + size_t size, + int direction) + +{ + return pci_map_page(hwdev, __skb_frag_page(frag), + frag->page_offset + offset, size, direction); +} + +/** + * skb_frag_dma_map - maps a paged fragment via the DMA API + * @device: the device to map the fragment to + * @frag: the paged fragment to map + * @offset: the offset within the fragment (starting at the fragments own offset) + * @size: the number of bytes to map + * @direction: the direction of the mapping (%PCI_DMA_*) + * + * Maps the page associated with @frag to @device. + */ +static inline dma_addr_t skb_frag_dma_map(struct device *dev, + const skb_frag_t *frag, + size_t offset, size_t size, + enum dma_data_direction dir) +{ + return dma_map_page(dev, __skb_frag_page(frag), + frag->page_offset + offset, size, dir); +} + +/** * skb_clone_writable - is the header of a clone writable * @skb: buffer to check * @len: length up to which to write