`
hro01hro
  • 浏览: 17521 次
社区版块
存档分类
最新评论

2--共享内存的实践到内核--共享内存的映射

阅读更多

2--共享内存的实践到内核--共享内存的映射
2011年05月11日
  今天继续我们的内核研究,即然我们选择了2.6.26内核做为研究对象的版本,所以请朋友们还是手中有这个源代码比较好,有的地方可能需要朋友们自己去研读,特别是有一定基础的朋友可以更宽泛一些的阅读,如果你是新手就请跟着我的步骤进行,必竟主线我们是牢牢抓住不放的,好了,接着上一节我们谈到的应用程序,里面有这样一句代码:
  这个函数就是将我们前边建立的共享内存映射到了本进程,我们跟着进入内核看一下,首先还是在sys_ipc()函数处     case SHMAT:
  switch(version){
  default:{
  ulong raddr;
  ret = do_shmat (first,(char __user *) ptr, second,&raddr);
  if(ret)
  return ret;
  return put_user (raddr,(ulong __user *) third);
  }
  case 1:    /* iBCS2 emulator entry point */
  if(!segment_eq(get_fs(), get_ds()))
  return-EINVAL;
  /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
  return do_shmat (first,(char __user *) ptr, second,(ulong *) third);
  } 看起很复杂重要的函数只有一个那就是do_shmat(),它在ipc/shm.c中的816行处,我们看一下它,函数比较长,我们分段看它 long do_shmat(int shmid,char __user *shmaddr,int shmflg, ulong *raddr)
  {
  struct shmid_kernel *shp;
  unsignedlong addr;
  unsignedlong size;
  structfile*file;
  int err;
  unsignedlong flags;
  unsignedlong prot;
  int acc_mode;
  unsignedlong user_addr;
  struct ipc_namespace *ns;
  struct shm_file_data *sfd;
  struct path path;
  mode_t f_mode;
  err =-EINVAL;
  if(shmid 内存的id标识号,第二、三个参数在应用程序分别传过一个0指针和0,第四个参数就是用于返回到sys_ipc()函数用的一个指针。函数中首先是对第二个参数也就是共享内存的映射地址进行检查,看是否能被SHMLBA整除,即是否按页的大小对齐。如果不能被整除这里就会进行对齐处理,我们看到应用程序传递过来的参数是0指针,这里就会由内核分配一个地址,此后就是对标志的一些处理。我们接着往下看 
  /*
  * We cannot rely on the fs check since SYSV IPC does have an
  * additional creator id...
  */
  ns = current->nsproxy->ipc_ns;
  shp = shm_lock_check(ns, shmid);
  if(IS_ERR(shp)){
  err = PTR_ERR(shp);
  goto out;
  }
  err =-EACCES;
  if(ipcperms(&shp->shm_perm, acc_mode))
  goto out_unlock;
  err = security_shm_shmat(shp, shmaddr, shmflg);
  if(err)
  goto out_unlock;
  path.dentry = dget(shp->shm_file->f_path.dentry);
  path.mnt = shp->shm_file->f_path.mnt;
  shp->shm_nattch++;
  size = i_size_read(path.dentry->d_inode);
  shm_unlock(shp);
  这段代码中,通过shm_lock_check()函数找到struct shmid_kernel 结构,并赋值给这里的局部结构变量shp,我们看到shm_lock_check()函数是与ipc机制相关的,这里我们看一下 
  staticinlinestruct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
  int id)
  {
  struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
  if(IS_ERR(ipcp))
  return(struct shmid_kernel *)ipcp;
  return container_of(ipcp,struct shmid_kernel, shm_perm);
  } 函数内部与消息队列的函数 msg_lock_check()一模一样,无非找到我们已经建立的共享内存并上锁。我们已经在消除队列中讲过 msg_lock_check()函数,所以这里不跟进了。此后我们进行了一些权限的检查,这些检查与文件系统的权限检查类似,我们以后在看文件系统的时候就会讲到,下面是关键的部分了 
  err =-ENOMEM;
  sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  if(!sfd)
  goto out_put_dentry;
  file= alloc_file(path.mnt, path.dentry, f_mode,&shm_file_operations);
  if(!file)
  goto out_free;
  file->private_data = sfd;
  file->f_mapping = shp->shm_file->f_mapping;
  sfd->id = shp->shm_perm.id;
  sfd->ns = get_ipc_ns(ns);
  sfd->file= shp->shm_file;
  sfd->vm_ops =NULL;
  down_write(&current->mm->mmap_sem);
  if(addr &&!(shmflg & SHM_REMAP)){
  err =-EINVAL;
  if(find_vma_intersection(current->mm, addr, addr + size))
  goto invalid;
  /*
  * If shm segment goes below stack, make sure there is some
  * space left for the stack to grow (at least 4 pages).
  */
  if(addr mm->start_stack &&
  addr > current->mm->start_stack - size - PAGE_SIZE * 5)
  goto invalid;
  }
  user_addr = do_mmap (file, addr, size, prot, flags, 0);
  *raddr = user_addr;
  err = 0;
  if(IS_ERR_VALUE(user_addr))
  err =(long)user_addr;
  invalid:
  up_write(&current->mm->mmap_sem);
  fput(file);
  out_nattch:
  down_write(&shm_ids(ns).rw_mutex);
  shp = shm_lock_down(ns, shmid);
  BUG_ON(IS_ERR(shp));
  shp->shm_nattch--;
  if(shp->shm_nattch == 0 &&
  shp->shm_perm.mode & SHM_DEST)
  shm_destroy(ns, shp);
  else
  shm_unlock(shp);
  up_write(&shm_ids(ns).rw_mutex);
  out:
  return err;
  out_unlock:
  shm_unlock(shp);
  goto out;
  out_free:
  kfree(sfd);
  out_put_dentry:
  dput(path.dentry);
  goto out_nattch;
  } 看似上面的过程很复杂其实实质作用的函数只有一个do_mmap()函数,这个函数与内存管理的映射相关,我们先预先看一下为好,也好了解一下内存映射的过程这个函数在include/linux/mm.h的1098行,函数非常短 
  staticinlineunsignedlong do_mmap(structfile*file,unsignedlong addr,
  unsignedlong len,unsignedlong prot,
  unsignedlong flag,unsignedlong offset)
  {
  unsignedlong ret =-EINVAL;
  if((offset + PAGE_ALIGN(len))> PAGE_SHIFT);
  out:
  return ret;
  } 我们看到他转交给了do_mmap_pgoff()函数,它在mm/mmap.c的908行处,这个函数也很长,我们将在内存管理的分析中详细论述,这里只看其关键的部分,也就是我们应用程序要去的地方 我们的映射地址是0,所以内核会get_unmapped_area自动分配一个地址,这个函数我们不跟进了,它里面直接相关内存管理的细节,我们放一放,在do_mmap_pgoff函数中会再进一步调用 这是关键的映射地方,我们跟进看一看 unsignedlong mmap_region(structfile*file,unsignedlong addr,
  unsignedlong len,unsignedlong flags,
  unsignedint vm_flags,unsignedlong pgoff,
  int accountable)
  { 我们只看关键的部分。。。。。。  if (file) {
  error = -EINVAL;
  if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
  goto free_vma;
  if (vm_flags & VM_DENYWRITE) {
  error = deny_write_access(file);
  if (error)
  goto free_vma;
  correct_wcount = 1;
  }
  vma->vm_file = file;
  get_file(file);
  error = file->f_op->mmap(file, vma);
  if (error)
  goto unmap_and_free_vma;
  if (vm_flags & VM_EXECUTABLE)
  added_exe_file_vma(mm);
  } else if (vm_flags & VM_SHARED) {
  error = shmem_zero_setup(vma);
  if (error)
  goto free_vma;
  } 实际最起作用的就只有上面红色的部分代码,这里的file也就是我们上一节讲到创建共享内存中在共享内存的文件系统中创建的那个文件指针,这里就取得了共享内存文件系统file指针后实际上就通过文件系统的file_operations钩子函数,为什么叫钩子函数,其实这些函数就是一些指针即地址,我们之所以称之为钩子就是因为经常要有东西往上挂,即把自己的地址放在file_operations中,这些地址是函数的地址,当代码访问到file_operations中的这些地址时就自动跳到我们挂到钩子上的函数中去了。更详细的要等到我们论述文件系统时了,我们先知道有这么一个钩子函数就成了,这里会执行到哪里呢,肯定是会执行到共享内存文件系统中的钩子函数中,我们看看他到了哪里,我们看到在ipc/shm.c的322行处有共享内存这个钩子函数的定义 
  static const struct file_operations shmem_file_operations = {
  .mmap  = shmem_mmap,
  #ifdef CONFIG_TMPFS
  .llseek  = generic_file_llseek,
  .read  = shmem_file_read,
  .write  = do_sync_write,
  .aio_write = generic_file_aio_write,
  .fsync  = simple_sync_file,
  .splice_read = generic_file_splice_read,
  .splice_write = generic_file_splice_write,
  #endif
  };
  很明显他会跳转到shmem_mmap()函数去执行 到这里我们可以看到实际上就已经映射完成了,可能朋友们会说怎么完成的,没看明白,要知道内核是一个环环相扣的架构,这里其实交给了内存管理的去处理了,那一部分我们以后会进一步论述和分析,在共享内存的映射这里只是建立了内存管理中的必要的映射机制,也就是把钩子函数与这里的共享内存挂上钩。使其在执行到关于共享内存的映射部分时自动到这里提供的机制中去进一步分配和处理,我们只能粗略的这样简介一下,真正发生映射发生时是在“缺页异常”,什么是缺页异常,我们说过内存是页为单位管理的,缺页就是指未建立管理的单位内存,我们以后论述这个名词,现在是假设内存管理中要映射并且走到了缺页异常处理程序中,会自动跳转到上面的钩子函数.fault = shmem_fault,根据这里跳转到shmem_fault()函数 
  static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
  struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
  int error;
  int ret;  if (((loff_t)vmf->pgoff = i_size_read(inode))
  return VM_FAULT_SIGBUS;  error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
  if (error)
  return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);  mark_page_accessed(vmf->page);
  return ret | VM_FAULT_LOCKED;
  }
分享到:
评论

相关推荐

    论文研究-WDF下用户模式和内核模式之间的内存共享 .pdf

    WDF下用户模式和内核模式之间的内存共享,张奇,谢军,Windows Driver Foundation (WDF) 是用于开发Windows 驱动程序的全新平台,也是微软推出的下一代的驱动开发模式。本文简单介绍了该平台下的一��

    用内存映射在多个应用程序之间共享数据

    用内存映射在多个应用程序之间共享数据,使用 (1)用CreateFileMapping()创建一个文件映射内核对象; (2)用MapViewOfFile()将文件数据映射到进程的地址空间; (3)用UnmapViewOfFile()从进程地址空间解除这个...

    Linux /Unix 共享内存

    char *shmaddr是共享内存的起始地址,如果shmaddr为0,内核会把共享内存映像到调用进程的地址空间中选定位置;如果shmaddr不为0,内核会把共享内存映像到shmaddr指定的位置。所以一般把shmaddr设为0。 int shmflag是...

    基于内存映射文件的复杂对象快速读取方法_黄向平.pdf

    为此,提出了一种基于内存映射( memory mapping) 文件的复杂对象共享 读取方法。借助内存映射文件与自定义内存分配器,实现了结构复杂的 C++标准模板库容器对象跨进程无拷贝、无格式 转化的共享,有效降低了数据读取...

    重庆理工大学操作系统基于Linux0.11内核的实践

    在Linux0.11的环境下完成基于内核栈切换的进程切换、地址映射与共享、终端设备的控制、proc文件系统的实现中的三个及以上实验项目。 在Linux四项任务中成功完成了四项:基于内核栈切换的进程切换,终端设备的控制,...

    Linux共享内存实现机制的详解

    内存共享: 两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步...

    包含LINUX内核同步、信号、内存、调度、文件系统.rar

    虚拟内存管理 包括 : 反向映射 , KSM , MMAP 映射 , 缺页中断 , 共享内存 , 进程虚拟地址空间管理 , 页面回收 ; 物理内存管理 包括 : 页面分配器 等 ; 内存管理 位于 下图 Linux 内核整体架构图 中的 内核空间 ;

    Go语言共享内存读写实例分析

    我们知道不同进程见的内存是互相独立的,没办法直接互相操作对方内的数据,而共享内存则是靠操作系统提供的内存映射机制,让不同进程的一块地址空间映射到同一个虚拟内存区域上,使不同的进程可以操作到一块共用的...

    Linux编程--Linux内核

    2.5 内存映射 22 2.6 请求调页 23 2.7 Linux页缓存 24 2.8 页换出和淘汰 25 2.8.1 减少缓冲区和页缓存大小 25 2.8.2 换出System V共享内存页 26 2.8.3 换出和淘汰页 27 2.9 交换缓存 27 2.10 页换入 28 第3章 进程 ...

    寒江独钓-Windows内核安全编程(高清完整版).part1

    2.1.2 共享的内核空间 19 2.1.3 无处不在的内核模块 20 2.2 数据类型 21 2.2.1 基本数据类型 21 2.2.2 返回状态 22 2.2.3 字符串 23 2.3 重要的数据结构 23 2.3.1 驱动对象 23 2.3.2 设备对象 25 2.3.3 请求 26 2.4 ...

    Linux内核情景分析

    5. 2 从路径名到目标节点 5. 3 访问权限与文件安全性 5. 4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5. 6 文件的写与读 5.7 其他文件操作 5. 8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 ...

    Linux内核情景分析(非扫描版)

    5. 2 从路径名到目标节点 5. 3 访问权限与文件安全性 5. 4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5. 6 文件的写与读 5.7 其他文件操作 5. 8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 ...

    Linux内核反向映射机制的详细资料说明

    Linux内核可以通过共享内存的方式为系统节省大量内存,例如fork子进程的时候,父子进程通过只读的方式共享所有的私有页面。再比如通过IPC共享内存方式,各个不相干的进程直接可以共享一块物理内存等等。我们都知道...

    linux操作系统内核技术-uestc课件

     1掌握处理器在进程地址空间上的三种运行位置,了解内核编程不能使用C库函数和FPU,以及可能产生内存故障、核心栈溢出和四种内核竞争情形的原因。(2学时)  2熟悉进程描述符的组织,进程上下文和进程状态转换,和...

    linux 内核源代码分析

    5. 2 从路径名到目标节点 5. 3 访问权限与文件安全性 5. 4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5. 6 文件的写与读 5.7 其他文件操作 5. 8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 ...

    深入解析Linux内存管理ppt

    目录:页表管理 内核页表 物理内存 高端内存 地址映射 虚拟内存 地址空间 高速缓存 页框回收 交换机制 缺页异常 共享内存 文件映射 程序执行

    深入分析Linux内核源码

    7.3.3 共享内存 第八章 虚拟文件系统 8.1 概述 8.2 VFS中的数据结构 8.2.1 超级块 8.2.2 VFS的索引节点 8.2.3 目录项对象 8.2.4 与进程相关的文件结构 8.2.5 主要数据结构间的关系 8.2.6 有关操作的数据...

    Windows 内核情景分析--采用开源代码ReactOS (上册) part01

    3.4 共享映射区(Section) 115 3.5 系统空间的缓冲区管理 133 第4章 对象管理 136 4.1 对象与对象目录 136 4.2 对象类型 148 4.3 句柄和句柄表 162 4.4 对象的创建 169 4.5 几个常用的内核函数 179 4.5.1 ...

    Linux内核 内容很全

    内存管理 15 2.1 虚拟内存抽象模型 15 2.1.1 请求调页 17 2.1.2...内存映射 22 2.6 请求调页 23 2.7 Linux页缓存 24 2.8 页换出和淘汰 25 2.8.1 减少缓冲区和页缓存大小 25 2.8.2 换出System V...

    ARM Cortex-M3内核微控制器快速入门与应用(上)

    本书首先叙述Cortex-M3内核微控制器的内部结构和内部寄存映射及功能,然后通过课题的形式训练读者掌握其编程应用方法。 书的内容不用多说了,重要的是电子版的只有通过豆丁的在线阅读才能看到,不方便。没办法本人费...

Global site tag (gtag.js) - Google Analytics