Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package autofs for openSUSE:Factory checked 
in at 2026-01-27 16:06:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/autofs (Old)
 and      /work/SRC/openSUSE:Factory/.autofs.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "autofs"

Tue Jan 27 16:06:18 2026 rev:142 rq:1329099 version:5.1.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/autofs/autofs.changes    2025-10-10 
17:08:02.653944439 +0200
+++ /work/SRC/openSUSE:Factory/.autofs.new.1928/autofs.changes  2026-01-27 
16:06:20.863065371 +0100
@@ -1,0 +2,19 @@
+Fri Jan 23 17:01:55 UTC 2026 - David Disseldorp <[email protected]>
+
+- fix deadlock on map entry removal (bsc#1246325)
+  * 0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch
+  * 0002-autofs-5.1.9-fix-deadlock-in-remount.patch
+  * 0003-CHANGELOG-add-a-few-missing-entries.patch
+  * 0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
+  * 0005-autofs-5.1.9-fix-devid-update-on-reload.patch
+  * 0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
+  * 0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
+  * 0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
+  * 0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
+  * 0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
+  * 0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
+  * 0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
+  * 0013-autofs-5.1.9-add-function-table_lookup_ino.patch
+  * 0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch
+
+-------------------------------------------------------------------

New:
----
  0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch
  0002-autofs-5.1.9-fix-deadlock-in-remount.patch
  0003-CHANGELOG-add-a-few-missing-entries.patch
  0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
  0005-autofs-5.1.9-fix-devid-update-on-reload.patch
  0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
  0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
  0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
  0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
  0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
  0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
  0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
  0013-autofs-5.1.9-add-function-table_lookup_ino.patch
  0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch

----------(New B)----------
  New:- fix deadlock on map entry removal (bsc#1246325)
  * 0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch
  * 0002-autofs-5.1.9-fix-deadlock-in-remount.patch
  New:  * 0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch
  * 0002-autofs-5.1.9-fix-deadlock-in-remount.patch
  * 0003-CHANGELOG-add-a-few-missing-entries.patch
  New:  * 0002-autofs-5.1.9-fix-deadlock-in-remount.patch
  * 0003-CHANGELOG-add-a-few-missing-entries.patch
  * 0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
  New:  * 0003-CHANGELOG-add-a-few-missing-entries.patch
  * 0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
  * 0005-autofs-5.1.9-fix-devid-update-on-reload.patch
  New:  * 0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
  * 0005-autofs-5.1.9-fix-devid-update-on-reload.patch
  * 0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
  New:  * 0005-autofs-5.1.9-fix-devid-update-on-reload.patch
  * 0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
  * 0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
  New:  * 0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
  * 0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
  * 0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
  New:  * 0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
  * 0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
  * 0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
  New:  * 0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
  * 0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
  * 0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
  New:  * 0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
  * 0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
  * 0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
  New:  * 0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
  * 0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
  * 0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
  New:  * 0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
  * 0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
  * 0013-autofs-5.1.9-add-function-table_lookup_ino.patch
  New:  * 0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
  * 0013-autofs-5.1.9-add-function-table_lookup_ino.patch
  * 0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch
  New:  * 0013-autofs-5.1.9-add-function-table_lookup_ino.patch
  * 0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ autofs.spec ++++++
--- /var/tmp/diff_new_pack.iqbzva/_old  2026-01-27 16:06:22.267124969 +0100
+++ /var/tmp/diff_new_pack.iqbzva/_new  2026-01-27 16:06:22.267124969 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package autofs
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -59,6 +59,21 @@
 # bsc#1221682 - GCC 14: autofs package fails
 Patch109:       autofs-5.1.9-fix-ldap_parse_page_control-check.patch
 Patch110:       autofs-5.1.9-Fix-incompatible-function-pointer-types.patch
+# bsc#1246325 - fix map entry removal regression. queued for upstream.
+Patch111:       0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch
+Patch112:       0002-autofs-5.1.9-fix-deadlock-in-remount.patch
+Patch113:       0003-CHANGELOG-add-a-few-missing-entries.patch
+Patch114:       0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch
+Patch115:       0005-autofs-5.1.9-fix-devid-update-on-reload.patch
+Patch116:       0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch
+Patch117:       0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch
+Patch118:       0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch
+Patch119:       0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch
+Patch120:       0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch
+Patch121:       0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch
+Patch122:       0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch
+Patch123:       0013-autofs-5.1.9-add-function-table_lookup_ino.patch
+Patch124:       0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch
 BuildRequires:  autoconf
 BuildRequires:  bison
 BuildRequires:  cyrus-sasl-devel
@@ -94,18 +109,10 @@
 floppies, and so forth.
 
 %prep
-%setup -q
+%autosetup -p1
 cp %{SOURCE3} .
 cp %{SOURCE4} .
 cp %{SOURCE5} .
-#
-%patch -P 100 -p1
-%patch -P 101 -p1
-%patch -P 102 -p1
-%patch -P 106 -p1
-%patch -P 108 -p1
-%patch -P 109 -p1
-%patch -P 110 -p1
 
 %build
 autoreconf -fiv

++++++ 0001-autofs-5.1.9-fix-get-parent-multi-mount-check-in-try.patch ++++++
>From ad2ab844414acb793b2a5fc71edcda8e179aeda2 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Tue, 5 Dec 2023 11:18:58 +0800
Subject: [PATCH 01/14] autofs-5.1.9 - fix get parent multi-mount check in
 try_remount()

In commit 635b90ecc (autofs-5.1.8 - fix mount tree startup reconnect)
when getting the parent the check for a multi-mount should include a
check for the root of the multi-mount as well since the root does not
set its parent (it remains NULL).

We could set the root parent to itself but that may have side effects
because the convention has always been the parent is NULL for the
multi-mount root.

Reported-by: Roberto Bergantinos Corpas <[email protected]>
Suggested-by: Roberto Bergantinos Corpas <[email protected]>

Signed-off-by: Ian Kent <[email protected]>
(cherry picked from commit fe0cc2dc930990da59b0c6facf043d7067af476a)
---
 CHANGELOG    | 3 +++
 lib/mounts.c | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

Index: autofs-5.1.9/CHANGELOG
===================================================================
--- autofs-5.1.9.orig/CHANGELOG
+++ autofs-5.1.9/CHANGELOG
@@ -1,5 +1,7 @@
 
+=======
 - Fix incompatible function pointer types in cyrus-sasl module.
+- fix get parent multi-mount check in try_remount().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
Index: autofs-5.1.9/lib/mounts.c
===================================================================
--- autofs-5.1.9.orig/lib/mounts.c
+++ autofs-5.1.9/lib/mounts.c
@@ -2878,7 +2878,7 @@ int try_remount(struct autofs_point *ap,
        }
 
        me->flags &= ~MOUNT_FLAG_DIR_CREATED;
-       mapent = IS_MM(me) ? MM_PARENT(me) : me;
+       mapent = IS_MM(me) && !IS_MM_ROOT(me) ? MM_PARENT(me) : me;
        /* Direct or offset mount, key is full path */
        if (mapent->key[0] == '/') {
                if (!is_mounted(mapent->key, MNTS_REAL))

++++++ 0002-autofs-5.1.9-fix-deadlock-in-remount.patch ++++++
>From 7189daddda95fef293a32207ad2d86b0158b6f68 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Tue, 5 Dec 2023 13:25:49 +0800
Subject: [PATCH 02/14] autofs-5.1.9 - fix deadlock in remount

If we're starting up or trying to re-connect to an existing direct mount
we could be iterating through the map entries with the cache readlock
held so we can't just take the writelock for direct mounts. But when
trying to re-connect to an existing mount at startup there won't be any
other process updating the map entry cache.

Signed-off-by: Ian Kent <[email protected]>
(cherry picked from commit ad518262e9294ad465120cdb6fd29fdd4ccb179d)
---
 CHANGELOG           |  1 +
 modules/parse_sun.c | 26 ++++++++++++++++++++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)

Index: autofs-5.1.9/CHANGELOG
===================================================================
--- autofs-5.1.9.orig/CHANGELOG
+++ autofs-5.1.9/CHANGELOG
@@ -2,6 +2,7 @@
 =======
 - Fix incompatible function pointer types in cyrus-sasl module.
 - fix get parent multi-mount check in try_remount().
+- fix deadlock in remount.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
Index: autofs-5.1.9/modules/parse_sun.c
===================================================================
--- autofs-5.1.9.orig/modules/parse_sun.c
+++ autofs-5.1.9/modules/parse_sun.c
@@ -889,7 +889,18 @@ update_offset_entry(struct autofs_point
                        strcpy(m_mapent, loc);
        }
 
-       cache_writelock(mc);
+       /*
+        * If we're starting up or trying to re-connect to an existing
+        * direct mount we could be iterating through the map entries
+        * with the readlock held so we can't just take the writelock
+        * for direct mounts. But at when trying to re-connect to an
+        * existing mount at startup there won't be any other process
+        * updating the map entry cache.
+        */
+       if (ap->state == ST_INIT && ap->flags & MOUNT_FLAG_REMOUNT)
+               cache_readlock(mc);
+       else
+               cache_writelock(mc);
        ret = cache_update_offset(mc, name, m_key, m_mapent, age);
 
        me = cache_lookup_distinct(mc, m_key);
@@ -1582,7 +1593,18 @@ dont_expand:
                        free(myoptions);
                } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
 
-               cache_writelock(mc);
+               /*
+                * If we're starting up or trying to re-connect to an existing
+                * direct mount we could be iterating through the map entries
+                * with the readlock held so we can't just take the writelock
+                * for direct mounts. But at when trying to re-connect to an
+                * existing mount at startup there won't be any other process
+                * updating the map entry cache.
+                */
+               if (ap->state == ST_INIT && ap->flags & MOUNT_FLAG_REMOUNT)
+                       cache_readlock(mc);
+               else
+                       cache_writelock(mc);
                me = cache_lookup_distinct(mc, name);
                if (!me) {
                        cache_unlock(mc);

++++++ 0003-CHANGELOG-add-a-few-missing-entries.patch ++++++
>From df646c6579ffc035b9e31749a4d3c6b3d1d5bfc9 Mon Sep 17 00:00:00 2001
From: David Disseldorp <[email protected]>
Date: Fri, 31 Oct 2025 16:55:52 +1100
Subject: [PATCH 03/14] CHANGELOG: add a few missing entries

This is purely to ensure that Ian's patchset applies cleanly.

Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG | 3 +++
 1 file changed, 3 insertions(+)

Index: autofs-5.1.9/CHANGELOG
===================================================================
--- autofs-5.1.9.orig/CHANGELOG
+++ autofs-5.1.9/CHANGELOG
@@ -3,6 +3,9 @@
 - Fix incompatible function pointer types in cyrus-sasl module.
 - fix get parent multi-mount check in try_remount().
 - fix deadlock in remount.
+- fix state queue not processing state changes.
+- refactor mnts_get_expire_list().
+- add en xtra logging entry to tree_mapent_mount_offsets().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.

++++++ 0004-autofs-5.1.9-quiet-possibly-noisy-log-message.patch ++++++
>From a0f840d689a50154fbf500aaf0b5eb83e88e58ba Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:29 +0800
Subject: [PATCH 04/14] autofs-5.1.9 - quiet possibly noisy log message

The message that logs when a mount is already mounted and only the
timeout will be updated on map re-read can create a lot of noise in
the log for direct mount maps. But this is normal operation and is of
limited value for both direct and indirect maps, so remove it.

Signed-off-by: Ian Kent <[email protected]>
[ddiss: rebase without 6fdfbcd ("autofs-5.1.9 - make ioctl ops
 ->timeout() handle per-dentry expire")]
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG    | 1 +
 lib/mounts.c | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index f1fa82f..1bfbb60 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@
 - fix state queue not processing state changes.
 - refactor mnts_get_expire_list().
 - add en xtra logging entry to tree_mapent_mount_offsets().
+- quiet possibly noisy log message.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/lib/mounts.c b/lib/mounts.c
index 6dcf37a..c77fac7 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -2756,7 +2756,6 @@ static int remount_active_mount(struct autofs_point *ap,
 
        /* Re-reading the map, set timeout and return */
        if (ap->state == ST_READMAP) {
-               debug(ap->logopt, "already mounted, update timeout");
                ops->timeout(ap->logopt, fd, timeout);
                ops->close(ap->logopt, fd);
                return REMOUNT_READ_MAP;
-- 
2.51.0


++++++ 0005-autofs-5.1.9-fix-devid-update-on-reload.patch ++++++
>From f3019644344ff039f7ed1c0b2f0d83f9ff6f29b0 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:30 +0800
Subject: [PATCH 05/14] autofs-5.1.9 - fix devid update on reload

On map update if there's a direct mount in the master map it may be
associated with multiple maps.

If there's an entry that's been removed but is present in another map
and the removed entry has a real mount associated with it special case
handling is needed.

Currently the function that looks for these newly valid map entries
doesn't do it properly. It's meant to look for the first "valid" map
entry but doesn't check if the entry is valid. So if a valid entry
follows the an invalid entry it isn't found, the invalid entry is
returned instead.

Once this is fixed the handling of a removed direct mount entry that's
covered by a real mount can be done. Basically, the newly valid map
entry needs to take over the mount (which wasn't being done quite right
either) and the removed map entry deleted so that the covering mount can
expire. From this point onward the newly valid map entry will be used.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG           |  1 +
 daemon/lookup.c     | 38 ++++++++++++--------------------------
 daemon/state.c      | 17 +++++------------
 include/automount.h |  2 +-
 4 files changed, 19 insertions(+), 39 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 1bfbb60..34d06b0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@
 - refactor mnts_get_expire_list().
 - add en xtra logging entry to tree_mapent_mount_offsets().
 - quiet possibly noisy log message.
+- fix devid update on reload.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/lookup.c b/daemon/lookup.c
index dc77948..3791aa7 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -1348,6 +1348,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, 
struct mapent_cache *mc, ti
 
        me = cache_enumerate(mc, NULL);
        while (me) {
+               dev_t devid;
                struct mapent *valid;
                char *key = NULL, *next_key = NULL;
 
@@ -1405,6 +1406,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, 
struct mapent_cache *mc, ti
                        me = cache_enumerate(mc, me);
                        continue;
                }
+               devid = ap->type == LKP_INDIRECT ? ap->dev : me->dev;
 
                /*
                 * If this key has another valid entry we want to prune it,
@@ -1412,37 +1414,20 @@ void lookup_prune_one_cache(struct autofs_point *ap, 
struct mapent_cache *mc, ti
                 * mount if it is a direct mount or it's just a stale indirect
                 * cache entry.
                 */
-               valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
-               if (valid && valid->mc == mc) {
-                        /*
-                         * We've found a map entry that has been removed from
-                         * the current cache so it isn't really valid. Set the
-                         * mapent negative to prevent further mount requests
-                         * using the cache entry.
-                         */
-                       debug(ap->logopt, "removed map entry detected, mark 
negative");
-                       if (valid->mapent) {
-                               free(valid->mapent);
-                               valid->mapent = NULL;
-                       }
+               valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT, age);
+               if (valid)
                        cache_unlock(valid->mc);
-                       valid = NULL;
-               }
-               if (!valid &&
-                   is_mounted(path, MNTS_REAL)) {
+               else if (is_mounted(path, MNTS_REAL)) {
                        debug(ap->logopt, "prune postponed, %s mounted", path);
                        free(key);
                        free(path);
                        me = cache_enumerate(mc, me);
                        continue;
                }
-               if (valid)
-                       cache_unlock(valid->mc);
 
                me = cache_enumerate(mc, me);
                if (me)
                        next_key = strdup(me->key);
-
                cache_unlock(mc);
 
                cache_writelock(mc);
@@ -1455,10 +1440,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, 
struct mapent_cache *mc, ti
                if (valid)
                        cache_delete(mc, key);
                else if (!is_mounted(path, MNTS_AUTOFS)) {
-                       dev_t devid = ap->dev;
                        status = CHE_FAIL;
-                       if (ap->type == LKP_DIRECT)
-                               devid = this->dev;
                        if (this->ioctlfd == -1)
                                status = cache_delete(mc, key);
                        if (status != CHE_FAIL) {
@@ -1532,7 +1514,7 @@ int lookup_prune_cache(struct autofs_point *ap, time_t 
age)
 }
 
 /* Return with cache readlock held */
-struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char 
*key, unsigned int type)
+struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char 
*key, unsigned int type, time_t age)
 {
        struct master_mapent *entry = ap->entry;
        struct map_source *map;
@@ -1556,8 +1538,12 @@ struct mapent *lookup_source_valid_mapent(struct 
autofs_point *ap, const char *k
                        me = cache_lookup_distinct(mc, key);
                else
                        me = cache_lookup(mc, key);
-               if (me)
-                       break;
+               if (me) {
+                       /* Valid? */
+                       if (me->age >= age)
+                               break;
+                       me = NULL;
+               }
                cache_unlock(mc);
                map = map->next;
        }
diff --git a/daemon/state.c b/daemon/state.c
index 5fce6e3..b6728af 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -333,17 +333,7 @@ static int do_readmap_mount(struct autofs_point *ap,
                 * This is becuase of the requirement to continue running with
                 * an empty cache awaiting a map re-load.
                 */
-               valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT);
-               if (valid && valid->mc == me->mc) {
-                       /*
-                        * We've found a map entry that has been removed from
-                        * the current cache so there is no need to update it.
-                        * The stale entry will be dealt with when we prune the
-                        * cache later.
-                        */
-                       cache_unlock(valid->mc);
-                       valid = NULL;
-               }
+               valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT, 
now);
                if (valid) {
                        struct mapent_cache *vmc = valid->mc;
                        struct ioctl_ops *ops = get_ioctl_ops();
@@ -365,8 +355,11 @@ static int do_readmap_mount(struct autofs_point *ap,
                        /* Take over the mount if there is one */
                        valid->ioctlfd = me->ioctlfd;
                        me->ioctlfd = -1;
+                       /* Same path */
+                       valid->dev = me->dev;
+                       valid->ino = me->ino;
                        /* Set device and inode number of the new mapent */
-                       cache_set_ino_index(vmc, me);
+                       cache_set_ino_index(vmc, valid);
                        cache_unlock(vmc);
                        /* Set timeout and calculate the expire run frequency */
                        timeout = get_exp_timeout(ap, map);
diff --git a/include/automount.h b/include/automount.h
index 9548db8..a32b7c9 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -279,7 +279,7 @@ int lookup_nss_mount(struct autofs_point *ap, struct 
map_source *source, const c
 void lookup_close_lookup(struct autofs_point *ap);
 void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, 
time_t age);
 int lookup_prune_cache(struct autofs_point *ap, time_t age);
-struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char 
*key, unsigned int type);
+struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char 
*key, unsigned int type, time_t age);
 struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, 
unsigned int type);
 int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key);
 
-- 
2.51.0


++++++ 0006-autofs-5.1.9-fix-cache-writelock-must-be-taken-in-up.patch ++++++
>From 7bc36285913d69c2c815c1a89f71160cf8a85004 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:31 +0800
Subject: [PATCH 06/14] autofs-5.1.9 - fix cache writelock must be taken in
 update_map_cache()

In update_map_cache() the cache writelock must be taken because we need
to clean up the map entry as it will be a problem later if we don't.

It's possible that some other process has taken the lock temporarily but
when this function is called the thread does not hold any cache locks so
it should be ok to aquire it.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG          |  1 +
 daemon/automount.c | 12 +++++-------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 34d06b0..eda4f79 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,7 @@
 - add en xtra logging entry to tree_mapent_mount_offsets().
 - quiet possibly noisy log message.
 - fix devid update on reload.
+- fix cache writelock must be taken in update_map_cache().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/automount.c b/daemon/automount.c
index 6cb3b1b..d68064c 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -526,13 +526,11 @@ static void update_map_cache(struct autofs_point *ap, 
const char *path)
                }
 
                mc = map->mc;
-               /* If the lock is busy try later */
-               if (cache_try_writelock(mc)) {
-                       me = cache_lookup_distinct(mc, key);
-                       if (me && me->ioctlfd == -1)
-                               cache_delete(mc, key);
-                       cache_unlock(mc);
-               }
+               cache_writelock(mc);
+               me = cache_lookup_distinct(mc, key);
+               if (me && me->ioctlfd == -1)
+                       cache_delete(mc, key);
+               cache_unlock(mc);
 
                map = map->next;
        }
-- 
2.51.0


++++++ 0007-autofs-5.1.9-fix-skip-valid-map-entries-on-expire-cl.patch ++++++
>From 045a4dc9e0a0bf9363f8341d527806db5661da9a Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:32 +0800
Subject: [PATCH 07/14] autofs-5.1.9 - fix skip valid map entries on expire
 cleanup

After an expire if the current map entry is stale because it could not
be cleaned up during the map entry prune (due to the presence of a real
mount) it needs to be cleaned up after a successful expire.

Currently this is done by update_map_cache() if the entry is contained
in an invalid map but it should be doing it if the entry is no longer
valid. In addition, if update_map_cache() gets called the umount has
been successful so the ioctlfd does not need to be checked (and is in
fact updated later in the expire process).

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG          | 1 +
 daemon/automount.c | 9 ++-------
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index eda4f79..9ec26ef 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@
 - quiet possibly noisy log message.
 - fix devid update on reload.
 - fix cache writelock must be taken in update_map_cache().
+- fix skip valid map entries on expire cleanup.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/automount.c b/daemon/automount.c
index d68064c..26e3a5c 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -519,16 +519,11 @@ static void update_map_cache(struct autofs_point *ap, 
const char *path)
        while (map) {
                struct mapent *me = NULL;
 
-               /* Skip current, in-use cache */
-               if (ap->entry->age <= map->age) {
-                       map = map->next;
-                       continue;
-               }
-
                mc = map->mc;
                cache_writelock(mc);
                me = cache_lookup_distinct(mc, key);
-               if (me && me->ioctlfd == -1)
+               /* Only for invalid map entries */
+               if (me && map->age > me->age)
                        cache_delete(mc, key);
                cache_unlock(mc);
 
-- 
2.51.0


++++++ 0008-autofs-5.1.9-remove-unnecessary-call-to-set_direct_m.patch ++++++
>From a587657840051907384ff0c7a788cfb11da36c4d Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:33 +0800
Subject: [PATCH 08/14] autofs-5.1.9 - remove unnecessary call to
 set_direct_mount_tree_catatonic()

Function do_umount_autofs_direct() is called in two cases, during a
readmap and when umounting top level direct mounts.

During a readmap, mounts should not be set catatonic so the call to
set_direct_mount_tree_catatonic() is not needed. If it's called for a
top level direct mount the caller, umount_autofs_direct(), calls
set_direct_mount_tree_catatonic() itself already. So remove this
unnecessary call.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG       | 1 +
 daemon/direct.c | 5 +----
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 9ec26ef..36a19d6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,7 @@
 - fix devid update on reload.
 - fix cache writelock must be taken in update_map_cache().
 - fix skip valid map entries on expire cleanup.
+- remove unnecessary call to set_direct_mount_tree_catatonic().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/direct.c b/daemon/direct.c
index a9d7128..973be6f 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -186,11 +186,8 @@ int do_umount_autofs_direct(struct autofs_point *ap, 
struct mapent *me)
                        warn(ap->logopt, "mount point %s is in use", me->key);
                        if (ap->state == ST_SHUTDOWN_FORCE)
                                goto force_umount;
-                       else {
-                               if (ap->state != ST_READMAP)
-                                       set_direct_mount_tree_catatonic(ap, me);
+                       else
                                return 0;
-                       }
                        break;
                case ENOTDIR:
                        error(ap->logopt, "mount point is not a directory");
-- 
2.51.0


++++++ 0009-autofs-5.1.9-remove-unnecessary-assignment-in-umount.patch ++++++
>From aa035fffd014a84a9d3a2da2b06e66f494080065 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:34 +0800
Subject: [PATCH 09/14] autofs-5.1.9 - remove unnecessary assignment in
 umount_multi()

Remove the leftover initialisation of left from when there were multiple
calls to umount_subtree_mounts().

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG          | 1 +
 daemon/automount.c | 4 +---
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 36a19d6..3f7c425 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,7 @@
 - fix cache writelock must be taken in update_map_cache().
 - fix skip valid map entries on expire cleanup.
 - remove unnecessary call to set_direct_mount_tree_catatonic().
+- remove unnecessary assignment in umount_multi().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/automount.c b/daemon/automount.c
index 26e3a5c..348b3a7 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -710,9 +710,7 @@ int umount_multi(struct autofs_point *ap, const char *path, 
int incl)
                mnts_put_mount(sbmnt);
        }
 
-       left = 0;
-
-       left += umount_subtree_mounts(ap, path, is_autofs_fs);
+       left = umount_subtree_mounts(ap, path, is_autofs_fs);
 
        /* Delete detritus like unwanted mountpoints and symlinks */
        if (left == 0 &&
-- 
2.51.0


++++++ 0010-autofs-5.1.9-fix-direct-mount-trigger-umount-failure.patch ++++++
>From 1f6f3085e2d0f2b42235ce7f706e8aa21ac65e03 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:35 +0800
Subject: [PATCH 10/14] autofs-5.1.9 - fix direct mount trigger umount failure
 case

In function do_umount_autofs_direct() for the case where the trigger
mount is found to be in use we should be detaching the mount so it gets
umounted but the process can continue using it while it has an open file
handle for it.

This is because direct mount triggers are only umounted when the map
entry is removed from a map or automount(8) is shutdown which in both
cases the trigger mount needs to go away.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG       | 1 +
 daemon/direct.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
index 3f7c425..d4e9834 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@
 - fix skip valid map entries on expire cleanup.
 - remove unnecessary call to set_direct_mount_tree_catatonic().
 - remove unnecessary assignment in umount_multi().
+- fix direct mount trigger umount failure case.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/direct.c b/daemon/direct.c
index 973be6f..6999d2a 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -153,6 +153,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct 
mapent *me)
                        } else {
                                me->ioctlfd = -1;
                                ops->close(ap->logopt, ioctlfd);
+                               rv = -1;
                                goto force_umount;
                        }
                }
-- 
2.51.0


++++++ 0011-autofs-5.1.9-refactor-do_umount_autofs_direct.patch ++++++
>From 2720ad7c2a242e592f85d28473a8e4a4047c7ce1 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:36 +0800
Subject: [PATCH 11/14] autofs-5.1.9 - refactor do_umount_autofs_direct()

Refactor functon do_umount_autofs_direct() so that it can be called from
do_expire_direct() to clean up stale direct mounts that couldn't be
cleaned up at map re-load.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG       |   1 +
 daemon/direct.c | 106 ++++++++++++++++++++++++++----------------------
 2 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index d4e9834..85afa94 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@
 - remove unnecessary call to set_direct_mount_tree_catatonic().
 - remove unnecessary assignment in umount_multi().
 - fix direct mount trigger umount failure case.
+- refactor do_umount_autofs_direct().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/direct.c b/daemon/direct.c
index 6999d2a..e724a0f 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -81,12 +81,66 @@ static void mnts_cleanup(void *arg)
        mnts_put_expire_list(mnts);
 }
 
+static int finish_umount(struct autofs_point *ap, struct mapent *me, int rv)
+{
+       char buf[MAX_ERR_BUF];
+
+       if (rv != 0) {
+               info(ap->logopt, "forcing umount of direct mount %s", me->key);
+               rv = umount2(me->key, MNT_DETACH);
+       } else
+               info(ap->logopt, "umounted direct mount %s", me->key);
+
+       if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
+               if  (rmdir(me->key) == -1) {
+                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+                       warn(ap->logopt, "failed to remove dir %s: %s",
+                            me->key, estr);
+               }
+       }
+       return rv;
+}
+
+static int do_umount_direct(struct autofs_point *ap, struct mapent *me)
+{
+       int rv, retries = UMOUNT_RETRIES;
+
+       while ((rv = umount(me->key)) == -1 && retries--) {
+               struct timespec tm = {0, 50000000};
+               if (errno != EBUSY)
+                       break;
+               nanosleep(&tm, NULL);
+       }
+
+       if (rv == -1) {
+               switch (errno) {
+               case ENOENT:
+               case EINVAL:
+                       warn(ap->logopt, "mount point %s does not exist",
+                             me->key);
+                       return 0;
+               case EBUSY:
+                       warn(ap->logopt, "mount point %s is in use", me->key);
+                       if (ap->state == ST_SHUTDOWN_FORCE)
+                               goto out;
+                       else
+                               return 0;
+               case ENOTDIR:
+                       error(ap->logopt, "mount point is not a directory");
+                       return 0;
+               }
+               return 1;
+       }
+out:
+       return finish_umount(ap, me, rv);
+}
+
 int do_umount_autofs_direct(struct autofs_point *ap, struct mapent *me)
 {
        struct ioctl_ops *ops = get_ioctl_ops();
        struct mapent_cache *mc = me->mc;
        char buf[MAX_ERR_BUF];
-       int ioctlfd = -1, rv, left, retries;
+       int ioctlfd = -1, rv, left;
        char key[PATH_MAX + 1];
        struct mapent *tmp;
        int opened = 0;
@@ -153,8 +207,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct 
mapent *me)
                        } else {
                                me->ioctlfd = -1;
                                ops->close(ap->logopt, ioctlfd);
-                               rv = -1;
-                               goto force_umount;
+                               return finish_umount(ap, me, -1);
                        }
                }
                me->ioctlfd = -1;
@@ -167,52 +220,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, 
struct mapent *me)
 
        sched_yield();
 
-       retries = UMOUNT_RETRIES;
-       while ((rv = umount(me->key)) == -1 && retries--) {
-               struct timespec tm = {0, 50000000};
-               if (errno != EBUSY)
-                       break;
-               nanosleep(&tm, NULL);
-       }
-
-       if (rv == -1) {
-               switch (errno) {
-               case ENOENT:
-               case EINVAL:
-                       warn(ap->logopt, "mount point %s does not exist",
-                             me->key);
-                       return 0;
-                       break;
-               case EBUSY:
-                       warn(ap->logopt, "mount point %s is in use", me->key);
-                       if (ap->state == ST_SHUTDOWN_FORCE)
-                               goto force_umount;
-                       else
-                               return 0;
-                       break;
-               case ENOTDIR:
-                       error(ap->logopt, "mount point is not a directory");
-                       return 0;
-                       break;
-               }
-               return 1;
-       }
-
-force_umount:
-       if (rv != 0) {
-               info(ap->logopt, "forcing umount of direct mount %s", me->key);
-               rv = umount2(me->key, MNT_DETACH);
-       } else
-               info(ap->logopt, "umounted direct mount %s", me->key);
-
-       if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
-               if  (rmdir(me->key) == -1) {
-                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-                       warn(ap->logopt, "failed to remove dir %s: %s",
-                            me->key, estr);
-               }
-       }
-       return rv;
+       return do_umount_direct(ap, me);
 }
 
 int umount_autofs_direct(struct autofs_point *ap)
-- 
2.51.0


++++++ 0012-autofs-5.1.9-fix-stale-direct-mount-trigger-not-umou.patch ++++++
>From 9ef154bfe91b0702d9df039886f7dd6a1880c03d Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:37 +0800
Subject: [PATCH 12/14] autofs-5.1.9 - fix stale direct mount trigger not
 umounted on expire

If a direct mount map entry is removed but has an active real mount the
mount trigger needs to be unmounted during the expire cleanup.

If the direct mount map entry has been re-added the map entry age will
have been updated so the entry won't be seen as stale so the umount
won't be done.

Also in function umount_multi() update_map_cache() and check_rm_dirs()
are not called for direct mounts because count_mounts() always returns
1 or more for top level direct mounts. Make this clear by using ap->type
in the logical check and rely on the left == 0 check to verify there are
no remaining mounts for indirect mounts since count_mounts() will be
more expensive.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG          |  1 +
 daemon/automount.c | 12 ++++++++----
 daemon/direct.c    | 22 +++++++++++++++++++++-
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 85afa94..b97214a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,7 @@
 - remove unnecessary assignment in umount_multi().
 - fix direct mount trigger umount failure case.
 - refactor do_umount_autofs_direct().
+- fix stale direct mount trigger not umounted on expire.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/automount.c b/daemon/automount.c
index 348b3a7..c353fac 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -712,10 +712,14 @@ int umount_multi(struct autofs_point *ap, const char 
*path, int incl)
 
        left = umount_subtree_mounts(ap, path, is_autofs_fs);
 
-       /* Delete detritus like unwanted mountpoints and symlinks */
-       if (left == 0 &&
-           ap->state != ST_READMAP &&
-           !count_mounts(ap, path, ap->dev)) {
+       /* Delete detritus like unwanted mountpoints and symlinks
+        * for indirect mounts. This can't be done for direct mounts
+        * here because there's an ioctl file handle open on the
+        * autofs trigger mount for them so it must be done after
+        * the expire.
+        */
+       if (ap->type == LKP_INDIRECT &&
+           ap->state != ST_READMAP && left == 0) {
                update_map_cache(ap, path);
                check_rm_dirs(ap, path, incl);
        }
diff --git a/daemon/direct.c b/daemon/direct.c
index e724a0f..be498d6 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -1002,10 +1002,30 @@ static void *do_expire_direct(void *arg)
                               mt.ioctlfd, mt.wait_queue_token, -ENOENT);
        else {
                struct mapent *me;
+
                cache_writelock(mt.mc);
                me = cache_lookup_distinct(mt.mc, mt.name);
-               if (me)
+               if (me) {
+                       /* If the direct mount map entry is no longer
+                        * valid but there is an autofs mount trigger
+                        * for the mount the mount trigger needs to be
+                        * umounted, the map entry deleted and the mount
+                        * point directory removed (if it was created by
+                        * us).
+                        */
                        me->ioctlfd = -1;
+                       if (me->mc->map->age > me->age &&
+                           is_mounted(mt.name, MNTS_AUTOFS)) {
+                               /* We must detach the mount becuase the
+                                * umount must be completed before
+                                * notifying status to the kernel but
+                                * there's an ioctlfd open on the
+                                * trigger.
+                                */
+                               if (!finish_umount(ap, me, -1))
+                                       cache_delete(me->mc, me->key);
+                       }
+               }
                cache_unlock(mt.mc);
                ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
                ops->close(ap->logopt, mt.ioctlfd);
-- 
2.51.0


++++++ 0013-autofs-5.1.9-add-function-table_lookup_ino.patch ++++++
>From 694a6ae8ba08808b72066ea2dad93a9c7878b0e3 Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:38 +0800
Subject: [PATCH 13/14] autofs-5.1.9 - add function table_lookup_ino()

Add function table_lookup_ino() to try and locate a mount for a given
device, open a file handle for it, and return it's path in the provided
buffer.

Signed-off-by: Ian Kent <[email protected]>
[ddiss: proc_mounts option parsing looks fragile here]
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG        |  1 +
 include/mounts.h |  1 +
 lib/mounts.c     | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
index b97214a..f9aafd4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@
 - fix direct mount trigger umount failure case.
 - refactor do_umount_autofs_direct().
 - fix stale direct mount trigger not umounted on expire.
+- add function table_lookup_ino().
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/include/mounts.h b/include/mounts.h
index 8e6f62a..6141bc4 100644
--- a/include/mounts.h
+++ b/include/mounts.h
@@ -173,6 +173,7 @@ void mnts_remove_amdmounts(struct autofs_point *ap);
 struct mnt_list *mnts_add_mount(struct autofs_point *ap, const char *name, 
unsigned int flags);
 void mnts_remove_mount(const char *mp, unsigned int flags);
 struct mnt_list *get_mnt_list(const char *path, int include);
+char *table_lookup_ino(struct autofs_point *ap, dev_t dev, ino_t ino, char 
*buf, size_t len, int *fd);
 unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
 int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr);
 void tree_free(struct tree_node *root);
diff --git a/lib/mounts.c b/lib/mounts.c
index c77fac7..c89943c 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -2324,6 +2324,76 @@ void free_mnt_list(struct mnt_list *list)
        }
 }
 
+char *table_lookup_ino(struct autofs_point *ap,
+                      dev_t dev, ino_t ino,
+                      char *buf, size_t len, int *fd)
+{
+       struct ioctl_ops *ops;
+       struct mntent *mnt;
+       struct mntent mnt_wrk;
+       char tmp[PATH_MAX * 3];
+       char *path = NULL;
+       FILE *tab;
+       int ret = 0;
+
+       ops = get_ioctl_ops();
+       if (!ops) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       tab = open_fopen_r(_PROC_MOUNTS);
+       if (!tab) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       while ((mnt = local_getmntent_r(tab, &mnt_wrk, tmp, PATH_MAX * 3))) {
+               unsigned int type;
+               int ioctlfd;
+               dev_t devid;
+
+               if (strcmp(mnt->mnt_type, "autofs"))
+                       continue;
+
+               type = t_direct;
+               if (strstr(mnt->mnt_opts, "indirect"))
+                       type = t_indirect;
+               else if (strstr(mnt->mnt_opts, "offset"))
+                       type = t_offset;
+
+               ret = ops->mount_device(ap->logopt, mnt->mnt_dir, type, &devid);
+               if (ret == -1 || ret == 0)
+                       continue;
+
+               ioctlfd = open_ioctlfd(ap, mnt->mnt_dir, devid);
+               if (fd > 0) {
+                       struct stat st;
+
+                       if (fstat(ioctlfd, &st) == -1) {
+                               ops->close(ap->logopt, ioctlfd);
+                               continue;
+                       }
+
+                       if (strlen(mnt->mnt_dir) >= len) {
+                               errno = ENAMETOOLONG;
+                               break;
+                       }
+
+                       if (st.st_dev == dev && st.st_ino == ino) {
+                               strcpy(buf, mnt->mnt_dir);
+                               path = buf;
+                               *fd = ioctlfd;
+                               break;
+                       }
+                       ops->close(ap->logopt, ioctlfd);
+               }
+       }
+       fclose(tab);
+
+       return path;
+}
+
 static int table_is_mounted(const char *mp, unsigned int type)
 {
        struct mntent *mnt;
-- 
2.51.0


++++++ 0014-autofs-5.1.9-improve-handling-of-missing-map-entry-f.patch ++++++
>From 5b5cf984cef487cc7672cb709c03b08512537a3f Mon Sep 17 00:00:00 2001
From: Ian Kent <[email protected]>
Date: Fri, 31 Oct 2025 09:31:39 +0800
Subject: [PATCH 14/14] autofs-5.1.9 - improve handling of missing map entry
 for mount request

If the map entry isn't found it must have been deleted from the map but
a trigger mount is still mounted because it has sent us this request.
Use the mount table for a brute force lookup to get the path and open a
file handle for it so we can send a failure status to the kernel.

Also remove the crit() log message following open_ioctlfd() as it already
issues an appropriate error message on failure.

Signed-off-by: Ian Kent <[email protected]>
Acked-by: David Disseldorp <[email protected]>
---
 CHANGELOG       |  1 +
 daemon/direct.c | 49 +++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index f9aafd4..2725130 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@
 - refactor do_umount_autofs_direct().
 - fix stale direct mount trigger not umounted on expire.
 - add function table_lookup_ino().
+- improve handling of missing map entry for mount request.
 
 02/11/2023 autofs-5.1.9
 - fix kernel mount status notification.
diff --git a/daemon/direct.c b/daemon/direct.c
index be498d6..123611d 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -1371,12 +1371,50 @@ int handle_packet_missing_direct(struct autofs_point 
*ap, autofs_packet_missing_
        }
 
        if (!me) {
-               /*
-                * Shouldn't happen as the kernel is telling us
-                * someone has walked on our mount point.
+               char tmp[PATH_MAX + 1];
+               char *path;
+
+               /* If the map entry wasn't found it must have been deleted
+                * from the map but a trigger mount is still mounted because
+                * it has sent us this request. So use the mount table for a
+                * brute force lookup to get the path and open a file handle
+                * for it so we can return a not found status to the kernel.
                 */
-               logerr("can't find map entry for (%lu,%lu)",
-                   (unsigned long) pkt->dev, (unsigned long) pkt->ino);
+               path = table_lookup_ino(ap, pkt->dev, pkt->ino, tmp, PATH_MAX + 
1, &ioctlfd);
+               if (!path) {
+                       /* This could be cuased by an inability to open a file
+                        * handle but generally that doesn't happen. The mount
+                        * has to exist and be pinned becuase we got this 
request
+                        * so it can't be umounted. Therefore it's very unlikely
+                        * this case will happen. If it does happen it's fatal,
+                        * the waiter will hang and there's nothing we can do
+                        * about it.
+                        */
+                       logerr("can't find mount for (%lu,%lu)",
+                           (unsigned long) pkt->dev, (unsigned long) pkt->ino);
+                       /* TODO:  how do we clear wait q in kernel ?? */
+               } else {
+                       int rv;
+
+                       /* Try and recover from this unexpecyedly missing map
+                        * entry by detaching the direct mount trigger that
+                        * sent the request so it's no longer visible to the
+                        * VFS.
+                        */
+                       info(ap->logopt, "forcing umount of direct mount %s", 
path);
+                       rv = umount2(path, MNT_DETACH);
+                       if  (rmdir(path) == -1) {
+                               char buf[MAX_ERR_BUF];
+                               char *estr;
+
+                               estr = strerror_r(errno, buf, MAX_ERR_BUF);
+                               warn(ap->logopt,
+                                    "failed to remove dir %s: %s", path, estr);
+                       }
+                       ops->send_fail(ap->logopt,
+                                      ioctlfd, pkt->wait_queue_token, -EINVAL);
+                       ops->close(ap->logopt, ioctlfd);
+               }
                master_source_unlock(ap->entry);
                master_mutex_unlock();
                pthread_setcancelstate(state, NULL);
@@ -1395,7 +1433,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, 
autofs_packet_missing_
                master_source_unlock(ap->entry);
                master_mutex_unlock();
                pthread_setcancelstate(state, NULL);
-               crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
                /* TODO:  how do we clear wait q in kernel ?? */
                return 1;
        }
-- 
2.51.0

Reply via email to