autofs-5.1.6 - use mnt_list for amdmounts From: Ian Kent Use struct mnt_list objects for the list of amd mounts instead of struct amd_entry. Signed-off-by: Ian Kent --- CHANGELOG | 1 daemon/automount.c | 47 ++++++++++------------ daemon/lookup.c | 18 +++++--- include/automount.h | 2 - include/master.h | 2 - include/mounts.h | 12 ++++++ include/parse_amd.h | 1 lib/master.c | 36 +---------------- lib/mounts.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ modules/mount_autofs.c | 15 ++++--- modules/parse_amd.c | 43 +++++++++++++++----- 11 files changed, 193 insertions(+), 87 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e501f3b9..91420739 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -57,6 +57,7 @@ xx/xx/2020 autofs-5.1.7 - make external mounts use simpler hashtable. - add a hash index to mnt_list. - use mnt_list for submounts. +- use mnt_list for amdmounts. 07/10/2019 autofs-5.1.6 - support strictexpire mount option. diff --git a/daemon/automount.c b/daemon/automount.c index c174c2a8..d9644e4c 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -595,7 +595,8 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi * it already to ensure it's ok to remove any offset triggers. */ if (!is_mm_root && is_mounted(path, MNTS_REAL)) { - struct amd_entry *entry; + struct mnt_list *mnt; + debug(ap->logopt, "unmounting dir = %s", path); if (umount_ent(ap, path) && is_mounted(path, MNTS_REAL)) { @@ -605,16 +606,12 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi } /* Check for an external mount and umount if possible */ - mounts_mutex_lock(ap); - entry = __master_find_amdmount(ap, path); - if (!entry) { - mounts_mutex_unlock(ap); - goto done; + mnt = mnts_find_amdmount(path); + if (mnt) { + umount_amd_ext_mount(ap, mnt->ext_mp); + mnts_remove_amdmount(path); + mnts_put_mount(mnt); } - list_del(&entry->entries); - mounts_mutex_unlock(ap); - umount_amd_ext_mount(ap, entry->fs); - free_amd_entry(entry); } done: return left; @@ -639,7 +636,8 @@ int umount_multi(struct autofs_point *ap, const char *path, int incl) /* if this is a symlink we can handle it now */ if (S_ISLNK(st.st_mode)) { - struct amd_entry *entry; + struct mnt_list *mnt; + if (st.st_dev != ap->dev) { crit(ap->logopt, "symlink %s has the wrong device, " @@ -652,6 +650,7 @@ int umount_multi(struct autofs_point *ap, const char *path, int incl) "failed to remove symlink %s", path); return 1; } + /* Check if the autofs mount has browse mode enabled. * If so re-create the directory entry. */ @@ -671,17 +670,15 @@ int umount_multi(struct autofs_point *ap, const char *path, int incl) "mkdir_path %s failed: %s", path, estr); } } + /* Check for an external mount and attempt umount if needed */ - mounts_mutex_lock(ap); - entry = __master_find_amdmount(ap, path); - if (!entry) { - mounts_mutex_unlock(ap); - return 0; + mnt = mnts_find_amdmount(path); + if (mnt) { + umount_amd_ext_mount(ap, mnt->ext_mp); + mnts_remove_amdmount(path); + mnts_put_mount(mnt); } - list_del(&entry->entries); - mounts_mutex_unlock(ap); - umount_amd_ext_mount(ap, entry->fs); - free_amd_entry(entry); + return 0; } @@ -1720,17 +1717,17 @@ static void handle_mounts_cleanup(void *arg) clean = 1; if (submount) { - struct amd_entry *am; + struct mnt_list *mnt; /* We are finishing up */ ap->parent->submnt_count--; /* Submount at ap->path belongs to parent submount list. */ mnts_remove_submount(ap->path); - am = __master_find_amdmount(ap->parent, ap->path); - if (am) { - list_del_init(&am->entries); - free_amd_entry(am); + mnt = mnts_find_amdmount(ap->path); + if (mnt) { + mnts_remove_amdmount(ap->path); + mnts_put_mount(mnt); } } diff --git a/daemon/lookup.c b/daemon/lookup.c index db00cb4a..2fea0c0b 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -830,7 +830,7 @@ static int lookup_amd_instance(struct autofs_point *ap, const char *name, int name_len) { struct map_source *instance; - struct amd_entry *entry; + struct mnt_list *mnt; const char *argv[2]; const char **pargv = NULL; int argc = 0; @@ -853,21 +853,23 @@ static int lookup_amd_instance(struct autofs_point *ap, strcpy(m_key, ap->path); strcat(m_key, "/"); strcat(m_key, me->multi->key); - entry = master_find_amdmount(ap, m_key); + + mnt = mnts_find_amdmount(m_key); free(m_key); - if (!entry) { + if (!mnt) { error(ap->logopt, "expected amd mount entry not found"); return NSS_STATUS_UNKNOWN; } - if (strcmp(entry->type, "host")) { - error(ap->logopt, "unexpected map type %s", entry->type); + if (strcmp(mnt->amd_type, "host")) { + error(ap->logopt, "unexpected map type %s", mnt->amd_type); + mnts_put_mount(mnt); return NSS_STATUS_UNKNOWN; } - if (entry->opts && *entry->opts) { - argv[0] = entry->opts; + if (mnt->amd_opts && *mnt->amd_opts) { + argv[0] = mnt->amd_opts; argv[1] = NULL; pargv = argv; argc = 1; @@ -886,9 +888,11 @@ static int lookup_amd_instance(struct autofs_point *ap, } } if (!instance) { + mnts_put_mount(mnt); error(ap->logopt, "expected hosts map instance not found"); return NSS_STATUS_UNKNOWN; } + mnts_put_mount(mnt); return do_lookup_mount(ap, instance, name, name_len); } diff --git a/include/automount.h b/include/automount.h index 11622ac2..600f98dd 100644 --- a/include/automount.h +++ b/include/automount.h @@ -569,10 +569,10 @@ struct autofs_point { struct autofs_point *parent; /* Owner of mounts list for submount */ pthread_mutex_t mounts_mutex; /* Protect mount lists */ struct list_head mounts; /* List of autofs mounts at current level */ - struct list_head amdmounts; /* List of non submount amd mounts */ unsigned int submount; /* Is this a submount */ unsigned int submnt_count; /* Number of submounts */ struct list_head submounts; /* List of child submounts */ + struct list_head amdmounts; /* List of non submount amd mounts */ unsigned int shutdown; /* Shutdown notification */ }; diff --git a/include/master.h b/include/master.h index 12d2363d..8faae754 100644 --- a/include/master.h +++ b/include/master.h @@ -109,8 +109,6 @@ void master_source_current_wait(struct master_mapent *); void master_source_current_signal(struct master_mapent *); struct master_mapent *master_find_mapent(struct master *, const char *); unsigned int master_partial_match_mapent(struct master *, const char *); -struct amd_entry *__master_find_amdmount(struct autofs_point *, const char *); -struct amd_entry *master_find_amdmount(struct autofs_point *, const char *); struct master_mapent *master_new_mapent(struct master *, const char *, time_t); void master_add_mapent(struct master *, struct master_mapent *); void master_remove_mapent(struct master_mapent *); diff --git a/include/mounts.h b/include/mounts.h index a031a1c9..047f0b92 100644 --- a/include/mounts.h +++ b/include/mounts.h @@ -38,6 +38,7 @@ #define MNTS_INDIRECT 0x0008 #define MNTS_DIRECT 0x0010 #define MNTS_OFFSET 0x0020 +#define MNTS_AMD_MOUNT 0x0040 #define REMOUNT_SUCCESS 0x0000 #define REMOUNT_FAIL 0x0001 @@ -64,6 +65,14 @@ struct mnt_list { struct list_head submount; struct list_head submount_work; + /* List of amd-mounts of an autofs_point */ + char *ext_mp; + char *amd_pref; + char *amd_type; + char *amd_opts; + unsigned int amd_cache_opts; + struct list_head amdmount; + /* * List operations ie. get_mnt_list. */ @@ -118,6 +127,9 @@ struct mnt_list *mnts_add_submount(struct autofs_point *ap); void mnts_remove_submount(const char *mp); void mnts_get_submount_list(struct list_head *mnts, struct autofs_point *ap); void mnts_put_submount_list(struct list_head *mnts); +struct mnt_list *mnts_find_amdmount(const char *path); +struct mnt_list *mnts_add_amdmount(struct autofs_point *ap, struct amd_entry *entry); +void mnts_remove_amdmount(const char *mp); struct mnt_list *get_mnt_list(const char *path, int include); int unlink_mount_tree(struct autofs_point *ap, const char *mp); void free_mnt_list(struct mnt_list *list); diff --git a/include/parse_amd.h b/include/parse_amd.h index 5e3318a0..81506cbd 100644 --- a/include/parse_amd.h +++ b/include/parse_amd.h @@ -65,7 +65,6 @@ struct amd_entry { char *umount; struct selector *selector; struct list_head list; - struct list_head entries; }; int amd_parse_list(struct autofs_point *, diff --git a/lib/master.c b/lib/master.c index 9d3035a2..7af516ce 100644 --- a/lib/master.c +++ b/lib/master.c @@ -152,12 +152,10 @@ void master_free_autofs_point(struct autofs_point *ap) head = &ap->amdmounts; p = head->next; while (p != head) { - struct amd_entry *entry = list_entry(p, struct amd_entry, entries); + struct mnt_list *mnt = list_entry(p, struct mnt_list, amdmount); p = p->next; - if (!list_empty(&entry->entries)) - list_del(&entry->entries); - ext_mount_remove(entry->fs); - free_amd_entry(entry); + ext_mount_remove(mnt->ext_mp); + mnts_remove_amdmount(mnt->mp); } mounts_mutex_unlock(ap); @@ -761,34 +759,6 @@ unsigned int master_partial_match_mapent(struct master *master, const char *path return ret; } -struct amd_entry *__master_find_amdmount(struct autofs_point *ap, const char *path) -{ - struct list_head *head, *p; - - head = &ap->amdmounts; - list_for_each(p, head) { - struct amd_entry *entry; - - entry = list_entry(p, struct amd_entry, entries); - - if (!strcmp(entry->path, path)) - return entry; - } - - return NULL; -} - -struct amd_entry *master_find_amdmount(struct autofs_point *ap, const char *path) -{ - struct amd_entry *entry; - - mounts_mutex_lock(ap); - entry = __master_find_amdmount(ap, path); - mounts_mutex_unlock(ap); - - return entry; -} - struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age) { struct master_mapent *entry; diff --git a/lib/mounts.c b/lib/mounts.c index af301da1..64b911c3 100644 --- a/lib/mounts.c +++ b/lib/mounts.c @@ -546,7 +546,6 @@ struct amd_entry *new_amd_entry(const struct substvar *sv) memset(new, 0, sizeof(*new)); new->path = path; INIT_LIST_HEAD(&new->list); - INIT_LIST_HEAD(&new->entries); return new; } @@ -887,6 +886,7 @@ static struct mnt_list *mnts_alloc_mount(const char *mp) INIT_HLIST_NODE(&this->hash); INIT_LIST_HEAD(&this->submount); INIT_LIST_HEAD(&this->submount_work); + INIT_LIST_HEAD(&this->amdmount); done: return this; } @@ -1048,6 +1048,107 @@ void mnts_put_submount_list(struct list_head *mnts) mnts_hash_mutex_unlock(); } +struct mnt_list *mnts_find_amdmount(const char *path) +{ + struct mnt_list *mnt; + + mnt = mnts_lookup_mount(path); + if (mnt && mnt->flags & MNTS_AMD_MOUNT) + return mnt; + mnts_put_mount(mnt); + return NULL; +} + +struct mnt_list *mnts_add_amdmount(struct autofs_point *ap, struct amd_entry *entry) +{ + struct mnt_list *this; + char *type, *ext_mp, *pref, *opts; + + ext_mp = pref = type = opts = NULL; + + if (entry->fs) { + ext_mp = strdup(entry->fs); + if (!ext_mp) + goto fail; + } + + if (entry->pref) { + pref = strdup(entry->pref); + if (!pref) + goto fail; + } + + if (entry->type) { + type = strdup(entry->type); + if (!type) + goto fail; + } + + if (entry->opts) { + opts = strdup(entry->opts); + if (!opts) + goto fail; + } + + mnts_hash_mutex_lock(); + this = mnts_get_mount(entry->path); + if (this) { + this->ext_mp = ext_mp; + this->amd_pref = pref; + this->amd_type = type; + this->amd_opts = opts; + this->amd_cache_opts = entry->cache_opts; + this->flags |= MNTS_AMD_MOUNT; + if (list_empty(&this->amdmount)) + list_add_tail(&this->amdmount, &ap->amdmounts); + } + mnts_hash_mutex_unlock(); + + return this; +fail: + if (ext_mp) + free(ext_mp); + if (pref) + free(pref); + if (type) + free(type); + if (opts) + free(opts); + return NULL; +} + +void mnts_remove_amdmount(const char *mp) +{ + struct mnt_list *this; + + mnts_hash_mutex_lock(); + this = mnts_lookup(mp); + if (!(this && this->flags & MNTS_AMD_MOUNT)) + goto done; + this->flags &= ~MNTS_AMD_MOUNT; + list_del_init(&this->submount); + if (this->ext_mp) { + free(this->ext_mp); + this->ext_mp = NULL; + } + if (this->amd_type) { + free(this->amd_type); + this->amd_type = NULL; + } + if (this->amd_pref) { + free(this->amd_pref); + this->amd_pref = NULL; + } + if (this->amd_opts) { + free(this->amd_opts); + this->amd_opts = NULL; + } + this->amd_cache_opts = 0; + __mnts_put_mount(this); +done: + mnts_hash_mutex_unlock(); +} + /* From glibc decode_name() */ /* Since the values in a line are separated by spaces, a name cannot * contain a space. Therefore some programs encode spaces in names diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c index 356bba8c..1c40e27a 100644 --- a/modules/mount_autofs.c +++ b/modules/mount_autofs.c @@ -286,16 +286,19 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, mounts_mutex_lock(ap); if (source->flags & MAP_FLAG_FORMAT_AMD) { - struct amd_entry *am_entry = __master_find_amdmount(ap, entry->path); + struct mnt_list *mnt; - if (am_entry) { - if (am_entry->pref) { - nap->pref = am_entry->pref; - am_entry->pref = NULL; + mnt = mnts_find_amdmount(entry->path); + if (mnt) { + if (mnt->amd_pref) { + nap->pref = mnt->amd_pref; + mnt->amd_pref = NULL; } - if (am_entry->cache_opts & AMD_CACHE_OPTION_ALL) + if (mnt->amd_cache_opts & AMD_CACHE_OPTION_ALL) nap->flags |= MOUNT_FLAG_AMD_CACHE_ALL; + + mnts_put_mount(mnt); } } diff --git a/modules/parse_amd.c b/modules/parse_amd.c index 43ee779e..d3e8a450 100644 --- a/modules/parse_amd.c +++ b/modules/parse_amd.c @@ -1300,6 +1300,7 @@ static int do_host_mount(struct autofs_point *ap, const char *name, { struct lookup_mod *lookup; struct map_source *instance; + struct mnt_list *mnt = NULL; struct mapent *me; const char *argv[2]; const char **pargv = NULL; @@ -1316,7 +1317,9 @@ static int do_host_mount(struct autofs_point *ap, const char *name, */ if (strcmp(name, entry->rhost)) { char *target; - size_t len = strlen(ap->path) + strlen(entry->rhost) + 2; + size_t len; + + len = strlen(ap->path) + strlen(entry->rhost) + 2; target = malloc(len); if (!target) { warn(ap->logopt, MODPREFIX @@ -1329,6 +1332,15 @@ static int do_host_mount(struct autofs_point *ap, const char *name, if (entry->path) free(entry->path); entry->path = target; + + /* Add an mnt_list entry for the updated path. */ + mnt = mnts_add_amdmount(ap, entry); + if (!mnt) { + error(ap->logopt, MODPREFIX + "failed to update mount mnt_list entry"); + goto out; + } + /* * Wait for any expire before racing to mount the * export tree or bail out if we're shutting down. @@ -1388,6 +1400,8 @@ static int do_host_mount(struct autofs_point *ap, const char *name, warn(ap->logopt, MODPREFIX "failed to create symlink to hosts mount base"); out: + if (ret && mnt) + mnts_remove_amdmount(mnt->mp); return ret; } @@ -2204,6 +2218,7 @@ int parse_mount(struct autofs_point *ap, const char *name, struct list_head entries, *p, *head; struct amd_entry *defaults_entry; struct amd_entry *cur_defaults; + struct mnt_list *mnt; int rv = 1; int cur_state; int ret; @@ -2313,21 +2328,27 @@ int parse_mount(struct autofs_point *ap, const char *name, * add parsed entry to parent amd mount list and remove * on mount fail. */ - mounts_mutex_lock(ap); - list_add_tail(&this->entries, &ap->amdmounts); - mounts_mutex_unlock(ap); + mnt = mnts_add_amdmount(ap, this); + if (!mnt) { + error(ap->logopt, MODPREFIX + "failed to add mount to mnt_list"); + break; + } rv = amd_mount(ap, name, this, source, sv, flags, ctxt); - mounts_mutex_lock(ap); if (!rv) { - /* Mounted, remove entry from parsed list */ - list_del_init(&this->list); - mounts_mutex_unlock(ap); + /* + * If entry->path doesn't match the mnt->mp then + * the mount point path has changed and a new + * mnt_list entry added for it, so remove the + * original. + */ + if (strcmp(this->path, mnt->mp)) + mnts_remove_amdmount(this->path); break; } - /* Not mounted, remove entry from the parent list */ - list_del_init(&this->entries); - mounts_mutex_unlock(ap); + /* Not mounted, remove the mnt_list entry from amdmount list */ + mnts_remove_amdmount(this->path); } free_amd_entry(cur_defaults);