499 lines
15 KiB
Diff
499 lines
15 KiB
Diff
autofs-5.0.6 - add hup signal handling to hosts map
|
|
|
|
From: Ian Kent <ikent@redhat.com>
|
|
|
|
Add HUP signal handling to the internal hosts lookup module.
|
|
---
|
|
|
|
CHANGELOG | 1
|
|
daemon/direct.c | 4 -
|
|
include/mounts.h | 1
|
|
lib/mounts.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
man/auto.master.5.in | 5 +
|
|
man/autofs.5 | 8 +-
|
|
modules/lookup_hosts.c | 97 ++++++++++++++++++++++++-----
|
|
modules/parse_sun.c | 9 ++
|
|
8 files changed, 262 insertions(+), 25 deletions(-)
|
|
|
|
|
|
--- autofs-5.0.6.orig/CHANGELOG
|
|
+++ autofs-5.0.6/CHANGELOG
|
|
@@ -57,6 +57,7 @@
|
|
- fix offset mount point directory removal.
|
|
- fix remount of multi mount.
|
|
- fix devce ioctl alloc path check.
|
|
+- add hup signal handling to hosts map.
|
|
|
|
28/06/2011 autofs-5.0.6
|
|
-----------------------
|
|
--- autofs-5.0.6.orig/daemon/direct.c
|
|
+++ autofs-5.0.6/daemon/direct.c
|
|
@@ -654,7 +654,9 @@ int mount_autofs_offset(struct autofs_po
|
|
ret = try_remount(ap, me, t_offset);
|
|
if (ret == 1)
|
|
return MOUNT_OFFSET_OK;
|
|
- return MOUNT_OFFSET_FAIL;
|
|
+ /* Offset mount not found, fall thru and try to mount it */
|
|
+ if (!(ret == -1 && errno == ENOENT))
|
|
+ return MOUNT_OFFSET_FAIL;
|
|
} else {
|
|
/*
|
|
if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
|
|
--- autofs-5.0.6.orig/include/mounts.h
|
|
+++ autofs-5.0.6/include/mounts.h
|
|
@@ -112,5 +112,6 @@ int try_remount(struct autofs_point *, s
|
|
int umount_ent(struct autofs_point *, const char *);
|
|
int mount_multi_triggers(struct autofs_point *, struct mapent *, const char *, unsigned int, const char *);
|
|
int umount_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
|
|
+int clean_stale_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
|
|
|
|
#endif
|
|
--- autofs-5.0.6.orig/lib/mounts.c
|
|
+++ autofs-5.0.6/lib/mounts.c
|
|
@@ -1436,6 +1436,7 @@ static int remount_active_mount(struct a
|
|
|
|
/* 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;
|
|
@@ -1550,7 +1551,9 @@ int try_remount(struct autofs_point *ap,
|
|
* record that in the mount point struct. Otherwise we're
|
|
* re-reading the map.
|
|
*/
|
|
- if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) {
|
|
+ if (ret == REMOUNT_READ_MAP)
|
|
+ return 1;
|
|
+ else if (ret == REMOUNT_SUCCESS) {
|
|
if (fd != -1) {
|
|
if (type == t_indirect)
|
|
ap->ioctlfd = fd;
|
|
@@ -1781,5 +1784,162 @@ int umount_multi_triggers(struct autofs_
|
|
}
|
|
|
|
return left;
|
|
+}
|
|
+
|
|
+int clean_stale_multi_triggers(struct autofs_point *ap,
|
|
+ struct mapent *me, char *top, const char *base)
|
|
+{
|
|
+ char *root;
|
|
+ char mm_top[PATH_MAX + 1];
|
|
+ char path[PATH_MAX + 1];
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ char *offset;
|
|
+ struct mapent *oe;
|
|
+ struct list_head *mm_root, *pos;
|
|
+ const char o_root[] = "/";
|
|
+ const char *mm_base;
|
|
+ int left, start;
|
|
+ time_t age;
|
|
+
|
|
+ if (top)
|
|
+ root = top;
|
|
+ else {
|
|
+ if (!strchr(me->multi->key, '/'))
|
|
+ /* Indirect multi-mount root */
|
|
+ /* sprintf okay - if it's mounted, it's
|
|
+ * PATH_MAX or less bytes */
|
|
+ sprintf(mm_top, "%s/%s", ap->path, me->multi->key);
|
|
+ else
|
|
+ strcpy(mm_top, me->multi->key);
|
|
+ root = mm_top;
|
|
+ }
|
|
+
|
|
+ left = 0;
|
|
+ start = strlen(root);
|
|
+
|
|
+ mm_root = &me->multi->multi_list;
|
|
+
|
|
+ if (!base)
|
|
+ mm_base = o_root;
|
|
+ else
|
|
+ mm_base = base;
|
|
+
|
|
+ pos = NULL;
|
|
+ offset = path;
|
|
+ age = me->multi->age;
|
|
+
|
|
+ while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
|
|
+ char *oe_base;
|
|
+ char *key;
|
|
+ int ret;
|
|
+
|
|
+ oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
|
|
+ /* root offset is a special case */
|
|
+ if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
|
|
+ continue;
|
|
+
|
|
+ /* Check for and umount stale subtree offsets */
|
|
+ oe_base = oe->key + strlen(root);
|
|
+ ret = clean_stale_multi_triggers(ap, oe, root, oe_base);
|
|
+ left =+ ret;
|
|
+ if (ret)
|
|
+ continue;
|
|
+
|
|
+ if (oe->age == age)
|
|
+ continue;
|
|
+
|
|
+ /*
|
|
+ * If an offset that has an active mount has been removed
|
|
+ * from the multi-mount we don't want to attempt to trigger
|
|
+ * mounts for it. Obviously this is because it has been
|
|
+ * removed, but less obvious is the potential strange
|
|
+ * behaviour that can result if we do try and mount it
|
|
+ * again after it's been expired. For example, if an NFS
|
|
+ * file system is no longer exported and is later umounted
|
|
+ * it can be mounted again without any error message but
|
|
+ * shows as an empty directory. That's going to confuse
|
|
+ * people for sure.
|
|
+ *
|
|
+ * If the mount cannot be umounted (the process is now
|
|
+ * using a stale mount) the offset needs to be invalidated
|
|
+ * so no further mounts will be attempted but the offset
|
|
+ * cache entry must remain so expires can continue to
|
|
+ * attempt to umount it. If the mount can be umounted and
|
|
+ * the offset is removed, at least for NFS we will get
|
|
+ * ESTALE errors when attempting list the directory.
|
|
+ */
|
|
+ if (oe->ioctlfd != -1 ||
|
|
+ is_mounted(_PROC_MOUNTS, oe->key, MNTS_REAL)) {
|
|
+ if (umount_ent(ap, oe->key)) {
|
|
+ debug(ap->logopt,
|
|
+ "offset %s has active mount, invalidate",
|
|
+ oe->key);
|
|
+ if (oe->mapent) {
|
|
+ free(oe->mapent);
|
|
+ oe->mapent = NULL;
|
|
+ }
|
|
+ left++;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ key = strdup(oe->key);
|
|
+ if (!key) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ error(ap->logopt, "malloc: %s", estr);
|
|
+ left++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ debug(ap->logopt, "umount offset %s", oe->key);
|
|
+
|
|
+ if (umount_autofs_offset(ap, oe)) {
|
|
+ warn(ap->logopt, "failed to umount offset %s", key);
|
|
+ left++;
|
|
+ } else {
|
|
+ struct stat st;
|
|
+
|
|
+ /* Mount point not ours to delete ? */
|
|
+ if (!(oe->flags & MOUNT_FLAG_DIR_CREATED)) {
|
|
+ debug(ap->logopt, "delete offset key %s", key);
|
|
+ if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
|
|
+ error(ap->logopt,
|
|
+ "failed to delete offset key %s", key);
|
|
+ free(key);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * An error due to partial directory removal is
|
|
+ * ok so only try and remount the offset if the
|
|
+ * actual mount point still exists.
|
|
+ */
|
|
+ ret = rmdir_path(ap, oe->key, ap->dev);
|
|
+ if (ret == -1 && !stat(oe->key, &st)) {
|
|
+ ret = do_mount_autofs_offset(ap, oe, root, offset);
|
|
+ if (ret) {
|
|
+ left++;
|
|
+ free(key);
|
|
+ continue;
|
|
+ }
|
|
+ /*
|
|
+ * Fall through if the trigger can't be mounted
|
|
+ * again, since there is no offset there can't
|
|
+ * be any mount requests so remove the map
|
|
+ * entry from the cache. There's now a dead
|
|
+ * offset mount, but what else can we do ....
|
|
+ */
|
|
+ }
|
|
+
|
|
+ debug(ap->logopt, "delete offset key %s", key);
|
|
+
|
|
+ if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
|
|
+ error(ap->logopt,
|
|
+ "failed to delete offset key %s", key);
|
|
+ }
|
|
+ free(key);
|
|
+ }
|
|
+
|
|
+ return left;
|
|
}
|
|
|
|
--- autofs-5.0.6.orig/man/auto.master.5.in
|
|
+++ autofs-5.0.6/man/auto.master.5.in
|
|
@@ -220,7 +220,10 @@ set default log level "none", "verbose"
|
|
.SH BUILTIN MAP -hosts
|
|
If "-hosts" is given as the map then accessing a key under the mount point
|
|
which corresponds to a hostname will allow access to the exports of that
|
|
-host.
|
|
+host. The hosts map cannot be dynamically updated and requires a HUP signal
|
|
+to be sent to the daemon for it to check hosts for an update. Due to possible
|
|
+hierarchic dependencies within a mount tree, it might not be completely
|
|
+updated during the HUP signal processing.
|
|
.P
|
|
For example, with an entry in the master map of
|
|
.nh
|
|
--- autofs-5.0.6.orig/man/autofs.5
|
|
+++ autofs-5.0.6/man/autofs.5
|
|
@@ -13,10 +13,10 @@ These maps describe how file systems bel
|
|
map format; if another map format is specified (e.g. \fBhesiod\fP),
|
|
this documentation does not apply.
|
|
|
|
-Indirect maps can be changed on the fly and the automouter will recognize
|
|
-those changes on the next operation it performs on that map. Direct maps
|
|
-require a HUP signal be sent to the daemon to refresh their contents as does
|
|
-the master map.
|
|
+Indirect maps, except for the internal hosts map, can be changed on the fly
|
|
+and the automouter will recognize those changes on the next operation it
|
|
+performs on that map. Direct maps require a HUP signal be sent to the
|
|
+daemon to refresh their contents as does the master map.
|
|
.SH "FORMAT"
|
|
This is a description of the text file format. Other methods of specifying
|
|
these files may exist. All empty lines or lines beginning with # are
|
|
--- autofs-5.0.6.orig/modules/lookup_hosts.c
|
|
+++ autofs-5.0.6/modules/lookup_hosts.c
|
|
@@ -80,10 +80,11 @@ int lookup_read_master(struct master *ma
|
|
|
|
static char *get_exports(struct autofs_point *ap, const char *host)
|
|
{
|
|
- char *mapent = NULL;
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ char *mapent;
|
|
exports exp;
|
|
|
|
- debug(ap->logopt, MODPREFIX "fetchng export list for %s", name);
|
|
+ debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
|
|
|
|
exp = rpc_get_exports(host, 10, 0, RPC_CLOSE_NOLINGER);
|
|
|
|
@@ -92,20 +93,20 @@ static char *get_exports(struct autofs_p
|
|
if (mapent) {
|
|
int len = strlen(mapent) + 1;
|
|
|
|
- len += strlen(name) + 2*(strlen(exp->ex_dir) + 2) + 3;
|
|
+ len += strlen(host) + 2*(strlen(exp->ex_dir) + 2) + 3;
|
|
mapent = realloc(mapent, len);
|
|
if (!mapent) {
|
|
char *estr;
|
|
estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
|
rpc_exports_free(exp);
|
|
- return NSS_STATUS_UNAVAIL;
|
|
+ return NULL;
|
|
}
|
|
strcat(mapent, " \"");
|
|
strcat(mapent, exp->ex_dir);
|
|
strcat(mapent, "\"");
|
|
} else {
|
|
- int len = 2*(strlen(exp->ex_dir) + 2) + strlen(name) + 3;
|
|
+ int len = 2*(strlen(exp->ex_dir) + 2) + strlen(host) + 3;
|
|
|
|
mapent = malloc(len);
|
|
if (!mapent) {
|
|
@@ -113,14 +114,14 @@ static char *get_exports(struct autofs_p
|
|
estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
|
rpc_exports_free(exp);
|
|
- return NSS_STATUS_UNAVAIL;
|
|
+ return NULL;
|
|
}
|
|
strcpy(mapent, "\"");
|
|
strcat(mapent, exp->ex_dir);
|
|
strcat(mapent, "\"");
|
|
}
|
|
strcat(mapent, " \"");
|
|
- strcat(mapent, name);
|
|
+ strcat(mapent, host);
|
|
strcat(mapent, ":");
|
|
strcat(mapent, exp->ex_dir);
|
|
strcat(mapent, "\"");
|
|
@@ -130,14 +131,14 @@ static char *get_exports(struct autofs_p
|
|
rpc_exports_free(exp);
|
|
|
|
if (!mapent)
|
|
- error(ap->logopt, "exports lookup failed for %s", name);
|
|
+ error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
|
|
|
|
return mapent;
|
|
}
|
|
|
|
-static int do_parse_mount(struct autofs_point *ap,
|
|
+static int do_parse_mount(struct autofs_point *ap, struct map_source *source,
|
|
const char *name, int name_len, char *mapent,
|
|
- void *context)
|
|
+ struct lookup_context *ctxt)
|
|
{
|
|
int ret;
|
|
|
|
@@ -166,8 +167,68 @@ static int do_parse_mount(struct autofs_
|
|
return NSS_STATUS_SUCCESS;
|
|
}
|
|
|
|
+static int update_hosts_mounts(struct autofs_point *ap,
|
|
+ struct map_source *source, time_t age,
|
|
+ struct lookup_context *ctxt)
|
|
+{
|
|
+ struct mapent_cache *mc;
|
|
+ struct mapent *me;
|
|
+ char *mapent;
|
|
+ int ret;
|
|
+
|
|
+ mc = source->mc;
|
|
+
|
|
+ pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
+ cache_writelock(mc);
|
|
+ me = cache_lookup_first(mc);
|
|
+ while (me) {
|
|
+ /* Hosts map entry not yet expanded or already expired */
|
|
+ if (!me->multi)
|
|
+ goto next;
|
|
+
|
|
+ debug(ap->logopt, MODPREFIX "get list of exports for %s", me->key);
|
|
+
|
|
+ mapent = get_exports(ap, me->key);
|
|
+ if (mapent) {
|
|
+ cache_update(mc, source, me->key, mapent, age);
|
|
+ free(mapent);
|
|
+ }
|
|
+next:
|
|
+ me = cache_lookup_next(mc, me);
|
|
+ }
|
|
+ pthread_cleanup_pop(1);
|
|
+
|
|
+ pthread_cleanup_push(cache_lock_cleanup, mc);
|
|
+ cache_readlock(mc);
|
|
+ me = cache_lookup_first(mc);
|
|
+ while (me) {
|
|
+ /*
|
|
+ * Hosts map entry not yet expanded, already expired
|
|
+ * or not the base of the tree
|
|
+ */
|
|
+ if (!me->multi || me->multi != me)
|
|
+ goto cont;
|
|
+
|
|
+ debug(ap->logopt, MODPREFIX
|
|
+ "attempt to update exports for exports for %s", me->key);
|
|
+
|
|
+ master_source_current_wait(ap->entry);
|
|
+ ap->entry->current = source;
|
|
+ ap->flags |= MOUNT_FLAG_REMOUNT;
|
|
+ ret = ctxt->parse->parse_mount(ap, me->key, strlen(me->key),
|
|
+ me->mapent, ctxt->parse->context);
|
|
+ ap->flags &= ~MOUNT_FLAG_REMOUNT;
|
|
+cont:
|
|
+ me = cache_lookup_next(mc, me);
|
|
+ }
|
|
+ pthread_cleanup_pop(1);
|
|
+
|
|
+ return NSS_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
|
|
{
|
|
+ struct lookup_context *ctxt = (struct lookup_context *) context;
|
|
struct map_source *source;
|
|
struct mapent_cache *mc;
|
|
struct hostent *host;
|
|
@@ -177,18 +238,23 @@ int lookup_read_map(struct autofs_point
|
|
ap->entry->current = NULL;
|
|
master_source_current_signal(ap->entry);
|
|
|
|
+ mc = source->mc;
|
|
+
|
|
+ debug(ap->logopt, MODPREFIX "read hosts map");
|
|
+
|
|
/*
|
|
* If we don't need to create directories then there's no use
|
|
* reading the map. We always need to read the whole map for
|
|
* direct mounts in order to mount the triggers.
|
|
*/
|
|
if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT) {
|
|
- debug(ap->logopt, "map read not needed, so not done");
|
|
+ debug(ap->logopt, MODPREFIX
|
|
+ "map not browsable, update existing host entries only");
|
|
+ update_hosts_mounts(ap, source, age, ctxt);
|
|
+ source->age = age;
|
|
return NSS_STATUS_SUCCESS;
|
|
}
|
|
|
|
- mc = source->mc;
|
|
-
|
|
status = pthread_mutex_lock(&hostent_mutex);
|
|
if (status) {
|
|
error(ap->logopt, MODPREFIX "failed to lock hostent mutex");
|
|
@@ -209,6 +275,7 @@ int lookup_read_map(struct autofs_point
|
|
if (status)
|
|
error(ap->logopt, MODPREFIX "failed to unlock hostent mutex");
|
|
|
|
+ update_hosts_mounts(ap, source, age, ctxt);
|
|
source->age = age;
|
|
|
|
return NSS_STATUS_SUCCESS;
|
|
@@ -220,11 +287,9 @@ int lookup_mount(struct autofs_point *ap
|
|
struct map_source *source;
|
|
struct mapent_cache *mc;
|
|
struct mapent *me;
|
|
- char buf[MAX_ERR_BUF];
|
|
char *mapent = NULL;
|
|
int mapent_len;
|
|
time_t now = time(NULL);
|
|
- exports exp;
|
|
int ret;
|
|
|
|
source = ap->entry->current;
|
|
@@ -320,7 +385,7 @@ done:
|
|
cache_unlock(mc);
|
|
}
|
|
|
|
- ret = do_parse_mount(ap, name, name_len, mapent, ctxt->parse->context);
|
|
+ ret = do_parse_mount(ap, source, name, name_len, mapent, ctxt);
|
|
|
|
free(mapent);
|
|
|
|
--- autofs-5.0.6.orig/modules/parse_sun.c
|
|
+++ autofs-5.0.6/modules/parse_sun.c
|
|
@@ -1355,7 +1355,7 @@ int parse_mount(struct autofs_point *ap,
|
|
if (check_is_multi(p)) {
|
|
char *m_root = NULL;
|
|
int m_root_len;
|
|
- time_t age = time(NULL);
|
|
+ time_t age;
|
|
int l;
|
|
|
|
/* If name starts with "/" it's a direct mount */
|
|
@@ -1399,6 +1399,8 @@ int parse_mount(struct autofs_point *ap,
|
|
return 1;
|
|
}
|
|
|
|
+ age = me->age;
|
|
+
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
cache_multi_writelock(me);
|
|
/* It's a multi-mount; deal with it */
|
|
@@ -1472,8 +1474,11 @@ int parse_mount(struct autofs_point *ap,
|
|
|
|
/*
|
|
* We've got the ordered list of multi-mount entries so go
|
|
- * through and set the parent entry of each
|
|
+ * through and remove any stale entries if this is the top
|
|
+ * of the multi-mount and set the parent entry of each.
|
|
*/
|
|
+ if (me == me->multi)
|
|
+ clean_stale_multi_triggers(ap, me, NULL, NULL);
|
|
cache_set_parents(me);
|
|
|
|
rv = mount_subtree(ap, me, name, NULL, options, ctxt);
|