autofs 5.0.3 - check for exported mounts automatically mounted by kernel From: Ian Kent If a server exports file systems that are automatically mounted by the kernel client autofs will mistakenly over mount them when it constructs and mounts its multi-mount triggers. This patch makes autofs check for this case and ignores them if the kernel mounts them while it mounts multi-mount triggers. We don't want to fight with NFS over mounting these because it confuses autofs and they magically go away when the owner mount is umounted. This isn't ideal because autofs will mount these mounts while constructing its multi-mount triggers but it is unavoidable at the moment. --- CHANGELOG | 1 + daemon/direct.c | 26 ++++++++++++++++++-------- include/automount.h | 4 ++++ lib/parse_subs.c | 26 ++++++++++++++++++-------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ff4a265..d953d2d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ - init SASL callbacks on every ldap lookup library load. - fix incorrect match of map type name when included in map name. - fix incorrect pthreads condition handling for mount requests. +- add check for exports automatically mounted by NFS kernel client. 14/01/2008 autofs-5.0.3 ----------------------- diff --git a/daemon/direct.c b/daemon/direct.c index a9dda87..86c817c 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -664,12 +664,12 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) if (ap->state != ST_READMAP) warn(ap->logopt, "trigger %s already mounted", me->key); - return 0; + return MOUNT_OFFSET_OK; } if (me->ioctlfd != -1) { error(ap->logopt, "active offset mount %s", me->key); - return -1; + return MOUNT_OFFSET_FAIL; } status = pthread_once(&key_mnt_params_once, key_mnt_params_init); @@ -683,7 +683,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) crit(ap->logopt, "mnt_params value create failed for offset mount %s", me->key); - return 0; + return MOUNT_OFFSET_OK; } mp->options = NULL; @@ -697,12 +697,22 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) if (!mp->options) { mp->options = make_options_string(ap->path, ap->kpipefd, "offset"); if (!mp->options) - return 0; + return MOUNT_OFFSET_OK; } /* In case the directory doesn't exist, try to mkdir it */ if (mkdir_path(me->key, 0555) < 0) { if (errno == EEXIST) { + /* + * If the mount point directory is a real mount + * and it isn't the root offset then it must be + * a mount that has been automatically mounted by + * the kernel NFS client. + */ + if (me->multi != me && + is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) + return MOUNT_OFFSET_IGNORE; + /* * If we recieve an error, and it's EEXIST * we know the directory was not created. @@ -721,13 +731,13 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) debug(ap->logopt, "can't create mount directory: %s, %s", me->key, estr); - return -1; + return MOUNT_OFFSET_FAIL; } else { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); crit(ap->logopt, "failed to create mount directory: %s, %s", me->key, estr); - return -1; + return MOUNT_OFFSET_FAIL; } } else { /* No errors so the directory was successfully created */ @@ -787,7 +797,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) debug(ap->logopt, "mounted trigger %s", me->key); - return 0; + return MOUNT_OFFSET_OK; out_close: close(ioctlfd); @@ -797,7 +807,7 @@ out_err: if (stat(me->key, &st) == 0 && me->dir_created) rmdir_path(ap, me->key, st.st_dev); - return -1; + return MOUNT_OFFSET_FAIL; } static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt) diff --git a/include/automount.h b/include/automount.h index cd8ce7b..d59be77 100644 --- a/include/automount.h +++ b/include/automount.h @@ -468,6 +468,10 @@ struct autofs_point { /* Standard functions used by daemon or modules */ +#define MOUNT_OFFSET_OK 0 +#define MOUNT_OFFSET_FAIL -1 +#define MOUNT_OFFSET_IGNORE -2 + void *handle_mounts(void *arg); int umount_multi(struct autofs_point *ap, const char *path, int incl); int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token); diff --git a/lib/parse_subs.c b/lib/parse_subs.c index 5422fef..27cb0fc 100644 --- a/lib/parse_subs.c +++ b/lib/parse_subs.c @@ -390,7 +390,7 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, struct list_head *pos = NULL; unsigned int fs_path_len; unsigned int mounted; - int start; + int ret, start; fs_path_len = strlen(root) + strlen(base); if (fs_path_len > PATH_MAX) @@ -411,15 +411,25 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, } oe = cache_lookup_offset(base, offset, start, &me->multi_list); - if (!oe) + if (!oe || !oe->mapent) goto cont; debug(ap->logopt, "mount offset %s", oe->key); - if (mount_autofs_offset(ap, oe) < 0) - warn(ap->logopt, "failed to mount offset"); - else + ret = mount_autofs_offset(ap, oe); + if (ret >= MOUNT_OFFSET_OK) mounted++; + else { + if (ret != MOUNT_OFFSET_IGNORE) + warn(ap->logopt, "failed to mount offset"); + else { + debug(ap->logopt, + "ignoring \"nohide\" trigger %s", + oe->key); + free(oe->mapent); + oe->mapent = NULL; + } + } cont: offset = cache_get_offset(base, offset, start, &me->multi_list, &pos); @@ -457,7 +467,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); /* root offset is a special case */ - if (!oe || (strlen(oe->key) - start) == 1) + if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) continue; /* @@ -481,7 +491,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); /* root offset is a special case */ - if (!oe || (strlen(oe->key) - start) == 1) + if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) continue; debug(ap->logopt, "umount offset %s", oe->key); @@ -505,7 +515,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) { info(ap->logopt, "unmounting dir = %s", root); if (umount_ent(ap, root)) { - if (!mount_multi_triggers(ap, root, me, "/")) + if (mount_multi_triggers(ap, root, me, "/") < 0) warn(ap->logopt, "failed to remount offset triggers"); return left++;