mapping address pointer to page structure
Hi All, Is it possible to map a address like skb->data in to struct page. My requirement is to convert multiple skb to a single master skb, having all the data of other skb. i.e, i want add skb->data of multiple skb to a single skb as the fragments. So instead of making a memcpy every time, i just call skb_add_rx_frag my requirement is some thing like this *.* *.* *struct page *page = virt_to_page(skb->data);* * * *skb_add_rx_frag(master_skb, skb_shinfo(master_skb)->nr_frags, page, off, skb->len)* *.* *.* And can some one please tell what is the use of the functions like * virt_to_page* and *kmap_atomic_to_page*, i tried calling virt_to_page(skb->data), but when i print the data in the page address ( page_address(page) ) and the data in pointed by skb->data, i came to know its mapping to a wrong page. so can some one please explain me what is correct way to do this. Thanks in advance.
. struct page *page = virt_to_page(skb->data); If skb->data page aligned?
. And can some one please tell what is the use of the functions like virt_to_page and kmap_atomic_to_page, Generally to lock the page in memory(esp while doing dma) using get_page().
i tried calling virt_to_page(skb->data), but when i print the data in the page address ( page_address(page) ) and the data in pointed by skb->data, i came to know its mapping to a wrong page. If skb->data is not page aligned then page_address(page) will be equal to skb->data+(somevalue) (on nearest page boundary).
-syed
Hi Syed, Thanks for the response, in order to check whether the data is in page or not, i tried printing the whole page data, i found that it is present in the page, so i calculate the offset at which the data is present by using *(unsigned long) skb->data - (unsigned long) page_address(page)* seem like it working but my question is will it work in all case. So am using the following code *.* *.* *struct page *page = virt_to_page(skb->data);* *int offset = **(unsigned long) skb->data - (unsigned long) page_address(page);* *skb_add_rx_frag(master_skb, skb_shinfo(master_skb)->nr_frags, page, offset, skb->len)* *.* *.* * * is this the right way to do ? i want to understand how the memory handling are happening in kernel, can some one point me to right material. Thank you, On Wed, Mar 30, 2011 at 1:10 AM, sk.syed2 <sk.syed2@gmail.com> wrote:
. struct page *page = virt_to_page(skb->data); If skb->data page aligned?
. And can some one please tell what is the use of the functions like virt_to_page and kmap_atomic_to_page, Generally to lock the page in memory(esp while doing dma) using get_page().
i tried calling virt_to_page(skb->data), but when i print the data in the page address ( page_address(page) ) and the data in pointed by skb->data, i came to know its mapping to a wrong page. If skb->data is not page aligned then page_address(page) will be equal to skb->data+(somevalue) (on nearest page boundary).
-syed
struct page *page = virt_to_page(skb->data); int offset = (unsigned long) skb->data - (unsigned long) page_address(page); skb_add_rx_frag(master_skb, skb_shinfo(master_skb)->nr_frags, page, offset, skb->len) . . is this the right way to do ? This will work if skb->len < PAGE_SIZE, otherwise it means it spans more than a page and you need to do skb_add_rx_frag for each PAGE_SIZE data present. Refer to Understanding Linux network internals By Christian Benvenuti p 488/489.
-syed
On Wed, Mar 30, 2011 at 10:42 PM, sk.syed2 <sk.syed2@gmail.com> wrote:
struct page *page = virt_to_page(skb->data); int offset = (unsigned long) skb->data - (unsigned long) page_address(page); skb_add_rx_frag(master_skb, skb_shinfo(master_skb)->nr_frags, page, offset, skb->len) . . is this the right way to do ? This will work if skb->len < PAGE_SIZE, otherwise it means it spans more than a page and you need to do skb_add_rx_frag for each PAGE_SIZE data present. Refer to Understanding Linux network internals By Christian Benvenuti p 488/489.
Thanks Syed, skb->len is always smaller then PAGE_SIZE because i have set the mtu size as 1500 from my network driver. But am facing kernel panic, if i just the moment the driver call dev_queue_xmit, so i guess this may not be right way to get the page. Anyways thanks for the support.
Hi, On Wed, Mar 30, 2011 at 9:09 PM, swathi suresh <swathi.suresh07@gmail.com> wrote:
On Wed, Mar 30, 2011 at 10:42 PM, sk.syed2 <sk.syed2@gmail.com> wrote:
struct page *page = virt_to_page(skb->data); int offset = (unsigned long) skb->data - (unsigned long) page_address(page); skb_add_rx_frag(master_skb, skb_shinfo(master_skb)->nr_frags, page, offset, skb->len) . . is this the right way to do ? This will work if skb->len < PAGE_SIZE, otherwise it means it spans more than a page and you need to do skb_add_rx_frag for each PAGE_SIZE data present. Refer to Understanding Linux network internals By Christian Benvenuti p 488/489.
Thanks Syed, skb->len is always smaller then PAGE_SIZE because i have set the mtu size as 1500 from my network driver. But am facing kernel panic, if i just the moment the driver call dev_queue_xmit, so i guess this may not be right way to get the page.
It isn't sufficient for skb->len to just be less than PAGE_SIZE. offset + skb->len also has to be less than PAGE_SIZE, otherwise your data will cross into a different page. -- Dave Hylands Shuswap, BC, Canada http://www.davehylands.com
participants (3)
-
Dave Hylands -
sk.syed2 -
swathi suresh