commit 6cbb6e9a3b8b223babf723e0f56cdd7b7eb90455 Author: Ian Kent Date: Mon Jul 8 11:04:11 2024 +0800 autofs-5.1.9 - add some unimplemented amd map options Add handling for amd per-mount options "utimeout", "unmount" and "nounmount" if the kernel supports it. Signed-off-by: Ian Kent diff --git a/CHANGELOG b/CHANGELOG index 42f43490f..22b55bc18 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ - seperate amd mount and entry flags. - make iocl ops ->timeout() handle per-dentry expire. - refactor amd mount options handling. +- add some unimplemented amd map options. 02/11/2023 autofs-5.1.9 - fix kernel mount status notification. diff --git a/include/mounts.h b/include/mounts.h index 381d120c7..0c711ee83 100644 --- a/include/mounts.h +++ b/include/mounts.h @@ -113,6 +113,8 @@ struct mnt_list { char *amd_pref; char *amd_type; char *amd_opts; + unsigned long amd_flags; + unsigned int amd_utimeout; unsigned int amd_cache_opts; struct list_head amdmount; diff --git a/include/parse_amd.h b/include/parse_amd.h index 46f809146..5ff193186 100644 --- a/include/parse_amd.h +++ b/include/parse_amd.h @@ -33,6 +33,11 @@ #define AMD_MOUNT_TYPE_PROGRAM 0x00004000 #define AMD_MOUNT_TYPE_MASK 0x0000ffff +#define AMD_MOUNT_OPT_UNMOUNT 0x00010000 +#define AMD_MOUNT_OPT_NOUNMOUNT 0x00020000 +#define AMD_MOUNT_OPT_UTIMEOUT 0x00040000 +#define AMD_MOUNT_OPT_MASK 0x00ff0000 + #define AMD_DEFAULTS_MERGE 0x0001 #define AMD_DEFAULTS_RESET 0x0002 #define AMD_DEFAULTS_MASK 0x00ff @@ -49,6 +54,7 @@ struct amd_entry { char *path; unsigned long flags; + unsigned int utimeout; unsigned int cache_opts; unsigned int entry_flags; char *type; diff --git a/lib/mounts.c b/lib/mounts.c index 656de33d5..bee1ae58d 100644 --- a/lib/mounts.c +++ b/lib/mounts.c @@ -1193,6 +1193,8 @@ struct mnt_list *mnts_add_amdmount(struct autofs_point *ap, struct amd_entry *en this->amd_pref = pref; this->amd_type = type; this->amd_opts = opts; + this->amd_flags = entry->flags; + this->amd_utimeout = entry->utimeout; this->amd_cache_opts = entry->cache_opts; this->flags |= MNTS_AMD_MOUNT; if (list_empty(&this->amdmount)) @@ -1237,6 +1239,8 @@ static void __mnts_remove_amdmount(const char *mp) free(this->amd_opts); this->amd_opts = NULL; } + this->amd_flags = AMD_MOUNT_OPT_UNMOUNT; + this->amd_utimeout = -1; this->amd_cache_opts = 0; __mnts_put_mount(this); } diff --git a/modules/amd_parse.y b/modules/amd_parse.y index 28ec6caaf..416f2289f 100644 --- a/modules/amd_parse.y +++ b/modules/amd_parse.y @@ -647,8 +647,7 @@ static int match_mnt_option(char *option, char *options) { int ret = 0; - if (!strcmp(option, "fullybrowsable") || - !strcmp(option, "nounmount")) { + if (!strcmp(option, "fullybrowsable")) { sprintf(msg_buf, "option %s is not currently " "implemented, ignored", option); amd_info(msg_buf); @@ -660,15 +659,37 @@ static int match_mnt_option(char *option, char *options) sprintf(msg_buf, "option %s is not used by " "autofs, ignored", option); amd_info(msg_buf); + } else if (!strcmp(option, "umount")) { + entry.flags &= ~AMD_MOUNT_OPT_NOUNMOUNT; + entry.flags |= AMD_MOUNT_OPT_UNMOUNT; + } else if (!strcmp(option, "nounmount")) { + if (entry.flags & AMD_MOUNT_TYPE_AUTO) + prepend_opt(opts, "timeout=0"); + else { + entry.flags &= ~AMD_MOUNT_OPT_UNMOUNT; + entry.flags |= AMD_MOUNT_OPT_NOUNMOUNT; + entry.utimeout = 0; + } } else if (!strncmp(option, "utimeout=", 9)) { + /* + * amd type "auto" mounts map to autofs fstype=autofs + * mounts so a distinct autofs mount is present at the + * the root so there's no need for special handling, + * just pass the timeout= autofs option. + */ if (entry.flags & AMD_MOUNT_TYPE_AUTO) prepend_opt(options, ++option); else { - sprintf(msg_buf, "umount timeout can't be " - "used for other than type " - "\"auto\" with autofs, " - "ignored"); - amd_info(msg_buf); + if (strchr(option, '=')) { + unsigned long tout; + int ret; + + ret = sscanf(option, "utimeout=%lu", &tout); + if (ret) { + entry.flags |= AMD_MOUNT_OPT_UTIMEOUT; + entry.utimeout = tout; + } + } } } else ret = 1; @@ -791,6 +812,8 @@ static void local_init_vars(void) { memset(&entry, 0, sizeof(entry)); entry.cache_opts = AMD_CACHE_OPTION_NONE; + entry.flags = AMD_MOUNT_OPT_UNMOUNT; + entry.utimeout = -1; memset(opts, 0, sizeof(opts)); } @@ -900,6 +923,7 @@ static int add_location(void) new->path = entry.path; } new->flags = entry.flags; + new->utimeout = entry.utimeout; new->cache_opts = entry.cache_opts; new->entry_flags = entry.entry_flags; new->type = entry.type; diff --git a/modules/parse_amd.c b/modules/parse_amd.c index 0fb99862f..23f589450 100644 --- a/modules/parse_amd.c +++ b/modules/parse_amd.c @@ -1654,6 +1654,7 @@ static int amd_mount(struct autofs_point *ap, const char *name, struct parse_context *ctxt) { unsigned long fstype = entry->flags & AMD_MOUNT_TYPE_MASK; + unsigned long per_mnt_flags = entry->flags & AMD_MOUNT_OPT_MASK; int ret = 1; switch (fstype) { @@ -1725,6 +1726,55 @@ static int amd_mount(struct autofs_point *ap, const char *name, break; } + if (!ret) { + struct ioctl_ops *ops; + + if (!(per_mnt_flags & AMD_MOUNT_OPT_MASK)) + goto done; + + /* The mount succeeded, make sure there's no path component + * seperator in "name" as it must be the last component of + * the mount point alone for the per-mount options. + */ + if (strchr(name, '/')) { + warn(ap->logopt, "path component seperator not valid here"); + goto done; + } + + ops = get_ioctl_ops(); + + /* The default in autofs is to always expire mounts according to + * a timeout set in the autofs mount super block information + * structure. But amd allows for differing expire timeouts on a + * per-mount basis. It also has (context sensitive) options "unmount" + * to say expire this mount and "nounmount" to say don't expire this + * mount. In amd mounts these options are set by default according + * to whether a mount should expire or not, for example a cd mount + * is set "nounmount". Setting defaults like this is not used in the + * autofs amd implementation because there's only one, little used, + * removable file system available. + * + * But the "nounmount" and "utimeout" options can be useful. + */ + if (per_mnt_flags & AMD_MOUNT_OPT_NOUNMOUNT) { + if (entry->utimeout) + warn(ap->logopt, + "non-zero timeout set, possible conflicting options"); + + /* "nounmount" option, don't expire this mount. */ + if (ops) + ops->timeout(ap->logopt, ap->ioctlfd, name, 0); + } else if (per_mnt_flags & AMD_MOUNT_OPT_UTIMEOUT) { + if (!entry->utimeout) + warn(ap->logopt, + "zero timeout set, possible conflicting options"); + + /* "utimeout" option, expire this mount according to a timeout. */ + if (ops) + ops->timeout(ap->logopt, ap->ioctlfd, name, entry->utimeout); + } + } +done: return ret; }