]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: (subdir) use new FD based API
authorKarel Zak <kzak@redhat.com>
Tue, 18 Oct 2022 10:33:39 +0000 (12:33 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 3 Jan 2023 11:58:42 +0000 (12:58 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/hook_mount.c
libmount/src/hook_subdir.c
libmount/src/mountP.h

index 397a2aa330986d3440d98ae3637eae4789e1f114..91bb4b6f55092062c8034ca37fadd9e2e65ac3cb 100644 (file)
 
 #define get_sysapi(_cxt) mnt_context_get_sysapi(_cxt)
 
-#define set_syscall_status(_cxt, _name, _x) __extension__ ({ \
-               if (!(_x)) { \
-                       DBG(HOOK, ul_debug("syscall '%s' [%m]", _name)); \
-                       (_cxt)->syscall_status = -errno; \
-                       (_cxt)->syscall_name = (_name); \
-               } else { \
-                       DBG(HOOK, ul_debug("syscall '%s' [succes]", _name)); \
-                       (_cxt)->syscall_status = 0; \
-               } \
-       })
-
-
 /*
  * This hookset uses 'struct libmnt_sysapi' (mountP.h) as hookset data.
  */
index d0a274bc70c252cc95bb41400ab0a17734dc425b..74120f6d74fb252aed8b9c5abef0483690cd83da 100644 (file)
@@ -147,25 +147,71 @@ static int tmptgt_cleanup(int old_ns_fd)
 #endif
 }
 
-static int do_mount_subdir(const char *root,
-                          const char *subdir,
-                          const char *target)
+static int do_mount_subdir(
+                       struct libmnt_context *cxt,
+                       const char *root,
+                       const char *subdir,
+                       const char *target)
 {
-       char *src = NULL;
        int rc = 0;
 
-       if (asprintf(&src, "%s/%s", root, subdir) < 0)
-               return -ENOMEM;
+#ifdef UL_HAVE_MOUNT_API
+       struct libmnt_sysapi *api;
+
+       api = mnt_context_get_sysapi(cxt);
+       if (api) {
+               /* FD based way - unfortunately, it's impossible to open
+                * sub-directory on not-yet attached mount. It means hook_mount.c
+                * attaches to FS to temporary directory, and we clone
+                * and move the subdir, and umount the old temporary tree.
+                *
+                * The old mount(2) way does the same, but by BIND.
+                */
+               int fd;
+
+               DBG(HOOK, ul_debug("attach subdir  %s", subdir));
+               fd = open_tree(api->fd_tree, subdir,
+                                       OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
+               set_syscall_status(cxt, "open_tree", fd >= 0);
+               if (fd < 0)
+                       rc = -errno;
+
+               if (!rc) {
+                       rc = move_mount(fd, "", AT_FDCWD, target, MOVE_MOUNT_F_EMPTY_PATH);
+                       set_syscall_status(cxt, "move_mount", rc == 0);
+                       if (rc)
+                               rc = -errno;
+               }
+               if (!rc) {
+                       close(api->fd_tree);
+                       api->fd_tree = fd;
+               }
+       } else
+#endif
+       {
+               char *src = NULL;
+
+               if (asprintf(&src, "%s/%s", root, subdir) < 0)
+                       return -ENOMEM;
+
+               /* Classic mount(2) based way */
+               DBG(HOOK, ul_debug("mount subdir %s to %s", src, target));
+               rc = mount(src, target, NULL, MS_BIND, NULL);
 
-       DBG(HOOK, ul_debug("mount subdir %s to %s", src, target));
-       if (mount(src, target, NULL, MS_BIND | MS_REC, NULL) != 0)
-               rc = -MNT_ERR_APPLYFLAGS;
+               set_syscall_status(cxt, "mount", rc == 0);
+               if (rc)
+                       rc = -errno;
+               free(src);
+       }
 
-       DBG(HOOK, ul_debug("umount old root %s", root));
-       if (umount(root) != 0)
-               rc = -MNT_ERR_APPLYFLAGS;
+       if (!rc) {
+               DBG(HOOK, ul_debug("umount old root %s", root));
+               rc = umount(root);
+               set_syscall_status(cxt, "umount", rc == 0);
+               if (rc)
+                       rc = -errno;
+       }
 
-       free(src);
        return rc;
 }
 
@@ -186,7 +232,7 @@ static int hook_mount_post(
        mnt_fs_set_target(cxt->fs, hsd->org_target);
 
        /* bind subdir to the real target, umount temporary target */
-       rc = do_mount_subdir(MNT_PATH_TMPTGT,
+       rc = do_mount_subdir(cxt, MNT_PATH_TMPTGT,
                        hsd->subdir,
                        mnt_fs_get_target(cxt->fs));
        if (rc)
index 1c7f579acaa6f380a9851727f0128ea415c7173f..d2fced092d9c94bd513147a9ccb02b16ce60fa5f 100644 (file)
@@ -463,6 +463,17 @@ struct libmnt_context
 /* Flags usable with MS_BIND|MS_REMOUNT */
 #define MNT_BIND_SETTABLE      (MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_NOATIME|MS_NODIRATIME|MS_RELATIME|MS_RDONLY|MS_NOSYMFOLLOW)
 
+#define set_syscall_status(_cxt, _name, _x) __extension__ ({ \
+               if (!(_x)) { \
+                       DBG(CXT, ul_debug("syscall '%s' [%m]", _name)); \
+                       (_cxt)->syscall_status = -errno; \
+                       (_cxt)->syscall_name = (_name); \
+               } else { \
+                       DBG(CXT, ul_debug("syscall '%s' [succes]", _name)); \
+                       (_cxt)->syscall_status = 0; \
+               } \
+       })
+
 /* optmap.c */
 extern const struct libmnt_optmap *mnt_optmap_get_entry(
                             struct libmnt_optmap const **maps,