]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: (mount) support propagation by new kernel API
authorKarel Zak <kzak@redhat.com>
Mon, 26 Sep 2022 07:45:04 +0000 (09:45 +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/context.c
libmount/src/hook_mount.c
libmount/src/mountP.h
libmount/src/optlist.c

index 1cf8321c076df1ea591d06e5e32f57fba2ee79e6..e602ce54bc97996a1c7ec2cfdd4b8f6d4a242424 100644 (file)
@@ -2456,12 +2456,11 @@ int mnt_context_propagation_only(struct libmnt_context *cxt)
 
        if (cxt->action != MNT_ACT_MOUNT)
                return 0;
-
        if (cxt->mountdata || cxt->fs == NULL)
                return 0;
-
-       if ((cxt->fs->fstype && strcmp(cxt->fs->fstype, "none") != 0) ||
-           (cxt->fs->source && strcmp(cxt->fs->source, "none") == 0))
+       if (cxt->fs->fstype && strcmp(cxt->fs->fstype, "none") != 0)
+               return 0;
+       if (cxt->fs->source && strcmp(cxt->fs->source, "none") != 0)
                return 0;
 
        ls = mnt_context_get_optlist(cxt);
index abfd00ebf790e62d854fad31bfe86d2192db2c45..4cc44b8c19fc7a0e17b996a9185c543ac7334cd0 100644 (file)
@@ -140,6 +140,8 @@ static int hook_set_vfsflags(struct libmnt_context *cxt,
        uint64_t set = 0, clr = 0;
        int rc;
 
+       DBG(HOOK, ul_debugobj(hs, "setting VFS flags"));
+
        api = get_sysapi(cxt, hs);
        assert(api);
        assert(api->fd_tree >= 0);
@@ -166,10 +168,55 @@ static int hook_set_vfsflags(struct libmnt_context *cxt,
        return rc == 0 ? 0 : -errno;
 }
 
-static int hook_set_propagation(struct libmnt_context *cxt __attribute__((__unused__)),
-                       const struct libmnt_hookset *hs __attribute__((__unused__)),
+static int hook_set_propagation(struct libmnt_context *cxt,
+                       const struct libmnt_hookset *hs,
                        void *data __attribute__((__unused__)))
 {
+       struct libmnt_sysapi *api;
+       struct libmnt_optlist *ol;
+       struct libmnt_iter itr;
+       struct libmnt_opt *opt;
+       int rc = 0;
+
+       DBG(HOOK, ul_debugobj(hs, "setting propagation"));
+
+       ol = mnt_context_get_optlist(cxt);
+       if (!ol)
+               return -ENOMEM;
+
+       api = get_sysapi(cxt, hs);
+       assert(api);
+       assert(api->fd_tree >= 0);
+
+       mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+       while (mnt_optlist_next_opt(ol, &itr, &opt) == 0) {
+               const struct libmnt_optmap *map = mnt_opt_get_map(opt);
+               const struct libmnt_optmap *ent = mnt_opt_get_mapent(opt);
+               struct mount_attr attr = { .attr_clr = 0 };
+               unsigned int flgs = AT_EMPTY_PATH;
+
+               if (cxt->map_linux != map)
+                       continue;
+               if (mnt_opt_is_external(opt))
+                       continue;
+               if (!ent || !ent->id || !(ent->id & MS_PROPAGATION))
+                       continue;
+
+               attr.propagation = ent->id & MS_PROPAGATION;
+               if (ent->id & MS_REC)
+                       flgs |= AT_RECURSIVE;
+
+               DBG(HOOK, ul_debugobj(hs,
+                       "mount_setattr(propagation=0x%08" PRIx64")",
+                       (uint64_t) attr.propagation));
+
+               rc = mount_setattr(api->fd_tree, "", flgs, &attr, sizeof(attr));
+               set_syscall_status(cxt, "move_setattr", rc == 0);
+               if (rc != 0)
+                       return rc;
+       }
+
        return 0;
 }
 
@@ -210,9 +257,12 @@ static int init_sysapi(struct libmnt_context *cxt,
        assert(cxt);
        assert(hs);
 
+       DBG(HOOK, ul_debugobj(hs, "initialize API fds"));
+
        /* A) tree based operation -- the tree is mount source */
        if ((flags & MS_BIND)
            || (flags & MS_MOVE)) {
+               DBG(HOOK, ul_debugobj(hs, " BIND/MOVE"));
                path = mnt_fs_get_srcpath(cxt->fs);
                if (!path)
                        return -EINVAL;
@@ -220,6 +270,7 @@ static int init_sysapi(struct libmnt_context *cxt,
        /* B) tree based operation -- the tree is mount point */
        } else if ((flags & MS_REMOUNT)
            || mnt_context_propagation_only(cxt)) {
+               DBG(HOOK, ul_debugobj(hs, " REMOUNT/propagation"));
                path = mnt_fs_get_target(cxt->fs);
                if (!path)
                        return -EINVAL;
@@ -238,7 +289,7 @@ static int init_sysapi(struct libmnt_context *cxt,
                if (flags & MS_BIND)
                        oflg |= OPEN_TREE_CLONE;
 
-               DBG(HOOK, ul_debugobj(hs, "open_tree(%s)", path));
+               DBG(HOOK, ul_debugobj(hs, "open_tree(path=%s, flgs=0x%08lx)", path, oflg));
                if (mnt_context_is_fake(cxt))
                        goto fake;
 
@@ -249,6 +300,7 @@ static int init_sysapi(struct libmnt_context *cxt,
 
        /* C) FS based operation */
        } else {
+               DBG(HOOK, ul_debugobj(hs, " new FS"));
                const char *type = mnt_fs_get_fstype(cxt->fs);
 
                if (!type)
@@ -345,7 +397,7 @@ static int hook_prepare(struct libmnt_context *cxt,
                                        hook_attach_target);
 
        /* set propagation (has to be attached to VFS) */
-       if (!rc && mnt_optlist_get_propagation(ol) != 0)
+       if (!rc && mnt_optlist_get_propagation(ol))
                rc = mnt_context_append_hook(cxt, hs, MNT_STAGE_MOUNT_POST, NULL,
                                        hook_set_propagation);
 
index 8304d3af0ecf603f55ad14aba8cace3db39eec64..3345a14decb80dfb4f0750185e807427aca81d74 100644 (file)
@@ -557,7 +557,7 @@ extern int mnt_opt_set_external(struct libmnt_opt *opt, int enable);
 extern int mnt_opt_set_value(struct libmnt_opt *opt, const char *str);
 extern int mnt_opt_set_u64value(struct libmnt_opt *opt, uint64_t num);
 extern int mnt_opt_set_quoted_value(struct libmnt_opt *opt, const char *str);
-
+extern int mnt_opt_is_external(struct libmnt_opt *opt);
 
 /* fs.c */
 extern int mnt_fs_follow_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol);
index 939473dc56651c3ac625ebfb850c0873b252326f..dfef48fd083246d82f50862760858b5e358de1c6 100644 (file)
@@ -747,28 +747,27 @@ int mnt_optlist_get_flags(struct libmnt_optlist *ls, unsigned long *flags,
 }
 
 #ifdef UL_HAVE_MOUNT_API
-static inline uint64_t flags_to_attrs(unsigned long flags)
+static inline uint64_t flag_to_attr(unsigned long flag)
 {
-       uint64_t attrs = 0;
-
-       if (flags & MS_RDONLY)
-               attrs |= MOUNT_ATTR_RDONLY;
-       if (flags & MS_NOSUID)
-               attrs |= MOUNT_ATTR_NOSUID;
-       if (flags & MS_NOEXEC)
-               attrs |= MOUNT_ATTR_NOEXEC;
-       if (flags & MS_NODIRATIME)
-               attrs |= MOUNT_ATTR_NODIRATIME;
-       if (flags & MS_RELATIME)
-               attrs |= MOUNT_ATTR_RELATIME;
-       if (flags & MS_NOATIME)
-               attrs |= MOUNT_ATTR_NOATIME;
-       if (flags & MS_STRICTATIME)
-               attrs |= MOUNT_ATTR_STRICTATIME;
-       if (flags & MS_NOSYMFOLLOW)
-               attrs |= MOUNT_ATTR_NOSYMFOLLOW;
-
-       return attrs;
+       switch (flag) {
+       case MS_RDONLY:
+               return MOUNT_ATTR_RDONLY;
+       case MS_NOSUID:
+               return MOUNT_ATTR_NOSUID;
+       case MS_NOEXEC:
+               return MOUNT_ATTR_NOEXEC;
+       case MS_NODIRATIME:
+               return MOUNT_ATTR_NODIRATIME;
+       case MS_RELATIME:
+               return MOUNT_ATTR_RELATIME;
+       case MS_NOATIME:
+               return MOUNT_ATTR_NOATIME;
+       case MS_STRICTATIME:
+               return MOUNT_ATTR_STRICTATIME;
+       case MS_NOSYMFOLLOW:
+               return MOUNT_ATTR_NOSYMFOLLOW;
+       }
+       return 0;
 }
 #endif
 
@@ -785,24 +784,30 @@ int mnt_optlist_get_attrs(struct libmnt_optlist *ls, uint64_t *set, uint64_t *cl
        if (!ls || !ls->linux_map || !set || !clr)
                return -EINVAL;
 
+       *set = 0, *clr = 0;
        mnt_reset_iter(&itr, MNT_ITER_FORWARD);
 
        while (mnt_optlist_next_opt(ls, &itr, &opt) == 0) {
+               uint64_t x;
+
                if (ls->linux_map != opt->map)
                        continue;
                if (!opt->ent || !opt->ent->id)
                        continue;
                if (!is_wanted_opt(opt, ls->linux_map, MNT_OL_FLTR_DFLT))
                        continue;
+               x = flag_to_attr( opt->ent->id );
+               if (!x)
+                       continue;
 
                if (opt->ent->mask & MNT_INVERT)
-                       *clr |= flags_to_attrs( opt->ent->id );
+                       *clr |= x;
                else
-                       *set |= flags_to_attrs( opt->ent->id );
+                       *set |= x;
        }
 
        DBG(OPTLIST, ul_debugobj(ls, "return attrs set=0x%08" PRIx64
-                                     ", clr=0x08%" PRIx64, *set, *clr));
+                                     ", clr=0x%08" PRIx64, *set, *clr));
        return 0;
 
 #endif
@@ -922,7 +927,7 @@ int mnt_optlist_is_propagation_only(struct libmnt_optlist *ls)
                return 0;
 
        rest = flags & ~MS_PROPAGATION;
-       return (rest == 0 || rest == MS_SILENT);
+       return (rest == 0 || (rest & (MS_SILENT | MS_REC)));
 }
 
 int mnt_optlist_is_remount(struct libmnt_optlist *ls)
@@ -1032,6 +1037,10 @@ int mnt_opt_set_external(struct libmnt_opt *opt, int enable)
        return 0;
 }
 
+int mnt_opt_is_external(struct libmnt_opt *opt)
+{
+       return opt && opt->external ? 1 : 0;
+}
 
 
 #ifdef TEST_PROGRAM