What can still be done with a lazy-unmounted filesystem?
umount --lazy
calls umount(2)
with the MNT_DETACH
flag set. umount(2)
says that will:
"Perform a lazy unmount: make the mount point unavailable for new accesses, immediately disconnect the filesystem and all filesystems mounted below it from each other and from the mount table, and actually perform the unmount when the mount point ceases to be busy.
umount(8)
says that a file system is busy...
for example, when there are open files on it, or when some process has its working directory there, or when a swap file on it is in use.
But what exactly does "unavailable for new access" mean? I've seen applications that chdir(2)
into a directory which is subsequently unmounted, and they behave just fine.
linux unmounting
add a comment |
umount --lazy
calls umount(2)
with the MNT_DETACH
flag set. umount(2)
says that will:
"Perform a lazy unmount: make the mount point unavailable for new accesses, immediately disconnect the filesystem and all filesystems mounted below it from each other and from the mount table, and actually perform the unmount when the mount point ceases to be busy.
umount(8)
says that a file system is busy...
for example, when there are open files on it, or when some process has its working directory there, or when a swap file on it is in use.
But what exactly does "unavailable for new access" mean? I've seen applications that chdir(2)
into a directory which is subsequently unmounted, and they behave just fine.
linux unmounting
add a comment |
umount --lazy
calls umount(2)
with the MNT_DETACH
flag set. umount(2)
says that will:
"Perform a lazy unmount: make the mount point unavailable for new accesses, immediately disconnect the filesystem and all filesystems mounted below it from each other and from the mount table, and actually perform the unmount when the mount point ceases to be busy.
umount(8)
says that a file system is busy...
for example, when there are open files on it, or when some process has its working directory there, or when a swap file on it is in use.
But what exactly does "unavailable for new access" mean? I've seen applications that chdir(2)
into a directory which is subsequently unmounted, and they behave just fine.
linux unmounting
umount --lazy
calls umount(2)
with the MNT_DETACH
flag set. umount(2)
says that will:
"Perform a lazy unmount: make the mount point unavailable for new accesses, immediately disconnect the filesystem and all filesystems mounted below it from each other and from the mount table, and actually perform the unmount when the mount point ceases to be busy.
umount(8)
says that a file system is busy...
for example, when there are open files on it, or when some process has its working directory there, or when a swap file on it is in use.
But what exactly does "unavailable for new access" mean? I've seen applications that chdir(2)
into a directory which is subsequently unmounted, and they behave just fine.
linux unmounting
linux unmounting
edited 21 mins ago
Tom Hale
6,66533592
6,66533592
asked 2 days ago
Jonathon ReinhartJonathon Reinhart
8301918
8301918
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
This answer by Tom Hale goes on to clarify:
...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
Tom's answer really hit the nail on the head, but to reiterate:
"Unavailable for new access" simply means you cannot resolve path names that include the mountpoint.
You can do anything with the mountpoint, except open new files/directories by absolute path.
The only thing you can be certain that happens after calling
umount(MNT_DETACH)
is that the below the mountpoint are inaccessible by name.
The option name MNT_DETACH
even explains this behavior: The mountpoint is detached from the directory hierarchy, but nothing about the actual mounted filesystem is guaranteed to have happened.
It's somewhat obvious when you think about it, but the current working directory is essentially an open file reference to that directory, but maintained by the kernel. Thus:
chdir("/foo");
open("./bar.txt", O_RDONLY);
is equivalent to
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
which is equivalent to
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);
I did some tests regarding lazy unbinding and open directories:
- If you have an open file descriptor referencing a directory on the mountpoint:
- You can still call
getdents(2)
to read the directory contents - You can still use
openat(2)
to open files underneath that directory, using their path relative to it!
- You can still call
This program demonstrates:
#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%sn",
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 FILEn",
program_invocation_short_name);
return 1;
}
dirpath = argv[1];
filename = argv[2];
printf("PID: %un", (unsigned int)getpid());
printf("Opening handle to %sn", dirpath);
dir = opendir(dirpath);
if (dir == NULL)
error(2, errno, "opendir failed: %s", dirpath);
show_dir_listing(dir);
printf("nLazy-unmounting %snn", 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] = '';
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=%dn", 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=%dn", fd);
close(fd);
}
}
return 0;
}
Testing:
$ 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
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f493602%2fwhat-can-still-be-done-with-a-lazy-unmounted-filesystem%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
This answer by Tom Hale goes on to clarify:
...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
Tom's answer really hit the nail on the head, but to reiterate:
"Unavailable for new access" simply means you cannot resolve path names that include the mountpoint.
You can do anything with the mountpoint, except open new files/directories by absolute path.
The only thing you can be certain that happens after calling
umount(MNT_DETACH)
is that the below the mountpoint are inaccessible by name.
The option name MNT_DETACH
even explains this behavior: The mountpoint is detached from the directory hierarchy, but nothing about the actual mounted filesystem is guaranteed to have happened.
It's somewhat obvious when you think about it, but the current working directory is essentially an open file reference to that directory, but maintained by the kernel. Thus:
chdir("/foo");
open("./bar.txt", O_RDONLY);
is equivalent to
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
which is equivalent to
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);
I did some tests regarding lazy unbinding and open directories:
- If you have an open file descriptor referencing a directory on the mountpoint:
- You can still call
getdents(2)
to read the directory contents - You can still use
openat(2)
to open files underneath that directory, using their path relative to it!
- You can still call
This program demonstrates:
#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%sn",
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 FILEn",
program_invocation_short_name);
return 1;
}
dirpath = argv[1];
filename = argv[2];
printf("PID: %un", (unsigned int)getpid());
printf("Opening handle to %sn", dirpath);
dir = opendir(dirpath);
if (dir == NULL)
error(2, errno, "opendir failed: %s", dirpath);
show_dir_listing(dir);
printf("nLazy-unmounting %snn", 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] = '';
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=%dn", 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=%dn", fd);
close(fd);
}
}
return 0;
}
Testing:
$ 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
add a comment |
This answer by Tom Hale goes on to clarify:
...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
Tom's answer really hit the nail on the head, but to reiterate:
"Unavailable for new access" simply means you cannot resolve path names that include the mountpoint.
You can do anything with the mountpoint, except open new files/directories by absolute path.
The only thing you can be certain that happens after calling
umount(MNT_DETACH)
is that the below the mountpoint are inaccessible by name.
The option name MNT_DETACH
even explains this behavior: The mountpoint is detached from the directory hierarchy, but nothing about the actual mounted filesystem is guaranteed to have happened.
It's somewhat obvious when you think about it, but the current working directory is essentially an open file reference to that directory, but maintained by the kernel. Thus:
chdir("/foo");
open("./bar.txt", O_RDONLY);
is equivalent to
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
which is equivalent to
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);
I did some tests regarding lazy unbinding and open directories:
- If you have an open file descriptor referencing a directory on the mountpoint:
- You can still call
getdents(2)
to read the directory contents - You can still use
openat(2)
to open files underneath that directory, using their path relative to it!
- You can still call
This program demonstrates:
#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%sn",
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 FILEn",
program_invocation_short_name);
return 1;
}
dirpath = argv[1];
filename = argv[2];
printf("PID: %un", (unsigned int)getpid());
printf("Opening handle to %sn", dirpath);
dir = opendir(dirpath);
if (dir == NULL)
error(2, errno, "opendir failed: %s", dirpath);
show_dir_listing(dir);
printf("nLazy-unmounting %snn", 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] = '';
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=%dn", 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=%dn", fd);
close(fd);
}
}
return 0;
}
Testing:
$ 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
add a comment |
This answer by Tom Hale goes on to clarify:
...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
Tom's answer really hit the nail on the head, but to reiterate:
"Unavailable for new access" simply means you cannot resolve path names that include the mountpoint.
You can do anything with the mountpoint, except open new files/directories by absolute path.
The only thing you can be certain that happens after calling
umount(MNT_DETACH)
is that the below the mountpoint are inaccessible by name.
The option name MNT_DETACH
even explains this behavior: The mountpoint is detached from the directory hierarchy, but nothing about the actual mounted filesystem is guaranteed to have happened.
It's somewhat obvious when you think about it, but the current working directory is essentially an open file reference to that directory, but maintained by the kernel. Thus:
chdir("/foo");
open("./bar.txt", O_RDONLY);
is equivalent to
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
which is equivalent to
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);
I did some tests regarding lazy unbinding and open directories:
- If you have an open file descriptor referencing a directory on the mountpoint:
- You can still call
getdents(2)
to read the directory contents - You can still use
openat(2)
to open files underneath that directory, using their path relative to it!
- You can still call
This program demonstrates:
#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%sn",
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 FILEn",
program_invocation_short_name);
return 1;
}
dirpath = argv[1];
filename = argv[2];
printf("PID: %un", (unsigned int)getpid());
printf("Opening handle to %sn", dirpath);
dir = opendir(dirpath);
if (dir == NULL)
error(2, errno, "opendir failed: %s", dirpath);
show_dir_listing(dir);
printf("nLazy-unmounting %snn", 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] = '';
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=%dn", 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=%dn", fd);
close(fd);
}
}
return 0;
}
Testing:
$ 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
This answer by Tom Hale goes on to clarify:
...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
Tom's answer really hit the nail on the head, but to reiterate:
"Unavailable for new access" simply means you cannot resolve path names that include the mountpoint.
You can do anything with the mountpoint, except open new files/directories by absolute path.
The only thing you can be certain that happens after calling
umount(MNT_DETACH)
is that the below the mountpoint are inaccessible by name.
The option name MNT_DETACH
even explains this behavior: The mountpoint is detached from the directory hierarchy, but nothing about the actual mounted filesystem is guaranteed to have happened.
It's somewhat obvious when you think about it, but the current working directory is essentially an open file reference to that directory, but maintained by the kernel. Thus:
chdir("/foo");
open("./bar.txt", O_RDONLY);
is equivalent to
chdir("/foo");
openat(AT_FDCWD, "bar.txt", O_RDONLY);
which is equivalent to
int dirfd = open("/foo", O_RDONLY | O_DIRECTORY);
openat(dirfd, "bar.txt", O_RDONLY);
I did some tests regarding lazy unbinding and open directories:
- If you have an open file descriptor referencing a directory on the mountpoint:
- You can still call
getdents(2)
to read the directory contents - You can still use
openat(2)
to open files underneath that directory, using their path relative to it!
- You can still call
This program demonstrates:
#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%sn",
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 FILEn",
program_invocation_short_name);
return 1;
}
dirpath = argv[1];
filename = argv[2];
printf("PID: %un", (unsigned int)getpid());
printf("Opening handle to %sn", dirpath);
dir = opendir(dirpath);
if (dir == NULL)
error(2, errno, "opendir failed: %s", dirpath);
show_dir_listing(dir);
printf("nLazy-unmounting %snn", 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] = '';
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=%dn", 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=%dn", fd);
close(fd);
}
}
return 0;
}
Testing:
$ 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
edited 2 days ago
answered 2 days ago
Jonathon ReinhartJonathon Reinhart
8301918
8301918
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f493602%2fwhat-can-still-be-done-with-a-lazy-unmounted-filesystem%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown