1. 保护权限

mmap函数的prot参数可指定内存映射区的保护权限,例如指定PROT_READ和PROT_EXEC,在调用open打开文件就应该指定O_RDONLY或者O_RDWR。如果指定了PROT_WRITE,打开的文件应该使用O_WRONLY或者O_RDWR。

 

由于一些硬件架构提供的内存保护粒度有所不同,情况也会变的复杂:

1. 一般打开文件指定O_RDWR标记就已经满足基本的使用了。

2. 如果prot参数只指定了PROT_WRITE,且open以O_WRONLY标记打开文件,内存映射的保护权限和打开文件的权限理论上是兼容的,但是调用mmap却会失败,设置errno为EACCES错误。因为一些硬件架构上PROT_WRITE隐含了PROT_READ,这意味着系统分页可写也可读,但这与O_WRONLY标记实际上是不兼容的

例如下面这一段代码:

        //以O_WRONLY权限打开文件
        int fd = open("test.txt", O_WRONLY, 0644);
        if (fd < 0){
                perror("open error");
        }

        //拓展文件大小4096
        lseek(fd , 4096, SEEK_SET);
        write(fd , "0" , 1);

        //指向文件开头
        lseek(fd , 0 , SEEK_SET);

        //创建共享映射区,指定PROT_WRITE权限
        addr =(char *)mmap(NULL , 4096 , PROT_WRITE , MAP_SHARED , fd , 0);
        if (addr == MAP_FAILED){
                perror("mmap err: ");

                //进一步判断是否为EACCES错误
                if(errno == EACCES){
                        puts("EACCES error");
                        exit(-1);
                }
        }

 

程序执行结果:

46-内存映射的保护和同步-LMLPHP

 

3. 以O_RDONLY标记打开一个文件,mmap调用指定了MAP_PRIVATE创建私有内存映射,因为MAP_PRIVATE映射上的修改操作不会反映到打开的文件中,所以prot参数可以指定任意的组合权限。

对于一个MAP_SHARED映射来说,在MAP_SHARED映射上的修改操作会反映到打开的文件中,唯一与O_RDONLY标记兼容的内存保护权限就是PROT_READ|PROT_EXEC。

 

2. 映射区域同步——msync

一般,为确保映射区的数据写入物理磁盘上的文件中,在调用munmap解除映射前需要调用msync函数。前面我们没有调用msync函数依然能在文件中看到写入的数据,这是因为内核会自动将MAP_SHARED映射区的内容同步到打开的文件中,但内核并不保证何时同步数据。

通过调用msync函数可以让应用程序显式的控制文件与内存映射中的数据同步。

#include <sys/mman.h>
int msync(void *addr, size_t length, int flags);

返回值:成功返回0,失败返回-1并设置errno

addr:需要同步的内存映射区起始地址

length:需要同步的数据大小

flags:设置同步数据的方式(MS_SYNC,MS_ASYNC,MS_INVALIDATE)

 

10-06 13:41