]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: keep context fs and optlist synchronized
authorKarel Zak <kzak@redhat.com>
Wed, 24 Aug 2022 14:54:10 +0000 (16:54 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 3 Jan 2023 11:58:42 +0000 (12:58 +0100)
The new code uses cxt->optlist to maintain mount options, but for backward
compatibility and for some stuff in the library we need to keep context->fs
up to date with the optlist. It seems the best is to to keep it on-demand
and automatic.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/context_mount.c
libmount/src/fs.c
libmount/src/mountP.h
libmount/src/optlist.c

index a679a8029630f7dd0550be6c248e35b6c2a34d3b..743c77a05ac9922740a8501db1cad243c92c1ab1 100644 (file)
@@ -49,7 +49,6 @@ static int fix_optstr(struct libmnt_context *cxt)
        struct libmnt_optlist *ol;
        struct libmnt_opt *opt;
        struct libmnt_ns *ns_old;
-       struct libmnt_fs *fs;
        const char *val;
        int rc = 0;
 #ifdef HAVE_LIBSELINUX
@@ -61,8 +60,6 @@ static int fix_optstr(struct libmnt_context *cxt)
        if (cxt->flags & MNT_FL_MOUNTOPTS_FIXED)
                return 0;
 
-       fs = cxt->fs;
-
        DBG(CXT, ul_debugobj(cxt, "--> preparing options"));
 
        ol = mnt_context_get_optlist(cxt);
@@ -202,32 +199,6 @@ static int fix_optstr(struct libmnt_context *cxt)
        }
 #endif
        mnt_context_call_hooks(cxt, MNT_STAGE_PREP_OPTIONS);
-
-       /* For backward compatinility update context fs mount options */
-       if (fs) {
-               const char *p;
-
-               /* All options */
-               mnt_optlist_get_optstr(ol, &p, NULL, 0);
-               strdup_to_struct_member(fs, optstr, p);
-
-               /* FS options */
-               mnt_optlist_get_optstr(ol, &p, NULL, MNT_OL_FLTR_UNKNOWN);
-               strdup_to_struct_member(fs, fs_optstr, p);
-
-               /* VFS options */
-               mnt_optlist_get_optstr(ol, &p, cxt->map_linux, 0);
-               strdup_to_struct_member(fs, vfs_optstr, p);
-
-               /* Userspace options */
-               mnt_optlist_get_optstr(ol, &p, cxt->map_userspace, 0);
-               strdup_to_struct_member(fs, user_optstr, p);
-
-               DBG(CXT, ul_debugobj(cxt, " fixed options: "
-                       "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'",
-                       fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr));
-       }
-
 done:
        DBG(CXT, ul_debugobj(cxt, "<-- preparing options done [rc=%d]", rc));
        cxt->flags |= MNT_FL_MOUNTOPTS_FIXED;
@@ -820,6 +791,8 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt)
        rc = mnt_context_apply_fstab(cxt);
        if (!rc)
                rc = mnt_context_merge_mflags(cxt);
+       if (!rc && cxt->fs && cxt->optlist)
+               rc = mnt_fs_follow_optlist(cxt->fs, cxt->optlist);
        if (!rc)
                rc = evaluate_permissions(cxt);
        if (!rc)
index 46a22c75a7b6f86bb8248eef6a1697a1ef41403d..c7858898a40f17db2587768315ae1d63e6f58221 100644 (file)
@@ -59,6 +59,8 @@ void mnt_free_fs(struct libmnt_fs *fs)
 
        DBG(FS, ul_debugobj(fs, "free [refcount=%d]", fs->refcount));
 
+       mnt_unref_optlist(fs->optlist);
+
        mnt_reset_fs(fs);
        free(fs);
 }
@@ -95,6 +97,8 @@ void mnt_reset_fs(struct libmnt_fs *fs)
        free(fs->opt_fields);
        free(fs->comment);
 
+       fs->opts_age = 0;
+
        memset(fs, 0, sizeof(*fs));
        INIT_LIST_HEAD(&fs->ents);
        fs->refcount = ref;
@@ -166,6 +170,63 @@ static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
        return update_str(n, *o);
 }
 
+static inline int sync_opts_from_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol)
+{
+       unsigned int age = mnt_optlist_get_age(ol);
+
+       if (age != fs->opts_age) {
+               const char *p;
+               int rc;
+
+               /* All options */
+               rc = mnt_optlist_get_optstr(ol, &p, NULL, 0);
+               if (!rc)
+                       rc = strdup_to_struct_member(fs, optstr, p);
+
+               /* FS options */
+               if (!rc)
+                       rc = mnt_optlist_get_optstr(ol, &p, NULL, MNT_OL_FLTR_UNKNOWN);
+               if (!rc)
+                       rc = strdup_to_struct_member(fs, fs_optstr, p);
+
+               /* VFS options */
+               if (!rc)
+                       rc = mnt_optlist_get_optstr(ol, &p, mnt_get_builtin_optmap(MNT_LINUX_MAP), 0);
+               if (!rc)
+                       rc = strdup_to_struct_member(fs, vfs_optstr, p);
+
+               /* Userspace options */
+               if (!rc)
+                       rc = mnt_optlist_get_optstr(ol, &p, mnt_get_builtin_optmap(MNT_USERSPACE_MAP), 0);
+               if (!rc)
+                       rc = strdup_to_struct_member(fs, user_optstr, p);
+
+               if (rc) {
+                       DBG(FS, ul_debugobj(fs, "sync failed [rc=%d]", rc));
+                       return rc;
+               } else {
+                       DBG(FS, ul_debugobj(fs, "synced: "
+                               "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'",
+                               fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr));
+                       fs->opts_age = age;
+               }
+       }
+       return 0;
+}
+
+/* If @optlist is not NULL then @fs will read all option strings from @optlist.
+ * It means that mnt_fs_get_*_options() won't be read-only operations. */
+int mnt_fs_follow_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol)
+{
+       if (fs->optlist == ol)
+               return 0;
+
+       fs->opts_age = 0;
+       fs->optlist = ol;
+       mnt_ref_optlist(ol);
+       return 0;
+}
+
 /**
  * mnt_copy_fs:
  * @dest: destination FS
@@ -233,6 +294,10 @@ struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
        dest->usedsize   = src->usedsize;
        dest->priority   = src->priority;
 
+       dest->opts_age   = src->opts_age;
+       dest->optlist    = src->optlist;
+       mnt_ref_optlist(dest->optlist);
+
        return dest;
 err:
        if (!org)
@@ -247,13 +312,15 @@ err:
  *
  * Returns: copy of @fs.
  */
-struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs)
+struct libmnt_fs *mnt_copy_mtab_fs(struct libmnt_fs *fs)
 {
        struct libmnt_fs *n = mnt_new_fs();
 
        assert(fs);
        if (!n)
                return NULL;
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
 
        if (strdup_between_structs(n, fs, source))
                goto err;
@@ -786,6 +853,8 @@ char *mnt_fs_strdup_options(struct libmnt_fs *fs)
 
        if (!fs)
                return NULL;
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
 
        errno = 0;
        if (fs->optstr)
@@ -810,6 +879,9 @@ char *mnt_fs_strdup_options(struct libmnt_fs *fs)
  */
 const char *mnt_fs_get_options(struct libmnt_fs *fs)
 {
+       if (fs && fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        return fs ? fs->optstr : NULL;
 }
 
@@ -841,6 +913,8 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
 
        if (!fs)
                return -EINVAL;
+       fs->opts_age = 0;
+
        if (optstr) {
                int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
                if (rc)
@@ -889,6 +963,8 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
        if (!optstr)
                return 0;
 
+       fs->opts_age = 0;
+
        rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
        if (rc)
                return rc;
@@ -931,6 +1007,8 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
        if (!optstr)
                return 0;
 
+       fs->opts_age = 0;
+
        rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
        if (rc)
                return rc;
@@ -951,7 +1029,8 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
        return rc;
 }
 
-/*
+
+/**
  * mnt_fs_get_fs_options:
  * @fs: fstab/mtab/mountinfo entry pointer
  *
@@ -959,6 +1038,9 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
  */
 const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
 {
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        return fs ? fs->fs_optstr : NULL;
 }
 
@@ -970,6 +1052,9 @@ const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
  */
 const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs)
 {
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        return fs ? fs->vfs_optstr : NULL;
 }
 
@@ -1013,6 +1098,9 @@ char *mnt_fs_get_vfs_options_all(struct libmnt_fs *fs)
  */
 const char *mnt_fs_get_user_options(struct libmnt_fs *fs)
 {
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        return fs ? fs->user_optstr : NULL;
 }
 
@@ -1303,6 +1391,10 @@ int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
 
        if (!fs)
                return -EINVAL;
+
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        if (fs->fs_optstr)
                rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz);
        if (rc == 1 && fs->vfs_optstr)
@@ -1552,6 +1644,10 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
 {
        if (!fs || !file)
                return -EINVAL;
+
+       if (fs->optlist)
+               sync_opts_from_optlist(fs, fs->optlist);
+
        fprintf(file, "------ fs:\n");
        fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
        fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
index 902f511289c47c695ac3619348b530ce202d7f8e..dac5336b35e51ff7b326cb2715f13ee8927a0b45 100644 (file)
@@ -190,6 +190,10 @@ struct libmnt_fs {
        struct libmnt_table *tab;
 
        int             refcount;       /* reference counter */
+
+       unsigned int    opts_age;       /* to sync with optlist */
+       struct libmnt_optlist *optlist;
+
        int             id;             /* mountinfo[1]: ID */
        int             parent;         /* mountinfo[2]: parent */
        dev_t           devno;          /* mountinfo[3]: st_dev */
@@ -480,6 +484,7 @@ struct libmnt_optlist;
 extern struct libmnt_optlist *mnt_new_optlist(void);
 extern void mnt_ref_optlist(struct libmnt_optlist *ls);
 extern void mnt_unref_optlist(struct libmnt_optlist *ls);
+extern unsigned int mnt_optlist_get_age(struct libmnt_optlist *ls);
 extern int mnt_optlist_register_map(struct libmnt_optlist *ls, const struct libmnt_optmap *map);
 extern int mnt_optlist_remove_opt(struct libmnt_optlist *ls, struct libmnt_opt *opt);
 extern int mnt_optlist_remove_named(struct libmnt_optlist *ls, const char *name,
@@ -552,7 +557,8 @@ extern int mnt_opt_set_quoted_value(struct libmnt_opt *opt, const char *str);
 
 
 /* fs.c */
-extern struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs);
+extern int mnt_fs_follow_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol);
+extern struct libmnt_fs *mnt_copy_mtab_fs(struct libmnt_fs *fs);
 extern int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
                        __attribute__((nonnull(1)));
 extern int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
index a81295e1ac34e9e6fe145604862d6960e47c85fb..875cad058f5f482736892878234a12117dfca8d6 100644 (file)
@@ -40,6 +40,7 @@ struct libmnt_opt {
 
 struct libmnt_optlist {
        int refcount;
+       unsigned int age;                       /* incremented after each change */
 
        const struct libmnt_optmap      *linux_map;     /* map with MS_ flags */
        const struct libmnt_optmap      *maps[MNT_OL_MAXMAPS];
@@ -145,6 +146,8 @@ static void optlist_cleanup_cache(struct libmnt_optlist *ls, const struct libmnt
 {
        size_t i;
 
+       ls->age++;
+
        if (list_empty(&ls->opts))
                return;
 
@@ -772,6 +775,11 @@ int mnt_optlist_get_optstr(struct libmnt_optlist *ls, const char **optstr,
        return 0;
 }
 
+unsigned int mnt_optlist_get_age(struct libmnt_optlist *ls)
+{
+       return ls ? ls->age : 0;
+}
+
 int mnt_optlist_get_propagation(struct libmnt_optlist *ls)
 {
        return ls ? ls->propagation : 0;
@@ -888,6 +896,8 @@ int mnt_opt_set_external(struct libmnt_opt *opt, int enable)
        return 0;
 }
 
+
+
 #ifdef TEST_PROGRAM
 
 static int mk_optlist(struct libmnt_optlist **ol, const char *optstr)