Этот ответ Тома Хейла продолжает уточнять:
...it appears that the filesystem has been unmounted, but in reality it has only been hidden from the file namespace / heirarchy.
- Processes can still write via open file descriptors
- New or existing files can be opened for writing by processes with a working directory inside the mountpoint via relative pathnames
Ответ Тома действительно попал в самую точку, но повторюсь:
«Недоступно для нового доступа» просто означает, что вы не можете разрешать имена путей, которые включают точку монтирования.
Вы можете делать что угодно с точкой монтирования, кроме открытия новых файлов/каталогов по абсолютному пути .
Единственное, что вы можете быть уверены в том, что происходит после вызова 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
#include
#include
#include
#include
#include
#include
#include
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
Возможно, у вас есть повторяющиеся имена файлов? Если это так, они будут перезаписывать существующие и уменьшать общее количество файлов, попадающих в пункт назначения.
Вы можете попробовать это и посмотреть, что это вам даст, оно должно учитывать только количество уникальных базовых имен ваших найденных файлов:
find /tmp/files/test/ -type f -size -1000c -print0 | xargs -n1 -0 basename | sort | uniq | wc -l