> 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 autofs@linux.kernel.org http://linux.kernel.org/mailman/listinfo/autofs