What can still be done with a lazy-unmounted filesystem?












4















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.










share|improve this question





























    4















    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.










    share|improve this question



























      4












      4








      4








      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.










      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 21 mins ago









      Tom Hale

      6,66533592




      6,66533592










      asked 2 days ago









      Jonathon ReinhartJonathon Reinhart

      8301918




      8301918






















          1 Answer
          1






          active

          oldest

          votes


















          3














          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!






          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





          share|improve this answer

























            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
            });


            }
            });














            draft saved

            draft discarded


















            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









            3














            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!






            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





            share|improve this answer






























              3














              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!






              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





              share|improve this answer




























                3












                3








                3







                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!






                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





                share|improve this answer















                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!






                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






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 2 days ago

























                answered 2 days ago









                Jonathon ReinhartJonathon Reinhart

                8301918




                8301918






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Accessing regular linux commands in Huawei's Dopra Linux

                    Can't connect RFCOMM socket: Host is down

                    Kernel panic - not syncing: Fatal Exception in Interrupt