]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: fix sync options between context and fs structs
authorKarel Zak <kzak@redhat.com>
Thu, 22 Jun 2023 11:11:57 +0000 (13:11 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 22 Jun 2023 11:11:57 +0000 (13:11 +0200)
Since v2.39 libmount prefers "struct libmnt_optlist" to keep mount options
rather than the original "struct libmnt_fs". This is problem if the
"fs" struct is defined and maintained outside the context.

The library has already a way how to sync "fs" and "optlist", but this
needs to be improved and used more widely. Changes:

* force "fs" from context to always read options from "optlist"

* copy options from "fs" to "optlist" in mnt_context_set_fs()

* internally redirect mnt_fs_* API for options to "optlist" if optlist
  defined

* add simple test to make sure options from different sources are
  always merged together

Addresses: https://github.com/util-linux/util-linux/issues/2326
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/context.c
libmount/src/fs.c

index 4c5e65659f5b60d1f285e2d44334921fe9b3d955..0cd320190e314c992bab894246081250e3a0e34b 100644 (file)
@@ -911,9 +911,29 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
        if (!cxt)
                return -EINVAL;
 
+       if (cxt->fs == fs)
+               return 0;
+
        DBG(CXT, ul_debugobj(cxt, "setting new FS"));
-       mnt_ref_fs(fs);                 /* new */
-       mnt_unref_fs(cxt->fs);          /* old */
+
+       /* new */
+       if (fs) {
+               struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
+
+               if (!ol)
+                       return -ENOMEM;
+
+               mnt_ref_fs(fs);
+
+               mnt_optlist_set_optstr(ol, mnt_fs_get_options(fs), NULL);
+               mnt_fs_follow_optlist(fs, ol);
+       }
+
+       /* old */
+       if (cxt->fs)
+               mnt_fs_follow_optlist(cxt->fs, NULL);
+       mnt_unref_fs(cxt->fs);
+
        cxt->fs = fs;
        return 0;
 }
@@ -932,8 +952,17 @@ struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
 {
        if (!cxt)
                return NULL;
-       if (!cxt->fs)
+       if (!cxt->fs) {
+               struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
+
+               if (!ol)
+                       return NULL;
                cxt->fs = mnt_new_fs();
+               if (!cxt->fs)
+                       return NULL;
+
+               mnt_fs_follow_optlist(cxt->fs, ol);
+       }
        return cxt->fs;
 }
 
@@ -3314,6 +3343,50 @@ static int test_flags(struct libmnt_test *ts, int argc, char *argv[])
        return rc;
 }
 
+static int test_cxtsync(struct libmnt_test *ts, int argc, char *argv[])
+{
+       struct libmnt_context *cxt;
+       struct libmnt_fs *fs;
+       unsigned long flags = 0;
+       int rc;
+
+       if (argc != 4)
+               return -EINVAL;
+
+       fs = mnt_new_fs();
+       if (!fs)
+               return -ENOMEM;
+
+       rc = mnt_fs_set_options(fs, argv[1]);
+       if (rc)
+               return rc;
+
+       cxt = mnt_new_context();
+       if (!cxt)
+               return -ENOMEM;
+
+       rc = mnt_context_set_fs(cxt, fs);
+       if (rc)
+               return rc;
+
+       rc = mnt_context_append_options(cxt, argv[2]);
+       if (rc)
+               return rc;
+
+       rc = mnt_fs_append_options(fs, argv[3]);
+       if (rc)
+               return rc;
+
+       mnt_context_get_mflags(cxt, &flags);
+
+       printf("     fs options: %s\n", mnt_fs_get_options(fs));
+       printf("context options: %s\n", mnt_context_get_options(cxt));
+       printf(" context mflags: %08lx\n", flags);
+
+       mnt_free_context(cxt);
+       return 0;
+}
+
 static int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
 {
        struct libmnt_context *cxt;
@@ -3361,6 +3434,8 @@ static int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
        return 0;
 }
 
+
+
 int main(int argc, char *argv[])
 {
        struct libmnt_test tss[] = {
@@ -3368,6 +3443,7 @@ int main(int argc, char *argv[])
        { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
        { "--mount-all", test_mountall,  "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
        { "--flags", test_flags,   "[-o <opts>] <spec>" },
+       { "--cxtsync", test_cxtsync, "<fsopts> <cxtopts> <fsopts>" },
        { "--search-helper", test_search_helper, "<fstype>" },
        { NULL }};
 
index 655f07171319361eabb4aae38a0e0ec3683de1b6..79e32a170d4955188b0b49a1048dbab01a1cd43d 100644 (file)
@@ -228,10 +228,14 @@ int mnt_fs_follow_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol)
 
        if (fs->optlist == ol)
                return 0;
+       if (fs->optlist)
+               mnt_unref_optlist(fs->optlist);
 
        fs->opts_age = 0;
        fs->optlist = ol;
-       mnt_ref_optlist(ol);
+
+       if (ol)
+               mnt_ref_optlist(ol);
        return 0;
 }
 
@@ -919,7 +923,11 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
 
        if (!fs)
                return -EINVAL;
-       fs->opts_age = 0;
+
+       if (fs->optlist) {
+               fs->opts_age = 0;
+               return mnt_optlist_set_optstr(fs->optlist, optstr, NULL);
+       }
 
        if (optstr) {
                int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
@@ -968,8 +976,10 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
                return -EINVAL;
        if (!optstr)
                return 0;
-
-       fs->opts_age = 0;
+       if (fs->optlist) {
+               fs->opts_age = 0;
+               return mnt_optlist_append_optstr(fs->optlist, optstr, NULL);
+       }
 
        rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
        if (rc)
@@ -1013,7 +1023,10 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
        if (!optstr)
                return 0;
 
-       fs->opts_age = 0;
+       if (fs->optlist) {
+               fs->opts_age = 0;
+               return mnt_optlist_prepend_optstr(fs->optlist, optstr, NULL);
+       }
 
        rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
        if (rc)