> So what do you have, 4.1.4 will all the patches from kernel.org or the
> SLES 10 package, or an SLES 10 update of some sort?
Sorry for not being specific here.
I'm using the latest SLES10 update, which basically is 4.1.4 + some
patches from kernel.org + distribution specific configuration and build
changes + a couple of other bug fixes that are not upstream.
To make things easier to everyone, I grabbed the latest tarball and
patches from kernel.org and applied autofs-4.1.4-negative-timeout.patch
from RHEL 4 (credits to Jeff Moyer). Just one chunk was rejected (the
one from lookup_hesiod.c). Please find the refreshed patch attached,
minimally tested so far.
I'd appreciate if it could be merged upstream (after proper testing, of
course).
Thanks
Leonardo
Index: autofs-4.1.4/daemon/automount.c
===================================================================
--- autofs-4.1.4.orig/daemon/automount.c
+++ autofs-4.1.4/daemon/automount.c
@@ -603,6 +603,54 @@ static int send_fail(unsigned int wait_q
return 0;
}
+/*
+ * This function updates the negative lookup cache. The negative
+ * lookup cache keeps track of failed mounts in order to reduce
+ * mountd request load on the server. This cache has a configurable
+ * timeout, via the daemon option --negative-timeout.
+ */
+void update_negative_cache(char *key)
+{
+ int ret;
+ struct mapent_cache *me;
+
+ debug("update_negative_cache: key: %s", key);
+ if (key == NULL)
+ return;
+
+ /*
+ * This function should only be called for keys that are not in
+ * the cache.
+ */
+ me = cache_lookup(key);
+ if (me && strcmp(me->key, key) == 0) {
+ if (me->negative) {
+ debug("Error: found negative cache entry for key %s\n",
+ key);
+ return;
+ }
+ } else /* don't match the wild-card key */
+ me = NULL;
+
+ /* Add a negative entry to the cache */
+ debug("Adding negative cache entry for key %s\n", key);
+ if (!me) {
+ ret = cache_add(ap.path, key, NULL, time(NULL));
+ if (ret != CHE_OK) {
+ info("unable to cache failed lookup for %s", key);
+ return;
+ }
+ me = cache_lookup(key);
+ if (!me || strcmp(me->key, key) != 0) {
+ debug("added an entry and it doesn't exist!?");
+ return;
+ }
+ }
+ me->negative = 1;
+ me->last_lookup = time(NULL);
+ debug("Key %s added to negative cache\n", key);
+}
+
/* Handle exiting children (either from SIGCHLD or synchronous wait at
shutdown), and return the next state the system should enter as a
result. */
@@ -696,9 +744,16 @@ static enum states handle_child(int hang
pid, WIFSIGNALED(status),
WTERMSIG(status), WEXITSTATUS(status));
- if (WIFSIGNALED(status) || WEXITSTATUS(status) != 0)
+ if (WIFSIGNALED(status))
send_fail(mt->wait_queue_token);
- else
+ else if (WEXITSTATUS(status) != 0) {
+ int error_code = WEXITSTATUS(status);
+
+ if (error_code == EXIT_CODE_MOUNT_FAILED)
+ update_negative_cache(mt->key);
+
+ send_fail(mt->wait_queue_token);
+ } else
send_ready(mt->wait_queue_token);
/* Delete from list and add to freelist,
@@ -1077,6 +1132,7 @@ static int handle_packet_missing(const s
sigset_t oldsig;
pid_t f;
struct pending_mount *mt = NULL;
+ struct mapent_cache *me;
debug("handle_packet_missing: token %ld, name %s\n",
(unsigned long) pkt->wait_queue_token, pkt->name);
@@ -1087,6 +1143,32 @@ static int handle_packet_missing(const s
return 0;
}
+ /* Check to see if there is a negative cache entry */
+ me = cache_lookup(pkt->name);
+ if (me != NULL && strcmp(me->key, pkt->name) == 0 &&
+ me->negative) {
+ if (time(NULL) - me->last_lookup < ap.negative_timeout) {
+ debug("%s: found negative cache entry for key.\n",
+ __FUNCTION__);
+ send_fail(pkt->wait_queue_token);
+ return 0;
+ }
+ /*
+ * If the negative cache entry expired, then remove it.
+ * This means 1 of 2 things:
+ * 1) if an entry actually exists in the map, then clear
+ * the negative flag to trigger a new lookup
+ * 2) if this key was actually matched to the wildcard,
+ * then remove the cache entry altogether.
+ */
+ debug("%s: expired negative cache entry for key.\n",
+ __FUNCTION__);
+ if (me->mapent == NULL)
+ cache_delete(ap.path, pkt->name, 0);
+ else
+ me->negative = 0;
+ }
+
chdir(ap.path);
if (lstat(pkt->name, &st) == -1 ||
(S_ISDIR(st.st_mode) && st.st_dev == ap.dev)) {
@@ -1162,7 +1244,7 @@ static int handle_packet_missing(const s
rm_unwanted(buf, 1, 0); */
}
- _exit(err ? 1 : 0);
+ _exit(err);
} else {
/*
* Important: set up data structures while signals
@@ -1170,6 +1252,8 @@ static int handle_packet_missing(const s
*/
mt->pid = f;
mt->wait_queue_token = pkt->wait_queue_token;
+ mt->key = strdup(pkt->name); /* ok if this fails */
+ debug("mt->key set to %s\n", mt->key);
mt->next = ap.mounts;
ap.mounts = mt;
@@ -1733,6 +1817,7 @@ int main(int argc, char *argv[])
{"version", 0, 0, 'V'},
{"ghost", 0, 0, 'g'},
{"submount", 0, &submount, 1},
+ {"negative-timeout", 1, 0, 'n'},
{0, 0, 0, 0}
};
@@ -1743,9 +1828,10 @@ int main(int argc, char *argv[])
ap.ghost = DEFAULT_GHOST_MODE;
ap.type = LKP_INDIRECT;
ap.dir_created = 0; /* We haven't created the main directory yet */
+ ap.negative_timeout = 60;
opterr = 0;
- while ((opt = getopt_long(argc, argv, "+hp:t:vdVg", long_options, NULL)) != EOF) {
+ while ((opt = getopt_long(argc, argv, "+hp:t:vdVgn:", long_options, NULL)) != EOF) {
switch (opt) {
case 'h':
usage();
@@ -1774,7 +1860,9 @@ int main(int argc, char *argv[])
case 'g':
ap.ghost = LKP_GHOST;
break;
-
+ case 'n':
+ ap.negative_timeout = getnumopt(optarg, opt);
+ break;
case '?':
case ':':
printf("%s: Ambiguous or unknown options\n", program);
Index: autofs-4.1.4/include/automount.h
===================================================================
--- autofs-4.1.4.orig/include/automount.h
+++ autofs-4.1.4/include/automount.h
@@ -96,9 +96,13 @@ enum states {
struct pending_mount {
pid_t pid; /* Which process is mounting for us */
unsigned long wait_queue_token; /* Associated kernel wait token */
+ char *key; /* Store key for negative caching */
volatile struct pending_mount *next;
};
+#define EXIT_CODE_GENERIC_FAILURE 1
+#define EXIT_CODE_MOUNT_FAILED 2
+
struct autofs_point {
char *path; /* Mount point name */
int pipefd; /* File descriptor for pipe */
@@ -116,6 +120,7 @@ struct autofs_point {
int state_pipe[2];
unsigned dir_created; /* Was a directory created for this
mount? */
+ time_t negative_timeout; /* Timeout in secs for failed mounts */
};
extern struct autofs_point ap;
@@ -238,6 +243,9 @@ struct mapent_cache {
char *key;
char *mapent;
time_t age;
+ int negative; /* boolean, set to indicate a failed lookup */
+ time_t last_lookup; /* time of last lookup, used for negative cache
+ * expiration */
};
void cache_init(void);
Index: autofs-4.1.4/modules/lookup_file.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_file.c
+++ autofs-4.1.4/modules/lookup_file.c
@@ -252,7 +252,7 @@ static int read_map(const char *root, ti
while(1) {
entry = read_one(f, key, mapent);
if (entry)
- cache_add(root, key, mapent, age);
+ cache_update(root, key, mapent, age);
if (feof(f))
break;
@@ -383,7 +383,7 @@ int lookup_mount(const char *root, const
char key[KEY_MAX_LEN + 1];
int key_len;
char mapent[MAPENT_MAX_LEN + 1];
- struct mapent_cache *me;
+ struct mapent_cache *me, *exists;
time_t now = time(NULL);
time_t t_last_read;
int need_hup = 0;
@@ -405,10 +405,15 @@ int lookup_mount(const char *root, const
me = cache_lookup_first();
t_last_read = me ? now - me->age : ap.exp_runfreq + 1;
- /* only if it has been modified */
+ /* only perform a real lookup if the map was modified */
if (st.st_mtime > ctxt->mtime) {
+ /* cache_lookup may match wild-card */
+ exists = cache_lookup(key);
+ if (exists && strcmp(exists->key, key) != 0)
+ exists = NULL;
+
ret = lookup_one(root, key, key_len, ctxt);
- if (!ret)
+ if (ret == CHE_FAIL)
return 1;
debug("ret = %d", ret);
@@ -417,7 +422,7 @@ int lookup_mount(const char *root, const
if (ret & (CHE_UPDATED | CHE_MISSING))
need_hup = 1;
- if (ret == CHE_MISSING) {
+ if ((ret & CHE_MISSING) && exists) {
int wild = CHE_MISSING;
/* Maybe update wild card map entry */
@@ -445,13 +450,22 @@ int lookup_mount(const char *root, const
if (me) {
debug(MODPREFIX "%s -> %s", key, mapent);
ret = ctxt->parse->parse_mount(root, name, name_len,
- mapent, ctxt->parse->context);
- }
+ mapent, ctxt->parse->context);
+ } else {
+ ret = 1;
+ error(MODPREFIX "key \"%s\" not found in map.", name);
+ }
/* Have parent update its map ? */
if (need_hup)
kill(getppid(), SIGHUP);
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ if (ret)
+ ret = EXIT_CODE_MOUNT_FAILED;
+
+ debug(MODPREFIX "lookup_mount returning %d\n", ret);
return ret;
}
Index: autofs-4.1.4/modules/lookup_hesiod.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_hesiod.c
+++ autofs-4.1.4/modules/lookup_hesiod.c
@@ -125,6 +125,10 @@ int lookup_mount(const char *root, const
#else
free(hes_result);
#endif
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ if (rv)
+ rv = EXIT_CODE_MOUNT_FAILED;
return rv;
}
Index: autofs-4.1.4/modules/lookup_ldap.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_ldap.c
+++ autofs-4.1.4/modules/lookup_ldap.c
@@ -657,6 +657,15 @@ int lookup_mount(const char *root, const
debug(MODPREFIX "%s -> %s", key, mapent);
ret = ctxt->parse->parse_mount(root, name, name_len,
mapent, ctxt->parse->context);
+ /*
+ * If the mount fails, it is most likely due to
+ * the directory not existing on the server. In
+ * such a case, we want to remember that the mount
+ * failed so that we don't trigger successive
+ * mounts.
+ */
+ if (ret)
+ ret = EXIT_CODE_MOUNT_FAILED;
me = cache_lookup_next(me);
}
} else {
Index: autofs-4.1.4/modules/lookup_multi.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_multi.c
+++ autofs-4.1.4/modules/lookup_multi.c
@@ -134,14 +134,14 @@ int lookup_ghost(const char *root, int g
int lookup_mount(const char *root, const char *name, int name_len, void *context)
{
struct lookup_context *ctxt = (struct lookup_context *) context;
- int i;
+ int i, ret;
for (i = 0; i < ctxt->n; i++) {
- if (ctxt->m[i].mod->lookup_mount(root, name, name_len,
- ctxt->m[i].mod->context) == 0)
+ if ((ret = ctxt->m[i].mod->lookup_mount(root, name, name_len,
+ ctxt->m[i].mod->context)) == 0)
return 0;
}
- return 1; /* No module succeeded */
+ return ret; /* No module succeeded */
}
int lookup_done(void *context)
Index: autofs-4.1.4/modules/lookup_nisplus.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_nisplus.c
+++ autofs-4.1.4/modules/lookup_nisplus.c
@@ -99,6 +99,10 @@ int lookup_mount(const char *root, const
NIS_RES_OBJECT(result)->EN_data.en_cols.
en_cols_val[1].ec_value.ec_value_val,
ctxt->parse->context);
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ if (rv)
+ rv = EXIT_CODE_MOUNT_FAILED;
return rv;
}
Index: autofs-4.1.4/lib/cache.c
===================================================================
--- autofs-4.1.4.orig/lib/cache.c
+++ autofs-4.1.4/lib/cache.c
@@ -179,16 +179,22 @@ int cache_add(const char *root, const ch
return CHE_FAIL;
}
- pent = malloc(strlen(mapent) + 1);
- if (!pent) {
- free(me);
- free(pkey);
- return CHE_FAIL;
+ if (mapent) {
+ pent = malloc(strlen(mapent) + 1);
+ if (!pent) {
+ free(me);
+ free(pkey);
+ return CHE_FAIL;
+ }
}
-
me->key = strcpy(pkey, key);
- me->mapent = strcpy(pent, mapent);
+ if (mapent)
+ me->mapent = strcpy(pent, mapent);
+ else
+ me->mapent = NULL;
me->age = age;
+ me->negative = 0;
+ me->last_lookup = 0;
/*
* We need to add to the end if values exist in order to
Index: autofs-4.1.4/modules/lookup_program.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_program.c
+++ autofs-4.1.4/modules/lookup_program.c
@@ -277,6 +277,10 @@ int lookup_mount(const char *root, const
ret = ctxt->parse->parse_mount(root, name, name_len,
mapent, ctxt->parse->context);
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ if (ret)
+ ret = EXIT_CODE_MOUNT_FAILED;
out_free:
free(mapent);
return ret;
Index: autofs-4.1.4/modules/lookup_userhome.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_userhome.c
+++ autofs-4.1.4/modules/lookup_userhome.c
@@ -62,7 +62,9 @@ int lookup_mount(const char *root, const
if (symlink(pw->pw_dir, name) && errno != EEXIST) {
error(MODPREFIX "symlink failed: %m");
- return 1;
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ return EXIT_CODE_MOUNT_FAILED;
}
return 0;
Index: autofs-4.1.4/modules/lookup_yp.c
===================================================================
--- autofs-4.1.4.orig/modules/lookup_yp.c
+++ autofs-4.1.4/modules/lookup_yp.c
@@ -220,7 +220,7 @@ int lookup_mount(const char *root, const
int key_len;
char *mapent;
int mapent_len;
- struct mapent_cache *me;
+ struct mapent_cache *me, *exists;
time_t now = time(NULL);
time_t t_last_read;
int need_hup = 0;
@@ -236,7 +236,15 @@ int lookup_mount(const char *root, const
if (key_len > KEY_MAX_LEN)
return 1;
- /* check map and if change is detected re-read map */
+ /*
+ * Check map and if change is detected re-read map
+ */
+
+ /* First check to see if this entry exists in the cache */
+ exists = cache_lookup(key);
+ if (exists && strcmp(exists->key, key) != 0)
+ exists = NULL;
+
ret = lookup_one(root, key, key_len, ctxt);
if (!ret)
return 1;
@@ -297,6 +305,11 @@ int lookup_mount(const char *root, const
if (need_hup)
kill(getppid(), SIGHUP);
+ /* EXIT_CODE_MOUNT_FAILED is caught by the upper layers
+ * and used to populate the negative lookup cache */
+ if (ret)
+ ret = EXIT_CODE_MOUNT_FAILED;
+
return ret;
}
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs