共享文件映射
一个应用场景就是两个进程共同读写一个文本文件,比如你用vim编辑保存后,再用cat命令查看
私有文件映射
最典型的应用就是进程对动态链接库(比如libc.so)的使用
共享匿名映射
一个典型应用是作为进程间通信机制的POSIX共享内存
私有匿名映射
用来实现glibc中的malloc
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
prot :
PROT_READ
PROT_WRITE
PROT_NONE
PROT_EXEC
flags:
MAP_SHARED
MAP_PRIVATE
MAP_ANON/MAP_ANONYMOUS
fd:
-1
0/1/2
3/4/5...
---------------------------------
共享文件映射
fd : 3/4/5...
flags : MAP_SHARED
私有文件映射
id : 3/4/5...
flags : MAP_PRIVATE
共享匿名映射
id : -1
flags : MAP_SHARED|MAP_ANONYMOUS
私有匿名映射
id : -1
flags :MAP_PRIVATE|MAP_ANONYMOUS
mmap 的典型应用
/dev/shm/xxx
共享内存实现方案有多种,posix共享内存是其中的一种
posix共享内存是一种通信方式,其基于 mmap 和 (文件系统shmem)
内存文件系统shmem 提供 fd 和 shmemfs 所有文件共享的 file_operations
shmem_file_operations 提供 generic_file_mmap 或者 shmem_mmap
底层用到了 shmem_vm_ops , shmem_vm_ops 重定位 到 shmem_vm_ops 或者 generic_file_vm_ops
mmap 提供 访问 fd 对应的 内存 的 技术
/dev/xxx
共享匿名映射
在内核中走到了
mmap_region-> mm/mmap.c(1844)shmem_zero_setup,
其实用到了 "/dev/zero" 文件
往下用到了 基于 tmpfs 的 shmem_vm_ops , shmem_vm_ops 重定位 到 shmem_vm_ops 或者 generic_file_vm_ops
共享文件映射
在内核中走到了
mmap_region-> mm/mmap.c(1807)call_mmap(即mmap_zero)->shmem_zero_setup
往下用到了 基于 tmpfs 的 shmem_vm_ops , shmem_vm_ops 重定位 到 shmem_vm_ops 或者 generic_file_vm_ops
/dev/zero 对应 的 file_operations 提供 zero_fops 的 mmap_zero
/dev/fb0 提供了 句柄 和 该文件独有的file_operations
fb_fops 提供 fb_mmap
符合 https:
mmap 提供了 访问 fd 对应的 内存 的 技术
[DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
mem_fops 提供 mmap_mem
符合 https:
[2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
.mmap = mmap_kmem,
符合 https:
- 其他 file_operations mmap 成员为 NULL 的 /dev/文件
tty_init
cdev_init(&tty_cdev, &tty_fops);
cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1);
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty");
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
tty_init
cdev_init(&console_cdev, &console_fops);
cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1);
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console")
device_create_with_groups(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, cons_dev_groups, "console");
console_fops 的 mmap 成员 为 NULL
[3] = { "null", 0666, &null_fops, 0 },
.mmap = NULL,
[4] = { "port", 0, &port_fops, 0 }
.mmap = NULL,
[7] = { "full", 0666, &full_fops, 0 },
.mmap = NULL,
[8] = { "random", 0666, &random_fops, 0 },
.mmap = NULL,
[9] = { "urandom", 0666, &urandom_fops, 0 },
.mmap = NULL,
[11] = { "kmsg", 0644, &kmsg_fops, 0 },
.mmap = NULL,
mmap成员的实现
shmem_zero_setup
vma->vm_ops = &shmem_vm_ops;
mmap_zero
shmem_zero_setup
vma->vm_ops = &shmem_vm_ops;
shmem_mmap
vma->vm_ops = &shmem_vm_ops;
shmem_vm_ops
shmem_fault
我们看到 /dev 下面的 文件 如果用到了 vma->vm_ops , 那么 一定是用到了 shmem_vm_ops
shmem_vm_ops 根据 tmpfs 的不同配置 会 重定位 到 shmem_vm_ops 或 generic_file_vm_ops
shmem_vm_ops 被 "共享匿名映射" 和 "共享文件映射 中的 /dev/zero" 和 "共享文件映射 中的 /dev/shm/xxx" 用到
$ grep "vma->vm_ops = " * -nr
drivers/usb/core/devio.c:271: vma->vm_ops = &usbdev_vm_ops;
drivers/char/mem.c:403: vma->vm_ops = &mmap_mem_ops;
fs/kernfs/file.c:500: vma->vm_ops = &kernfs_vm_ops;
fs/aio.c:369: vma->vm_ops = &aio_ring_vm_ops;
fs/nfs/file.c:195: vma->vm_ops = &nfs_file_vm_ops;
fs/ext4/file.c:766: vma->vm_ops = &ext4_dax_vm_ops;
fs/ext4/file.c:769: vma->vm_ops = &ext4_file_vm_ops;
include/linux/mm.h:641: vma->vm_ops = &dummy_vm_ops;
include/linux/mm.h:647: vma->vm_ops = NULL;
mm/shmem.c:2283: vma->vm_ops = &shmem_vm_ops;
mm/shmem.c:4280: vma->vm_ops = &shmem_vm_ops;
mm/filemap.c:3030: vma->vm_ops = &generic_file_vm_ops;
mm/mmap.c:3500: vma->vm_ops = ops;
net/ipv4/tcp.c:1756: vma->vm_ops = &tcp_vm_ops;
fb_mmap
vm_iomap_memory
mmap_mem
remap_pfn_range
mmap_kmem
mmap_mem
remap_pfn_range
很少情况下会出现第二类
在mmap前没做任何事情
在mmap中做了虚拟地址空间的申请,物理地址空间的申请和映射关系的建立