Kernel commit 092a53452b (("autofs: take more care to not update last_used on path walk") helped to (partially) resolve a problem where automounts were not expiring due to aggressive accesses from user space. This patch was later reverted because, for very large environments, it meant more mount requests from clients and when there are a lot of clients this caused a fairly significant increase in server load. But there is a need for both types of expire check, depending on use case, so a mount option to allow for strict update of last use of autofs dentrys has been added ito the autofs file system (which just means not updating the last use on path walk accesses). So add support for this master map mount entry option in the user space code. Signed-off-by: Ian Kent <raven@xxxxxxxxxx> --- CHANGELOG | 3 +++ daemon/direct.c | 10 ++++++++++ daemon/indirect.c | 10 ++++++++++ include/automount.h | 3 +++ lib/master_parse.y | 8 +++++++- lib/master_tok.l | 1 + man/auto.master.5.in | 8 ++++++++ modules/mount_autofs.c | 5 +++++ 8 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ca036f19..f671dc52 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +xx/xx/2019 autofs-5.1.6 +- support strictexpire mount option. + 30/10/2018 autofs-5.1.5 - fix flag file permission. - fix directory create permission. diff --git a/daemon/direct.c b/daemon/direct.c index b885d12f..9c61c4b4 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -421,6 +421,16 @@ int do_mount_autofs_direct(struct autofs_point *ap, mp->options = make_options_string(ap->path, ap->kpipefd, str_direct); if (!mp->options) return 0; + + if ((ap->flags & MOUNT_FLAG_STRICTEXPIRE) && + ((get_kver_major() == 5 && get_kver_minor() > 3) || + (get_kver_major() > 5))) { + char *tmp = realloc(mp->options, strlen(mp->options) + 12); + if (tmp) { + strcat(tmp, ",strictexpire"); + mp->options = tmp; + } + } } /* In case the directory doesn't exist, try to mkdir it */ diff --git a/daemon/indirect.c b/daemon/indirect.c index 438a0a21..d0724293 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -132,6 +132,16 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root) goto out_err; } + if ((ap->flags & MOUNT_FLAG_STRICTEXPIRE) && + ((get_kver_major() == 5 && get_kver_minor() > 3) || + (get_kver_major() > 5))) { + char *tmp = realloc(options, strlen(options) + 12); + if (tmp) { + strcat(tmp, ",strictexpire"); + options = tmp; + } + } + /* In case the directory doesn't exist, try to mkdir it */ if (mkdir_path(root, mp_mode) < 0) { if (errno != EEXIST && errno != EROFS) { diff --git a/include/automount.h b/include/automount.h index 947daa10..1bb32015 100644 --- a/include/automount.h +++ b/include/automount.h @@ -554,6 +554,9 @@ struct kernel_mod_version { #define MOUNT_FLAG_SLAVE 0x0100 #define MOUNT_FLAG_PRIVATE 0x0200 +/* Use strict expire semantics if requested and kernel supports it */ +#define MOUNT_FLAG_STRICTEXPIRE 0x0400 + struct autofs_point { pthread_t thid; char *path; /* Mount point name */ diff --git a/lib/master_parse.y b/lib/master_parse.y index 9aa57327..8fe8b128 100644 --- a/lib/master_parse.y +++ b/lib/master_parse.y @@ -58,6 +58,7 @@ static char *format; static long timeout; static long negative_timeout; static unsigned symlnk; +static unsigned strictexpire; static unsigned slave; static unsigned private; static unsigned nobind; @@ -105,7 +106,7 @@ static int master_fprintf(FILE *, char *, ...); %token MAP %token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOBIND OPT_NOGHOST OPT_GHOST OPT_VERBOSE %token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT OPT_SYMLINK OPT_MODE -%token OPT_SLAVE OPT_PRIVATE +%token OPT_STRICTEXPIRE OPT_SLAVE OPT_PRIVATE %token COLON COMMA NL DDASH %type <strtype> map %type <strtype> options @@ -206,6 +207,7 @@ line: | PATH OPT_DEBUG { master_notify($1); YYABORT; } | PATH OPT_TIMEOUT { master_notify($1); YYABORT; } | PATH OPT_SYMLINK { master_notify($1); YYABORT; } + | PATH OPT_STRICTEXPIRE { master_notify($1); YYABORT; } | PATH OPT_SLAVE { master_notify($1); YYABORT; } | PATH OPT_PRIVATE { master_notify($1); YYABORT; } | PATH OPT_NOBIND { master_notify($1); YYABORT; } @@ -619,6 +621,7 @@ option: daemon_option daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; } | OPT_NTIMEOUT NUMBER { negative_timeout = $2; } | OPT_SYMLINK { symlnk = 1; } + | OPT_STRICTEXPIRE { strictexpire = 1; } | OPT_SLAVE { slave = 1; } | OPT_PRIVATE { private = 1; } | OPT_NOBIND { nobind = 1; } @@ -693,6 +696,7 @@ static void local_init_vars(void) timeout = -1; negative_timeout = 0; symlnk = 0; + strictexpire = 0; slave = 0; private = 0; nobind = 0; @@ -901,6 +905,8 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY; if (symlnk) entry->ap->flags |= MOUNT_FLAG_SYMLINK; + if (strictexpire) + entry->ap->flags |= MOUNT_FLAG_STRICTEXPIRE; if (slave) entry->ap->flags |= MOUNT_FLAG_SLAVE; if (private) diff --git a/lib/master_tok.l b/lib/master_tok.l index f4e940ce..7486710b 100644 --- a/lib/master_tok.l +++ b/lib/master_tok.l @@ -391,6 +391,7 @@ MODE (--mode{OPTWS}|--mode{OPTWS}={OPTWS}) -?nobrowse { return(OPT_NOGHOST); } -?slave { return(OPT_SLAVE); } -?private { return(OPT_PRIVATE); } + -?strictexpire { return(OPT_STRICTEXPIRE); } -g|--ghost|-?browse { return(OPT_GHOST); } -v|--verbose { return(OPT_VERBOSE); } -d|--debug { return(OPT_DEBUG); } diff --git a/man/auto.master.5.in b/man/auto.master.5.in index 68242d45..dace4a1c 100644 --- a/man/auto.master.5.in +++ b/man/auto.master.5.in @@ -199,6 +199,14 @@ entries only, either in the master map (so it effects all map entries) or with individual map entries. The option is ignored for direct mounts and non-root offest mount entries. .TP +.I "strictexpire" +Use a strict expire policy for this automount. Using this option means +that last use of autofs directory entries will not be updated during +path walks so that mounts in an automount won't be kept mounted by +applications scanning the mount tree. Note that this doesn't completely +resolve the problem of expired automounts being immediately re-mounted +due to application accesses triggered by the expire itself. +.TP .I slave \fPor\fI private This option allows mount propagation of bind mounts to be set to either \fIslave\fP or \fIprivate\fP. This option may be needed when using diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c index cd0631b8..72e1aba4 100644 --- a/modules/mount_autofs.c +++ b/modules/mount_autofs.c @@ -57,6 +57,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int nobind = ap->flags & MOUNT_FLAG_NOBIND; int ghost = ap->flags & MOUNT_FLAG_GHOST; int symlnk = ap->flags & MOUNT_FLAG_SYMLINK; + int strictexpire = ap->flags & MOUNT_FLAG_STRICTEXPIRE; time_t timeout = get_exp_timeout(ap, ap->entry->maps); unsigned logopt = ap->logopt; struct map_type_info *info; @@ -131,6 +132,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, ghost = 1; else if (_strncmp("symlink", cp, 7) == 0) symlnk = 1; + else if (_strncmp("strictexpire", cp, 12) == 0) + strictexpire = 1; else if (_strncmp("hosts", cp, 5) == 0) hosts = 1; else if (_strncmp("timeout=", cp, 8) == 0) { @@ -173,6 +176,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, nap->parent = ap; if (symlnk) nap->flags |= MOUNT_FLAG_SYMLINK; + if (strictexpire) + nap->flags |= MOUNT_FLAG_STRICTEXPIRE; if (hosts) argc = 0;