You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.4 KiB
187 lines
5.4 KiB
autofs-5.1.1 - always set direct mounts catatonic at exit |
|
|
|
From: Ian Kent <raven@themaw.net> |
|
|
|
Direct mounts are all mounted at application start or when the map |
|
is re-read and entries have been added. |
|
|
|
They are only ever umounted at application exit or when the map is |
|
re-read and entries have been removed. |
|
|
|
If these mounts are in use (so that they are not umounted) and aren't |
|
set catatonic at exit and an application attempts to access the path |
|
it will lead to a hang as there is no daemon to answer the mount |
|
request. |
|
|
|
It's questionable whether to set busy direct mounts catatonic when |
|
attempting to umount them when re-reading the map as the mount may |
|
then expire leaving an unresponsive direct mount trigger that hasn't |
|
yet been cleaned from the map entry cache. |
|
|
|
Signed-off-by: Ian Kent <raven@themaw.net> |
|
--- |
|
CHANGELOG | 1 |
|
daemon/direct.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++----- |
|
2 files changed, 92 insertions(+), 8 deletions(-) |
|
|
|
--- autofs-5.0.7.orig/CHANGELOG |
|
+++ autofs-5.0.7/CHANGELOG |
|
@@ -186,6 +186,7 @@ |
|
- add remote-fs.target systemd dependency. |
|
- gaurd against incorrect umount return. |
|
- fix typo in autofs.conf. |
|
+- always set direct mounts catatonic at exit. |
|
|
|
25/07/2012 autofs-5.0.7 |
|
======================= |
|
--- autofs-5.0.7.orig/daemon/direct.c |
|
+++ autofs-5.0.7/daemon/direct.c |
|
@@ -82,6 +82,65 @@ static void mnts_cleanup(void *arg) |
|
return; |
|
} |
|
|
|
+/* When exiting direct mount triggers must be set catatonic, regardless |
|
+ * of whether they are busy on not, to avoid a hang on access once the |
|
+ * daemon has gone away. |
|
+ */ |
|
+static int set_direct_mount_catatonic(struct autofs_point *ap, struct mapent *me, int ioctlfd) |
|
+{ |
|
+ struct ioctl_ops *ops = get_ioctl_ops(); |
|
+ unsigned int opened = 0; |
|
+ char buf[MAX_ERR_BUF]; |
|
+ int fd = -1; |
|
+ int error; |
|
+ |
|
+ /* In case the miscellaneous device isn't being used try |
|
+ * and use an existing ioctl control fd. In this case if |
|
+ * we don't already have an ioctl fd the mount can't be |
|
+ * set catatonic if it's covered. |
|
+ */ |
|
+ if (ioctlfd >= 0) |
|
+ fd = ioctlfd; |
|
+ else if (me->ioctlfd >= 0) |
|
+ fd = me->ioctlfd; |
|
+ else { |
|
+ error = ops->open(ap->logopt, &fd, me->dev, me->key); |
|
+ if (error == -1) { |
|
+ int err = errno; |
|
+ char *estr; |
|
+ |
|
+ estr = strerror_r(errno, buf, MAX_ERR_BUF); |
|
+ error(ap->logopt, |
|
+ "failed to open ioctlfd for %s, error: %s", |
|
+ me->key, estr); |
|
+ return err; |
|
+ } |
|
+ opened = 1; |
|
+ } |
|
+ |
|
+ if (fd >= 0) { |
|
+ error = ops->catatonic(ap->logopt, fd); |
|
+ if (error == -1) { |
|
+ int err = errno; |
|
+ char *estr; |
|
+ |
|
+ estr = strerror_r(errno, buf, MAX_ERR_BUF); |
|
+ error(ap->logopt, |
|
+ "failed to set %s catatonic, error: %s", |
|
+ me->key, estr); |
|
+ if (opened) |
|
+ ops->close(ap->logopt, fd); |
|
+ return err; |
|
+ } |
|
+ if (opened) |
|
+ ops->close(ap->logopt, fd); |
|
+ } |
|
+ |
|
+ debug(ap->logopt, "set %s catatonic", me->key); |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me) |
|
{ |
|
struct ioctl_ops *ops = get_ioctl_ops(); |
|
@@ -97,7 +156,8 @@ int do_umount_autofs_direct(struct autof |
|
} |
|
|
|
if (me->ioctlfd != -1) { |
|
- if (tree_is_mounted(mnts, me->key, MNTS_REAL)) { |
|
+ if (ap->state == ST_READMAP && |
|
+ tree_is_mounted(mnts, me->key, MNTS_REAL)) { |
|
error(ap->logopt, |
|
"attempt to umount busy direct mount %s", |
|
me->key); |
|
@@ -116,7 +176,12 @@ int do_umount_autofs_direct(struct autof |
|
if (rv) { |
|
char *estr = strerror_r(errno, buf, MAX_ERR_BUF); |
|
error(ap->logopt, "ioctl failed: %s", estr); |
|
- if (opened && ioctlfd != -1) |
|
+ /* The ioctl failed so this probably won't |
|
+ * work either but since we opened it here |
|
+ * try anyway. We should set these catatonic |
|
+ * too but .... |
|
+ */ |
|
+ if (opened) |
|
ops->close(ap->logopt, ioctlfd); |
|
return 1; |
|
} else if (!status) { |
|
@@ -124,18 +189,20 @@ int do_umount_autofs_direct(struct autof |
|
error(ap->logopt, |
|
"ask umount returned busy for %s", |
|
me->key); |
|
- if (opened && ioctlfd != -1) |
|
+ if (ap->state != ST_READMAP) |
|
+ set_direct_mount_catatonic(ap, me, ioctlfd); |
|
+ if (opened) |
|
ops->close(ap->logopt, ioctlfd); |
|
return 1; |
|
} else { |
|
me->ioctlfd = -1; |
|
- ops->catatonic(ap->logopt, ioctlfd); |
|
+ set_direct_mount_catatonic(ap, me, ioctlfd); |
|
ops->close(ap->logopt, ioctlfd); |
|
goto force_umount; |
|
} |
|
} |
|
me->ioctlfd = -1; |
|
- ops->catatonic(ap->logopt, ioctlfd); |
|
+ set_direct_mount_catatonic(ap, me, ioctlfd); |
|
ops->close(ap->logopt, ioctlfd); |
|
} else { |
|
error(ap->logopt, |
|
@@ -212,15 +279,31 @@ int umount_autofs_direct(struct autofs_p |
|
cache_readlock(mc); |
|
me = cache_enumerate(mc, NULL); |
|
while (me) { |
|
+ int error; |
|
+ |
|
ne = cache_lookup_distinct(nc, me->key); |
|
if (ne && map->master_line > ne->age) { |
|
me = cache_enumerate(mc, me); |
|
continue; |
|
} |
|
|
|
- /* TODO: check return, locking me */ |
|
- do_umount_autofs_direct(ap, mnts, me); |
|
- |
|
+ /* The daemon is exiting so ... |
|
+ * If we get a fail here we must make our |
|
+ * best effort to set the direct mount trigger |
|
+ * catatonic regardless of the reason for the |
|
+ * failed umount. |
|
+ */ |
|
+ error = do_umount_autofs_direct(ap, mnts, me); |
|
+ if (!error) |
|
+ goto done; |
|
+ |
|
+ error = set_direct_mount_catatonic(ap, me, me->ioctlfd); |
|
+ if (!error) |
|
+ goto done; |
|
+ |
|
+ /* We really need to set this, last ditch attempt */ |
|
+ set_direct_mount_catatonic(ap, me, -1); |
|
+done: |
|
me = cache_enumerate(mc, me); |
|
} |
|
pthread_cleanup_pop(1);
|
|
|