From 7b37d5b5667103beac16f7ae3cca5feaf00a21b0 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 22 Jun 2023 13:11:57 +0200 Subject: [PATCH] libmount: fix sync options between context and fs structs 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 --- libmount/src/context.c | 82 ++++++++++++++++++++++++++++++++++++++++-- libmount/src/fs.c | 23 +++++++++--- 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/libmount/src/context.c b/libmount/src/context.c index 4c5e65659..0cd320190 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -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 ] [-f][-l][-r] |" }, { "--mount-all", test_mountall, "[-O ] [-t ] " }, + { "--cxtsync", test_cxtsync, " " }, { "--search-helper", test_search_helper, "" }, { NULL }}; diff --git a/libmount/src/fs.c b/libmount/src/fs.c index 655f07171..79e32a170 100644 --- a/libmount/src/fs.c +++ b/libmount/src/fs.c @@ -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) -- 2.41.0