지연 마운트 해제된 파일 시스템으로 또 무엇을 할 수 있나요?

지연 마운트 해제된 파일 시스템으로 또 무엇을 할 수 있나요?

umount --lazyumount(2)플래그를 설정하기 위한 호출입니다 MNT_DETACH.umount(2)이렇게 말하면 다음과 같습니다.

"지연된 마운트 해제 수행: 마운트 지점을 새로운 액세스에 사용할 수 없도록 만들고, 즉시 마운트 지점과 그 아래에 마운트된 모든 파일 시스템의 연결을 끊고, 마운트 지점을 더 이상 사용할 수 없도록 만듭니다. 실제 언로드는 사용 중일 때 수행됩니다.

umount(8)파일 시스템이 사용 중이라고 합니다...

예를 들어, 열린 파일이 있거나, 프로세스에 작업 디렉터리가 있거나, 스왑 파일이 사용 중일 때입니다.

그런데 "새로운 액세스가 불가능하다"는 것은 정확히 무엇을 의미합니까? 일부 응용 프로그램이 chdir(2)나중에 제거된 디렉터리에 들어가고 제대로 작동하는 것을 본 적이 있습니다 .

답변1

톰 헤일의 답변계속해서 명확하게 설명합니다.

...파일 시스템이 마운트 해제된 것처럼 보이지만 실제로는 파일 네임스페이스/계층 구조에서 숨겨져 있을 뿐입니다.

  • 프로세스는 열린 파일 설명자를 통해 계속 쓸 수 있습니다.
  • 상대 경로 이름을 사용하여 마운트 지점 내의 작업 디렉터리가 있는 프로세스에서 쓰기 위해 새 파일이나 기존 파일을 열 수 있습니다.

Tom의 답변은 정말 딱 들어맞았지만 다시 한 번 강조하자면 다음과 같습니다.

  • "새 액세스에 사용할 수 없음"은 단순히 마운트 지점이 포함된 경로 이름을 확인할 수 없음을 의미합니다.

  • 넌 할 수있어아무것새 파일/디렉토리를 여는 것 외에도 마운트 지점을 사용합니다.절대 경로를 통해.

  • 당신이 될 수 있는 유일한 것확증하다호출 후 일어나는 일은 umount(MNT_DETACH)마운트 지점 아래의 콘텐츠에 이름으로 액세스할 수 없다는 것입니다.

옵션 이름 MNT_DETACH도 이 동작을 설명합니다.마운트 포인트디렉토리 계층 구조에서 분리되지만 실제 마운트된 파일 시스템에는 아무 일도 일어나지 않습니다.


생각해 보면 이는 다소 분명하지만 현재 작업 디렉토리는 본질적으로 해당 디렉토리에 대한 열린 파일 참조이지만 커널에 의해 유지됩니다. 그러므로:

chdir("/foo");
open("./bar.txt", O_RDONLY);
동등하다
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
이는 다음과 같습니다.
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);

바인딩 해제 및 디렉터리 열기 지연에 대한 몇 가지 테스트를 수행했습니다.

  • 마운트 지점의 디렉터리를 참조하는 열린 파일 설명자가 있는 경우:
    • getdents(2)다음을 호출 하여 디렉토리 내용을 읽을 수 있습니다.
    • openat(2)해당 디렉토리에 대한 상대 경로를 사용하여 해당 디렉토리의 파일을 계속 열 수 있습니다 !

이 프로그램은 다음을 보여줍니다.

#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>

static void 
show_dir_listing(DIR *dir)
{
    printf("Listing directory (by handle):\n");
    rewinddir(dir);

    for (;;) {
        struct dirent *d;

        errno = 0;
        d = readdir(dir);
        if (d == NULL) {
            if (errno)
                error(2, errno, "readdir failed");
            break;
        }

        printf("    %s%s\n",
                d->d_name,
                (d->d_type == DT_DIR) ? "/" : "");
    }
}

int main(int argc, char **argv)
{
    const char *dirpath;
    const char *filename;
    DIR *dir;
    int fd, rc;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s DIR FILE\n",
                program_invocation_short_name);
        return 1;
    }
    dirpath = argv[1];
    filename = argv[2];

    printf("PID: %u\n", (unsigned int)getpid());

    printf("Opening handle to %s\n", dirpath);
    dir = opendir(dirpath);
    if (dir == NULL)
        error(2, errno, "opendir failed: %s", dirpath);

    show_dir_listing(dir);

    printf("\nLazy-unmounting %s\n\n", dirpath);
    rc = umount2(dirpath, MNT_DETACH);
    if (rc < 0)
        error(2, errno, "umount2 failed");

    show_dir_listing(dir);


    /* Try to open by full path name */
    {
        char path[PATH_MAX];
        path[0] = '\0';
        strcat(path, dirpath);
        strcat(path, "/");
        strcat(path, filename);

        printf("Trying to open(\"%s\")... ", path);
        fd = open(path, O_RDONLY);
        if (fd < 0) {
            printf("Failed!\n");
        }
        else {
            printf("Success: fd=%d\n", fd);
            close(fd);
        }
    }

    /* Try to openat relative to dir */
    {
        int dfd = dirfd(dir);
        printf("Trying to openat(%d, \"%s\")... ", dfd, filename);
        fd = openat(dfd, filename, O_RDONLY);
        if (fd < 0) {
            printf("Failed!\n");
        }
        else {
            printf("Success: fd=%d\n", fd);
            close(fd);
        }
    }

    return 0;
}

시험:

$ ls /tmp/to-be-bound/
bar.txt  crackle.txt  foo.txt  pop.txt  snap.txt
$ mkdir /tmp/readonly-bind
$ mount -o bind,ro /tmp/to-be-bound /tmp/readonly-bind
$ ls /tmp/readonly-bind/
bar.txt  crackle.txt  foo.txt  pop.txt  snap.txt
$ echo 'should fail' >> /tmp/readonly-bind/foo.txt 
-bash: /tmp/readonly-bind/foo.txt: Read-only file system

$ sudo ./lazytest /tmp/readonly-bind foo.txt
PID: 21160
Opening handle to /tmp/readonly-bind
Listing directory (by handle):
    ./
    ../
    pop.txt
    crackle.txt
    snap.txt
    bar.txt
    foo.txt

Lazy-unmounting /tmp/readonly-bind

Listing directory (by handle):
    ./
    ../
    pop.txt
    crackle.txt
    snap.txt
    bar.txt
    foo.txt
Trying to open("/tmp/readonly-bind/foo.txt")... Failed!
Trying to openat(3, "foo.txt")... Success: fd=4

관련 정보