_umount --lazy
_は、_MNT_DETACH
_フラグを設定してumount(2)
を呼び出します。 umount(2)
は次のようになります。
「レイジーアンマウントを実行します。マウントポイントを新しいアクセスに使用できないようにし、ファイルシステムとその下にマウントされているすべてのファイルシステムを相互におよびマウントテーブルからすぐに切断し、マウントポイントがビジー状態でなくなったときに実際にアンマウントを実行します。
umount(8)
は、ファイルシステムがビジーであることを示しています。
たとえば、開いているファイルがある場合、プロセスの作業ディレクトリがそこにある場合、またはスワップファイルが使用されている場合です。
しかし、「新しいアクセスに利用できない」とは正確にはどういう意味ですか?ディレクトリにchdir(2)
して、後でマウント解除されるアプリケーションを見たことがありますが、それらは問題なく動作します。
Tom Haleによるこの回答 さらに明確にします:
...ファイルシステムがマウント解除されているように見えますが、実際には、ファイルの名前空間/階層からのみ非表示になっています。
- プロセスは、開いているファイル記述子を介して引き続き書き込むことができます
- 新規または既存のファイルは、相対パス名を介してマウントポイント内の作業ディレクトリを持つプロセスによって書き込み用に開くことができます
トムの答えは本当に頭に釘を打ちましたが、繰り返します:
「新しいアクセスに使用できません」とは、マウントポイントを含むパス名を解決できないことを意味します。
新しいファイル/ディレクトリを開くことを除いて、マウントポイントで何でもできます絶対パスで。
umount(MNT_DETACH)
を呼び出した後に発生する可能性があるのは、certainだけです。これは、マウントポイントの下に名前でアクセスできないことです。
オプション名_MNT_DETACH
_は、この動作についても説明しています。mountpointはディレクトリ階層から切り離されていますが、実際にマウントされたファイルシステムについては何も起こらないことが保証されています。
考えてみると明らかですが、現在の作業ディレクトリは基本的にそのディレクトリへのオープンファイル参照ですが、カーネルによって維持されています。したがって:
_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
_