Home > Mobile >  What happens if you try to read/write a mapping with a deleted / disconnected backing file or device
What happens if you try to read/write a mapping with a deleted / disconnected backing file or device

Time:04-30

If I perform a mmap() on some file or a device in /dev/ that exposes memory, what happens to that mapping if the file is deleted or that device disconnected?

I've written a test program to experiment but I can't find any solid documentation on what should happen. The test program does the following

#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main()
{
    int fd = open("test_file", O_CREAT | O_RDWR);

    uint32_t data[10000] = {0};
    data[3] = 22;
    write(fd, data, sizeof data);
    sync();
    
    struct stat s;
    fstat(fd, &s);
    
    uint32_t *map = (uint32_t *)mmap(NULL, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    
    sleep(10);
    
    printf("%u\n", *(map 3));
    *(map 9000) = 91;
    printf("%u\n", *(map 9000));

    return 0;
}

My page size is 4096 bytes so I made the file larger than that so the map would span multiple pages. During that 10s sleep I run the following commands:

$ rm test_file
$ sync; echo 3 > /proc/sys/vm/drop_caches

Which I believe should destroy the backing file of the map and remove all pages so that it must seek the backing file out to perform any operations on it. Then after that 10s sleep the program attempts to read from page 1 and w/r to page 3.

Surprisingly the 2 values I get printed back out are 22 and 91

Why does this happen, is this behavior guaranteed or undefined? Is it because I was using a regular file and not a device? What if the mapping was really large, would things change? Should I expect to get a SIGSEGV or a SIGBUS under some conditions?

CodePudding user response:

rm just unlinks the file from a location in the filesystem (removes it from a directory). If there are other references to the file (such as a process that has it open), the file won't actually be removed -- the OS keeps a reference count of all the references to the file and only deletes it when the reference count drop to 0.

So in this case, the reference count will still be non-zero after the rm as the process has the file open. Only when the files is unmapped and closed (which happens when the process exits) will the file actually be deleted.

In the case of a device, the device file (in the filesystem) is similarly just a reference to the device driver. Removing it won't have any effect. However, if the device itself has some concept of being removed (such as removable storage), doing that will result in future access returning some error.

CodePudding user response:

What happens if you try to read/write a mapping with a deleted ... file

You will still write to that file. rm only unlinks the name from the directory, the file still exists.

disconnected backing ... device?

The process will receive a SIGBUS signal.

Why does this happen, is this behavior guaranteed or undefined?

Guaranteed, files keep reference count since always.

Is it because I was using a regular file and not a device?

No. A device kind of is a regular file. You can open("/dev/sda" and write to it and rm /dev/sda. In Linux almost everything is a regular file. A file has only one more layer of indirection in kernel - a filesystem.

What if the mapping was really large, would things change?

Should I expect to get a SIGSEGV or a SIGBUS under some conditions?

See man mmap. Search for SIGBUS.

  • Related