问题
Here is a example that maps a given file to memory using mmap
function. In this example, I didn't use fwrite
or write
function to write something into a disk file(just print contents to stdout), but the modified memory content is actually reflected on the disk file. I'm guessing that OS tracks mapped memory and writes to disk when mapped memory is modified. I'd like to know the detail of what OS does.
example.c
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]){
if(argc < 2){
printf("File path not mentioned\n");
exit(0);
}
const char *filepath = argv[1];
int fd = open(filepath, O_RDWR);
if(fd < 0){
printf("\n\"%s \" could not open\n",
filepath);
exit(1);
}
struct stat statbuf;
int err = fstat(fd, &statbuf);
if(err < 0){
printf("\n\"%s \" could not open\n",
filepath);
exit(2);
}
char *ptr = mmap(NULL,statbuf.st_size,
PROT_READ|PROT_WRITE,MAP_SHARED,
fd,0);
if(ptr == MAP_FAILED){
printf("Mapping Failed\n");
return 1;
}
close(fd);
ptr[statbuf.st_size - 2] = '@';
ssize_t n = write(1,ptr,statbuf.st_size);
if(n != statbuf.st_size){
printf("Write failed\n");
}
while(1);
}
mytext.txt
hello world!
compile and run
gcc example.c && ./a.out mytext.txt
program is not exited due to the last line and I can see the modified contents in another terminal via cat mytext.txt
hello world@
回答1:
I'm guessing that OS tracks mapped memory and writes to disk when mapped memory is modified.
Yes and no. Certainly the operating system keeps records of memory mapped to files on disk and ensures that changes to that memory are written to disk. However, I do not expect the changes are written immediately.
Based on general knowledge (it has been a long time since I looked at these particular internals of an operating system), what may happen is that the software managing the file system keeps a record that certain blocks on disk are mapped to memory and, once they are changed, that they are “dirty,” meaning they have been modified and will need to be written back to disk eventually.
The operating system may write dirty pages to disk on certain occasions. For example, when the files on the disk have been closed (which also means the memory pages have been unmapped, because mapping memory to a file includes holding the file open) and there is a request to unmount the disk, the dirty pages must be written to disk. They might also be written to disk periodically, as a policy choice.
However, the changes might appear to be in your file even though they are not written to disk! As you read the file, the file system figures out which blocks on disk contain the parts of the file you are requesting. Then it sees those blocks are already in memory. So, to satisfy your read request, it gives you the data from memory instead of reading it from disk. Thus, to you as a user, it will appear that the changed data is actually in the file even though the data is not yet on disk.
This behavior actually falls out of a general design for managing the file system. If you have a file open and read 100 bytes, the file system software initially has to file the right block on disk, read it into memory, and copy the 100 bytes you requested to your process. That block might be 512 bytes or 4096 bytes or some other size that is used for operating with disks. What is the file system going to do with that block? After requesting 100 bytes of a file, a program is very likely to request another 100 bytes. It would be a shame to read it from disk again. So the file system software keeps it around. Which means it keeps a database of which blocks from which disks it currently has in memory.
Next, suppose some other program reads the same file. Clearly, if the necessary block is already in memory, we are going to give that program data from the block in memory, not read it from disk again. So the file system shares all these blocks (subject to appropriate permissions). And if one program changes the data in the file, it goes to the block in memory, so other programs see it right away even if it is not yet written to disk.
Memory mapping a file ties right into this scheme of caching disk blocks in memory. The virtual memory of a process just gets mapped to the physical memory where the file system software is keeping the blocks of a file, and every process has the same view of the file regardless of whether it is using memory mapping or read and write operations.
(This is general information; particular operating systems may behave differently.)
回答2:
Your code seems compiled on Linux.
I am assuming it is.
The mmap(2) system call is related to the virtual address space, and as explained in this OS textbook, the virtual address space is managed by the MMU of your processor. In 2021, MMUs are a part of your processor chip.
So mmap
is asking the OS kernel to reconfigure the MMU. The CPU mode is changed to kernel mode as in every syscalls(2), and the kernel code will reconfigure the MMU and some internal kernel data to handle future page faults differently.
See also kernelnewbies, the OSDEV wiki, Advanced Linux Programming, Linux Assembly HOWTO and study the source code of your Linux kernel and/or GNU libc.
You are compiling with gcc example.c
. Consider compiling with gcc -Wall -Wextra -g example.c
(to get useful warnings and DWARF debug information) then using GDB and strace(1) or ltrace(1) to understand the behavior of your executable.
PS. You may want to use perror(3), or errno(3) with strerror(3)
来源:https://stackoverflow.com/questions/65870480/what-jobs-os-does-when-we-use-mmap-function