What jobs OS does when we use mmap function?
Asked Answered
C

2

0

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@
Changsha answered 24/1, 2021 at 12:23 Comment(3)
OT: Please don't include line-numbers in code you show. If you want to tell us about a specific line then add a comment on that line instead and mention it in the question body.Harmaning
As for your question about how mmap works and what the OS does, it's much to broad for this QA site. To understand it properly you need to read a lot about OS internals, and how it handles memory and files.Harmaning
If this is on Linux, you should add the Linux tagCenozoic
E
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.)

Europa answered 24/1, 2021 at 14:10 Comment(3)
Thanks for the very useful answer! I understand as follows that OS first check memory and loaded pages were not in the main memory then find the file from disk. Assuming I map the device memory like GPU, not file into main memory via mmap function, I can get the correct information always in cpu-side whenever I write something into mapped memory, but we can't guarantee the consistency when modified mapped memory is actually reflected on GPU-side since we don't know when OS copy from the contents of mapped memory to GPU memory. right?Changsha
@progr: Interactions between GPU and CPU are a separate question from how operating systems handle mapping files into memory. If you want to ask about that, you should post it as a separate question so other people can answer it.Europa
Okay, Thank you :)Changsha
C
1

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)

Cenozoic answered 24/1, 2021 at 14:19 Comment(1)
Thank you for the useful references. I'll enjoyChangsha

© 2022 - 2024 — McMap. All rights reserved.