mmap() после удаления файла

Мне сказали, что у mmap () могут возникнуть проблемы, если кто-то удалит исходный файл. Мне было интересно, если это действительно происходит. Итак, я создал небольшую тестовую программу. Я использую Linux.

#include <iostream>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int, char**)
{
    char const * const fileName = "/tmp/demo-file.dat";
    size_t size;

    {
        struct stat st;
        stat(fileName, &st);
        size = st.st_size;
    }

    int fd = open(fileName, O_RDWR);
    if (fd == -1)
    {
        std::cout << "open() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
        return (-1);
    }
    else
    {
        std::cout << "open() done (ok)" << std::endl;
    }

    for (int i = 20; i > 0; --i)
    {
        std::cout << "file open()'ed, wait #" << i << " seconds before mmap()" << std::endl;
        sleep(1);
    }

    void *data = mmap((void*)0L, size, PROT_READ, MAP_SHARED, fd, (off_t)0);
    if (data == (void*)-1)
    {
        std::cout << "mmap() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
    }
    else
    {
        std::cout << "mmap() done (ok)" << std::endl;
    }

    for (int i = 20; i > 0; --i)
    {
        std::cout << "going to close() socket in #" << i << " seconds" << std::endl;
        sleep (1);
    }

    close(fd);

    for (int i = 30; i > 0; --i)
    {
        std::cout << "going to umap() files in #" << i << " seconds (still accessing the data)" << std::endl;
        for (unsigned int x = 0; x < size; ++x)
        {
            char cp = *(char*) (data + x);
            (void) cp;
        }
        sleep(1);
    }

    munmap(data, size);

    for (int i = 30; i > 0; --i)
    {
        std::cout << "going to terminate #" << i << " seconds" << std::endl;
        sleep(1);
    }

    return 0;
}

Всякий раз, когда я удаляю файл - после операции open () - он не оказывает негативного влияния на mmap (). Я все еще могу получить доступ к данным в тестовой программе. Когда я удаляю файл сразу после close (), но до mmap (), он работает. Я также все еще вижу старый файл в /proc/[pid]/fd/ area:

lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)

Остальная часть программы работает.

Даже когда я удаляю файл после close (), он все равно успешно обращается к данным mmap (). Однако в обоих случаях после закрытия () я не вижу

lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)

больше. (кстати: где тогда отмечается, что этот файл "все еще существует как-то"?)

Значит, наоборот, что гарантировано, что mmap () все еще сможет работать с данными, даже если файл был удален вручную (в оболочке или каким-либо другим процессом)?

1 ответ

Вот что происходит.

Первое, что нужно проверить, это

$ls -i /tmp/demo-file.dat
65 /tmp/demo-file.dat

Обратите внимание на номер индекса файла 65.

При запуске программы, вот что у нее есть lsof вывод (кроме других записей, не относящихся к текущему дискурсу)

a.out   29271 ichakrab    3u   REG   0,21        5       65 /tmp/demo-file.dat

Это результат open() это было сделано. Обратите внимание, что номер индекса совпадает с другим файлом. open() увеличил количество ссылок на тот же индекс. Также обратите внимание, что REG указывает на обычный файл.

Теперь, если файл удален (используя rm и т.д.), вот что lsof похоже

a.out   29271 ichakrab    3u   REG   0,21        5       65 /tmp/demo-file.dat (deleted)

Это ожидаемо, так как открытый файл был удален, но дескриптор его inode все еще открыт в процессе.

Переходя к Mmap, и вот lsof выход

a.out   29271 ichakrab  DEL    REG   0,21                65 /tmp/demo-file.dat
a.out   29271 ichakrab    3u   REG   0,21        5       65 /tmp/demo-file.dat (deleted)

Теперь есть еще одна новая запись, но обратите внимание, что это типа DEL который указывает (снятие со страницы руководства lsof):

'' DEL '' для файла карты Linux, который был удален;

поскольку lsof больше не может определить исходный файл, он отображает это отображение как DEL конечно, без размера, но обратите внимание, что номер инода остается тем же, 65.

Теперь после close() был вызван на FD вот что lsof шоу

a.out   29271 ichakrab  DEL    REG   0,21                65 /tmp/demo-file.dat

Обратите внимание, что (deleted) вход ушел, так как это FD к REG файл был закрыт, и теперь остается только память mmap.

После munmap() эта запись тоже пропала (больше нет ссылок на /tmp/demo-file.dat и наконец программа заканчивается.

Другие вопросы по тегам