autofs-5.1.8 - fix expire retry looping From: Ian Kent Commit aa6da48d1 ("autofs-5.1.7 - eliminate count_mounts() from expire_proc_indirect()") stopped using the count_mounts() function in indirect mount expires because it can be a significant overhead and shouldn't be needed if the kernel expire dentry selection works as it should. Unfortunately there is a case where it doesn't work properly, when a USR1 signal is sent to the automount process it is meant to expire mounts regardless of the expire timeout. In this case if a mount has been propagated to a mount namespace and is held busy the mount will fail to umount and because setting the last used field of the mount dentry doesn't prevent the mount dentry from being selected for expire again immediately in this case automount will look continually. The problem occurs because the the kernel doesn't know how to check these propagated mounts for busyness and the init namespace automount process tries to expire the mount but fails and continues trying to expire the mount because the expire function assumes only mounts that are not busy will be selected for expire. Signed-off-by: Ian Kent --- CHANGELOG | 1 + daemon/indirect.c | 13 ++++++++++++- include/automount.h | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 58c1cd12..1ebb02fb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -94,6 +94,7 @@ - dont probe interface that cant send packet. - fix some sss error return cases. - fix incorrect matching of cached wildcard key. +- fix expire retry looping. 19/10/2021 autofs-5.1.8 - add xdr_exports(). diff --git a/daemon/indirect.c b/daemon/indirect.c index 204fa076..0f7b620b 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -343,6 +343,7 @@ void *expire_proc_indirect(void *arg) int offsets, submnts, count; int ioctlfd, cur_state; int status, ret, left; + int retries; ea = (struct expire_args *) arg; @@ -490,9 +491,19 @@ void *expire_proc_indirect(void *arg) * If there are no more real mounts left we could still * have some offset mounts with no '/' offset or symlinks * so we need to umount or unlink them here. + * + * The dentry info last_used field is set to 'now' when a + * dentry is selected for expire so that it isn't immediately + * selected again if the expire fails. But this can't work + * for immediate expires so the count_mounts() function must + * be used to limit the number of expire iterations. */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - while (1) { + if (how == AUTOFS_EXP_IMMEDIATE) + retries = count_mounts(ap, ap->path, ap->dev); + else + retries = -1; + while (retries--) { ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, how); if (ret != 0 && errno == EAGAIN) break; diff --git a/include/automount.h b/include/automount.h index 77ff0c70..9548db83 100644 --- a/include/automount.h +++ b/include/automount.h @@ -146,7 +146,7 @@ struct autofs_point; #define NEGATIVE_TIMEOUT 10 #define POSITIVE_TIMEOUT 120 #define UMOUNT_RETRIES 16 -#define EXPIRE_RETRIES 3 +#define EXPIRE_RETRIES 1 struct mapent_cache { pthread_rwlock_t rwlock;