亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 2731 | 回復(fù): 6
打印 上一主題 下一主題

[網(wǎng)絡(luò)子系統(tǒng)] 關(guān)于PACKET_MMAP映射的問(wèn)題!!好神奇!。。 [復(fù)制鏈接]

論壇徽章:
2
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-07-27 06:20:0015-16賽季CBA聯(lián)賽之福建
日期:2017-03-23 18:32:41
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2016-11-22 15:09 |只看該作者 |倒序?yàn)g覽
本帖最后由 HazeC 于 2016-11-22 15:11 編輯

問(wèn)題產(chǎn)生的來(lái)源:最近一直想著內(nèi)核把數(shù)據(jù)傳遞給應(yīng)用層的方式怎么能快點(diǎn)。ksocket、netlink嘗試之后都放棄了,于是打起來(lái)mmap的主意。
然后就卡殼了,卡殼的原因是內(nèi)核傳遞給應(yīng)用層的數(shù)據(jù)大小不是固定的,而我了解到的mmap函數(shù)實(shí)現(xiàn)里面調(diào)用的remap_pfn_range需要的是一塊連續(xù)的內(nèi)存。
但是如果是連續(xù)內(nèi)存的話,內(nèi)存大小就不可控制了。于是想起了用鏈表存儲(chǔ)每個(gè)buf,然后remap_pfn_range把鏈表映射上去。然而看到remap_pfn_range的參數(shù)就悲劇了。
查找開源實(shí)現(xiàn),PACKET_MMAP與PF_RING都是采用的mmap方式提交的數(shù)據(jù)。
首先查看的是PF_RING,看代碼
  1. tot_mem = sizeof(FlowSlotInfo) + num_slots * the_slot_len;
  2.   if(tot_mem % PAGE_SIZE)
  3.     tot_mem += PAGE_SIZE - (tot_mem % PAGE_SIZE);

  4.   pfr->ring_memory = rvmalloc(tot_mem);

  5.   if(pfr->ring_memory != NULL) {
  6. #if defined(RING_DEBUG)
  7.     printk("[PF_RING] successfully allocated %lu bytes at 0x%08lx\n",
  8.            (unsigned long)tot_mem, (unsigned long)pfr->ring_memory);
  9. #endif
  10.   } else {
  11.     printk("[PF_RING] ERROR: not enough memory for ring\n");
  12.     return(-1);
  13.   }

  14.   // memset(pfr->ring_memory, 0, tot_mem); // rvmalloc does the memset already

  15.   pfr->slots_info = (FlowSlotInfo *) pfr->ring_memory;
  16.   pfr->ring_slots = (char *)(pfr->ring_memory + sizeof(FlowSlotInfo));

  17.   pfr->slots_info->version = RING_FLOWSLOT_VERSION;
  18.   pfr->slots_info->slot_len = the_slot_len;
  19.   pfr->slots_info->data_len = pfr->bucket_len;
  20.   pfr->slots_info->tot_slots =
  21.     (tot_mem - sizeof(FlowSlotInfo)) / the_slot_len;
  22.   pfr->slots_info->tot_mem = tot_mem;
  23.   pfr->slots_info->sample_rate = 1;
復(fù)制代碼
PF_RING看樣子也是把buf最后放到了一塊固定內(nèi)存里面實(shí)現(xiàn)了。
于是看PACKET_MMAP,看代碼:

  1.         start = vma->vm_start;
  2.         for (rb = &po->rx_ring; rb <= &po->tx_ring; rb++) {
  3.                 if (rb->pg_vec == NULL)
  4.                         continue;

  5.                 for (i = 0; i < rb->pg_vec_len; i++) {
  6.                         struct page *page = virt_to_page(rb->pg_vec[i]);
  7.                         int pg_num;

  8.                         for (pg_num = 0; pg_num < rb->pg_vec_pages;
  9.                                         pg_num++, page++) {
  10.                                 err = vm_insert_page(vma, start, page);
  11.                                 if (unlikely(err))
  12.                                         goto out;
  13.                                 start += PAGE_SIZE;
  14.                         }
  15.                 }
  16.         }

  17.         atomic_inc(&po->mapped);
  18.         vma->vm_ops = &packet_mmap_ops;
復(fù)制代碼

此處是PACKET_MMAP的mmap實(shí)現(xiàn)。!vm_insert_page是把buf合并到了一個(gè)vma,但是最后的映射函數(shù)去哪了。。搜了下整個(gè)文件沒有。。
為什么。!

論壇徽章:
20
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-08-17 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-16 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-18 06:20:00每日論壇發(fā)貼之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16賽季CBA聯(lián)賽之江蘇
日期:2017-06-26 11:05:5615-16賽季CBA聯(lián)賽之上海
日期:2017-07-21 18:12:5015-16賽季CBA聯(lián)賽之青島
日期:2017-09-04 17:32:0515-16賽季CBA聯(lián)賽之吉林
日期:2018-03-26 10:02:16程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-15 06:20:0015-16賽季CBA聯(lián)賽之江蘇
日期:2016-07-07 18:37:512015亞冠之薩濟(jì)拖拉機(jī)
日期:2015-08-17 12:21:08
2 [報(bào)告]
發(fā)表于 2016-11-25 12:58 |只看該作者
vm_insert_page里面已經(jīng)包含set_pte的操作了。

論壇徽章:
2
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-07-27 06:20:0015-16賽季CBA聯(lián)賽之福建
日期:2017-03-23 18:32:41
3 [報(bào)告]
發(fā)表于 2016-11-28 16:25 |只看該作者
回復(fù) 2# nswcfd

是的、代碼看到了把不同快set到同一個(gè)vma里面,但問(wèn)題是沒看到把vma映射到應(yīng)用層去。奇怪的是這一點(diǎn)

論壇徽章:
20
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-08-17 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-16 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-18 06:20:00每日論壇發(fā)貼之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16賽季CBA聯(lián)賽之江蘇
日期:2017-06-26 11:05:5615-16賽季CBA聯(lián)賽之上海
日期:2017-07-21 18:12:5015-16賽季CBA聯(lián)賽之青島
日期:2017-09-04 17:32:0515-16賽季CBA聯(lián)賽之吉林
日期:2018-03-26 10:02:16程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-15 06:20:0015-16賽季CBA聯(lián)賽之江蘇
日期:2016-07-07 18:37:512015亞冠之薩濟(jì)拖拉機(jī)
日期:2015-08-17 12:21:08
4 [報(bào)告]
發(fā)表于 2016-12-02 15:43 |只看該作者
本帖最后由 nswcfd 于 2016-12-02 15:51 編輯
  1. #define DRV_NAME        "mmap"
  2. #define DRV_VERSION        "0.1"

  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/mm.h>
  6. #include <linux/miscdevice.h>

  7. static int mmap_chr_close(struct inode *inode, struct file *file)
  8. {
  9.         printk("chr close\n");
  10.         return 0;
  11. }

  12. int nomap;
  13. module_param(nomap, int, 0);

  14. static struct page *page;

  15. static void mmap_open(struct vm_area_struct *vma)
  16. {
  17.         printk("mmap_open: vma->start=%lx\n", vma->vm_start);
  18. }

  19. static void mmap_close(struct vm_area_struct *vma)
  20. {
  21.         printk("mmap_close: vma->start=%lx\n", vma->vm_start);
  22. }

  23. static struct vm_operations_struct mmap_ops = {
  24.         .open = mmap_open,
  25.         .close = mmap_close,
  26. };

  27. static int mmap_chr_mmap(struct file *file, struct vm_area_struct *vma)
  28. {
  29.         int err = -ENODEV;
  30.         printk("vma->start=%lx, vma->end=%lx\n", vma->vm_start, vma->vm_end);
  31.         if (nomap || !page)        
  32.                 return -ENODEV;
  33.         printk("page=%p, address=%p\n", page, page_address(page));
  34.         *(int *)page_address(page) = current->pid;
  35.         err = vm_insert_page(vma, vma->vm_start, page);
  36.         if (err)
  37.                 return err;
  38.         vma->vm_ops = &mmap_ops;
  39.         return 0;
  40. }

  41. static struct file_operations mmap_fops = {
  42.         .owner        = THIS_MODULE,        
  43.         .llseek = no_llseek,
  44.         .release = mmap_chr_close,
  45.         .mmap = mmap_chr_mmap,
  46. };

  47. #define TUN_MINOR        200
  48. #define MMAP_MINOR        TUN_MINOR

  49. static struct miscdevice mmap_miscdev = {
  50.         .minor = MMAP_MINOR,
  51.         .name = "mmap",
  52.         .fops = &mmap_fops,
  53. };

  54. static int __init mmap_init(void)
  55. {
  56.         int ret = 0;
  57.         page = alloc_page(GFP_KERNEL);
  58.         printk("page=%p, addr=%p\n", page, page_address(page));
  59.         ret = misc_register(&mmap_miscdev);
  60.         if (ret)
  61.                 printk(KERN_ERR "mmap: Can't register misc device %d\n", MMAP_MINOR);
  62.         return ret;
  63. }

  64. static void mmap_cleanup(void)
  65. {
  66.         if (page)
  67.                 __free_page(page);
  68.         misc_deregister(&mmap_miscdev);  
  69. }

  70. module_init(mmap_init);
  71. module_exit(mmap_cleanup);
  72. MODULE_LICENSE("GPL");
  73. MODULE_ALIAS_MISCDEV(MMAP_MINOR);
復(fù)制代碼

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <sys/mman.h>

  5. int main()
  6. {
  7.         int fd = open("mmap_dev", O_RDWR);
  8.         printf("fd=%d\n", fd);
  9.         if (fd < 0)
  10.                 return 1;
  11.         char *p = mmap(0, 10, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
  12.         printf("mmap=%p\n", p);
  13.         if (p != MAP_FAILED)
  14.                 printf("map[0]=%d, pid=%d\n", *(int *)p, getpid());
  15. }
復(fù)制代碼


# ./mmap_test
fd=3
<4>vma->start=2ad8378f7000, vma->end=2ad8378f8000
<4>page=ffff810000b21b78, address=ffff810012d59000
mmap=0x2ad8378f7000
map[0]=4557, pid=4557
<4>mmap_close: vma->start=2ad8378f7000
<4>chr close

注意kernel執(zhí)行fops->mmap的參數(shù)(vma->start)和用戶態(tài)mmap返回的數(shù)值是一樣的。
也就是說(shuō),在響應(yīng)mmap syscall的時(shí)候,內(nèi)核先分配vma(分配用戶態(tài)線性地址),然后調(diào)用fops->mmap回調(diào)(關(guān)鍵步驟set_pte映射頁(yè)表),最后給用戶態(tài)返回vma->start。

論壇徽章:
2
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-07-27 06:20:0015-16賽季CBA聯(lián)賽之福建
日期:2017-03-23 18:32:41
5 [報(bào)告]
發(fā)表于 2016-12-30 13:50 |只看該作者
回復(fù) 4# nswcfd

萬(wàn)分感謝。剛看到您的回復(fù),“在響應(yīng)mmap syscall的時(shí)候,內(nèi)核先分配vma(分配用戶態(tài)線性地址),然后調(diào)用fops->mmap回調(diào)(關(guān)鍵步驟set_pte映射頁(yè)表),最后給用戶態(tài)返回vma->start。” 這句話解決了疑惑。
現(xiàn)有個(gè)問(wèn)題是如果我把多個(gè)buf合并到一個(gè)vma的時(shí)候,af_packet.c中如下所示偽代碼
buf1\buf2\buf3f
start = vma->start
foreach(i in 3)
page = virt_to_page(bufi)
vm_insert_page(vma ,start ,page)
start += buf_size;

這段話的意思是不是將多個(gè)buf對(duì)應(yīng)的頁(yè)插入到一個(gè)vma里面去,當(dāng)用戶層調(diào)用mmap的時(shí)候的時(shí)候,用戶層獲取到的內(nèi)存是連續(xù)的,這個(gè)連續(xù)的空間就是vma的作用?
換句話說(shuō) vma這個(gè)實(shí)現(xiàn)了把內(nèi)核多個(gè)非連續(xù)的內(nèi)存空間合并成了一個(gè)連續(xù)的用戶空間?

論壇徽章:
20
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-08-17 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-16 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-18 06:20:00每日論壇發(fā)貼之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16賽季CBA聯(lián)賽之江蘇
日期:2017-06-26 11:05:5615-16賽季CBA聯(lián)賽之上海
日期:2017-07-21 18:12:5015-16賽季CBA聯(lián)賽之青島
日期:2017-09-04 17:32:0515-16賽季CBA聯(lián)賽之吉林
日期:2018-03-26 10:02:16程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-07-15 06:20:0015-16賽季CBA聯(lián)賽之江蘇
日期:2016-07-07 18:37:512015亞冠之薩濟(jì)拖拉機(jī)
日期:2015-08-17 12:21:08
6 [報(bào)告]
發(fā)表于 2016-12-30 20:02 |只看該作者
應(yīng)該是這樣理解吧。
可以看看當(dāng)用戶態(tài)的mmap超過(guò)一個(gè)page的時(shí)候,底層的這些callback的調(diào)用次數(shù)。

論壇徽章:
2
IT運(yùn)維版塊每日發(fā)帖之星
日期:2016-07-27 06:20:0015-16賽季CBA聯(lián)賽之福建
日期:2017-03-23 18:32:41
7 [報(bào)告]
發(fā)表于 2017-01-03 10:41 |只看該作者
回復(fù) 6# nswcfd

萬(wàn)分感謝 解答了疑惑
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP