mmap内存映射---(八)

在应用空间采用mmap进行内存映射时,内核调用的是ring_mmap函数;例如:我们在前面讲解时,讲解了pfring_open_consumer函数,这个函数里面调用mmap如下:

      ring->buffer = (char *)mmap(NULL,memSlotsLen,PROT_READ|PROT_WRITE,

                              MAP_SHARED, ring->fd, 0);

在内核采用ring_mmap函数进行处理;该函数源码如下:

staticint ring_mmap(struct file *file,

                   struct socket *sock, struct vm_area_struct*vma)

{

  struct sock *sk = sock->sk;

  struct pf_ring_socket *pfr = ring_sk(sk);

  //采用ring_skskpf_ring_socket建立关联,即取得环形缓冲区的内存地址

  int rc;

  unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);

  if(enable_debug)

    printk("[PF_RING] ring_mmap()called\n");

 

  if(ring_alloc_mem(sk) != 0) {

    printk("[PF_RING] ring_mmap(): unableto allocate memory\n");

    return(-EINVAL);

  }

 

  if(size % PAGE_SIZE) {

    if(enable_debug)

      printk("[PF_RING] ring_mmap()failed: len is not multiple of PAGE_SIZE\n");

         //打印错误信息,因为分配内存的长度不是PAGE_SIZE的整数倍

    return(-EINVAL);

  }

 

  if(enable_debug)

    printk("[PF_RING] ring_mmap() called,size: %ld bytes [bucket_len=%d]\n",

         size, pfr->bucket_len);

//打印调试信息,内存分配的大小及桶的大小

  if((pfr->dna_device == NULL) &&(pfr->ring_memory == NULL)) {

    if(enable_debug)

      printk("[PF_RING] ring_mmap()failed: ""mapping area to an unbound socket\n");

    return -EINVAL;

  }

 

 //dna_device==NULL表示没有采用dna技术

  if(pfr->dna_device == NULL) {

/*如果用户空间试图mmapsize超过了tot_mem的大小的话,直接报错*/

    if(size >pfr->slots_info->tot_mem) {

      if(enable_debug)

       printk("[PF_RING] ring_mmap()failed: "

             "area too large [%ld > %d]\n",

             size, pfr->slots_info->tot_mem);

      return(-EINVAL);

    }

 

    if(enable_debug)

      printk("[PF_RING] mmap[slot_len=%d]"

           "[tot_slots=%d] for ring on device %s\n",

           pfr->slots_info->slot_len, pfr->slots_info->min_num_slots,

           pfr->ring_netdev->dev->name);

    /*do_memory_mmap函数作用是进行内存映射,pfr->ring_memory为分配的环形队列空间;要mmap操作,实际上就是调用remap_pfn_range函数把pfr->ring_memory映射到用户空间;

   */

    if((rc = do_memory_mmap(vma, size,pfr->ring_memory, VM_LOCKED, 0)) < 0)

      return(rc);

  } else {

    int count = pfr->mmap_count;

    /* DNA Device */

/*

do_memory_mmap函数的定义如下:

 

static int do_memory_mmap(structvm_area_struct *vma,

                       unsigned long size, char *ptr, u_int flags, intmode)

{

 unsigned long start;

 

 /* we do not want to have this area swapped out, lock it */

  vma->vm_flags |= flags;

 

 start = vma->vm_start;

 

 if(enable_debug)

   printk("[PF_RING] do_memory_mmap(mode=%d, size=%lu,ptr=%p)\n", mode, size, ptr);

 

 while(size > 0) {

   int rc;

 

   if(mode == 0) {

#if(LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,11))

      rc = remap_vmalloc_range(vma, ptr, 0);

      break; /* Do not iterate */

#else

      rc = remap_pfn_range(vma, start,kvirt_to_pa((unsigned long)ptr), PAGE_SIZE, PAGE_SHARED);  //remap_pfn_range作用是进行内存映射

#endif

   } else if(mode == 1) {

      rc = remap_pfn_range(vma, start,__pa(ptr) >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED);

   } else {

      rc = remap_pfn_range(vma, start,((unsigned long)ptr) >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED);

   }

//根据3种模式的不同进行内存映射;

   if(rc) {

      if(enable_debug)

       printk("[PF_RING]remap_pfn_range() failed\n");

      return(-EAGAIN);

   }

 

   start += PAGE_SIZE;

   ptr += PAGE_SIZE;

   if(size > PAGE_SIZE) {

      size -= PAGE_SIZE;

   } else {

      size = 0;

   }

 }

 return(0);

}

       pfr->ring_memory 即为分配的环形队列空间。要mmap操作,实际上就是调用remap_pfn_range函数把pfr->ring_memory 映射到用户空间,就ok了。

remap_pfn_range()函数的原型:
int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr,unsigned long pfn, unsigned long size, pgprot_t prot);

   

*/

    printk("[PF_RING] mmapcount(%d)\n", count);

 

    pfr->mmap_count++;

 

    switch(count) {

    case 0:

      if((rc = do_memory_mmap(vma, size,

                           (void*)pfr->dna_device->packet_memory, VM_LOCKED, 1)) < 0)

       return(rc);

      break;

 

    case 1:

      if((rc = do_memory_mmap(vma, size,

                           (void*)pfr->dna_device->descr_packet_memory, VM_LOCKED, 1)) < 0)

       return(rc);

      break;

 

    case 2:

      if((rc = do_memory_mmap(vma, size,

                           (void *)pfr->dna_device->phys_card_memory,(VM_RESERVED | VM_IO), 2)) < 0)

       return(rc);

      break;

 

    default:

      return(-EAGAIN);

    }

  }

 

  if(enable_debug)

    printk("[PF_RING] ring_mmapsucceeded\n");

 

  return 0;

}

/************************************** */

 

   上面分析的源码就是应用程序采用mmap和内核ring_mmap进行内存映射的代码,可以用来共享内核和用户空间之间的内存;

你可能感兴趣的:(网络编程开源技术)