From faa3d718d73500bd017c90a4be0d408597928e68 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 24 Aug 2022 16:54:10 +0200 Subject: [PATCH] libmount: keep context fs and optlist synchronized 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 --- libmount/src/context_mount.c | 31 +---------- libmount/src/fs.c | 100 ++++++++++++++++++++++++++++++++++- libmount/src/mountP.h | 8 ++- libmount/src/optlist.c | 10 ++++ 4 files changed, 117 insertions(+), 32 deletions(-) diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index a679a80296..743c77a05a 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -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) diff --git a/libmount/src/fs.c b/libmount/src/fs.c index 46a22c75a7..c7858898a4 100644 --- a/libmount/src/fs.c +++ b/libmount/src/fs.c @@ -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)); diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 902f511289..dac5336b35 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -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) diff --git a/libmount/src/optlist.c b/libmount/src/optlist.c index a81295e1ac..875cad058f 100644 --- a/libmount/src/optlist.c +++ b/libmount/src/optlist.c @@ -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) -- 2.47.2