]>
Commit | Line | Data |
---|---|---|
e5fd101c PS |
1 | autofs-5.0.4 - fix negative cache non-existent key |
2 | ||
3 | From: Ian Kent <raven@themaw.net> | |
4 | ||
5 | autofs was not recording map entries that don't exist for negative | |
6 | caching. This was causing unwanted network map lookups. | |
7 | --- | |
8 | ||
9 | CHANGELOG | 1 + | |
10 | daemon/lookup.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-- | |
11 | modules/lookup_file.c | 20 ++++++++++++------- | |
12 | modules/lookup_hosts.c | 21 ++++++++++++++++---- | |
13 | modules/lookup_ldap.c | 20 ++++++++++++------- | |
14 | modules/lookup_nisplus.c | 19 ++++++++++++------ | |
15 | modules/lookup_program.c | 35 ++++++++++++++++++++++++++-------- | |
16 | modules/lookup_yp.c | 19 ++++++++++++------ | |
17 | 8 files changed, 143 insertions(+), 40 deletions(-) | |
18 | ||
19 | ||
20 | diff --git a/CHANGELOG b/CHANGELOG | |
21 | index 88ca579..bd35b00 100644 | |
22 | --- a/CHANGELOG | |
23 | +++ b/CHANGELOG | |
24 | @@ -2,6 +2,7 @@ | |
25 | ----------------------- | |
26 | - fix dumb libxml2 check | |
27 | - fix nested submount expire deadlock. | |
28 | +- fix negative caching for non-existent map keys. | |
29 | ||
30 | 4/11/2008 autofs-5.0.4 | |
31 | ----------------------- | |
32 | diff --git a/daemon/lookup.c b/daemon/lookup.c | |
33 | index 803df4f..0cf6e3f 100644 | |
34 | --- a/daemon/lookup.c | |
35 | +++ b/daemon/lookup.c | |
36 | @@ -804,6 +804,45 @@ static enum nsswitch_status lookup_map_name(struct nss_source *this, | |
37 | return result; | |
38 | } | |
39 | ||
40 | +static void update_negative_cache(struct autofs_point *ap, struct map_source *source, const char *name) | |
41 | +{ | |
42 | + struct master_mapent *entry = ap->entry; | |
43 | + struct map_source *map; | |
44 | + struct mapent *me; | |
45 | + | |
46 | + /* Have we recorded the lookup fail for negative caching? */ | |
47 | + me = lookup_source_mapent(ap, name, LKP_DISTINCT); | |
48 | + if (me) | |
49 | + /* | |
50 | + * Already exists in the cache, the mount fail updates | |
51 | + * will update negative timeout status. | |
52 | + */ | |
53 | + cache_unlock(me->mc); | |
54 | + else { | |
55 | + /* Notify only once after fail */ | |
56 | + error(ap->logopt, "key \"%s\" not found in map.", name); | |
57 | + | |
58 | + /* Doesn't exist in any source, just add it somewhere */ | |
59 | + if (source) | |
60 | + map = source; | |
61 | + else | |
62 | + map = entry->maps; | |
63 | + if (map) { | |
64 | + time_t now = time(NULL); | |
65 | + int rv = CHE_FAIL; | |
66 | + | |
67 | + cache_writelock(map->mc); | |
68 | + rv = cache_update(map->mc, map, name, NULL, now); | |
69 | + if (rv != CHE_FAIL) { | |
70 | + me = cache_lookup_distinct(map->mc, name); | |
71 | + me->status = now + ap->negative_timeout; | |
72 | + } | |
73 | + cache_unlock(map->mc); | |
74 | + } | |
75 | + } | |
76 | + return; | |
77 | +} | |
78 | + | |
79 | int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len) | |
80 | { | |
81 | struct master_mapent *entry = ap->entry; | |
82 | @@ -907,8 +946,13 @@ int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const c | |
83 | send_map_update_request(ap); | |
84 | pthread_cleanup_pop(1); | |
85 | ||
86 | - if (result == NSS_STATUS_NOTFOUND) | |
87 | - error(ap->logopt, "key \"%s\" not found in map.", name); | |
88 | + /* | |
89 | + * The last source lookup will return NSS_STATUS_NOTFOUND if the | |
90 | + * map exits and the key has not been found but the map may also | |
91 | + * not exist in which case the key is also not found. | |
92 | + */ | |
93 | + if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL) | |
94 | + update_negative_cache(ap, source, name); | |
95 | ||
96 | return !result; | |
97 | } | |
98 | diff --git a/modules/lookup_file.c b/modules/lookup_file.c | |
99 | index 807ceab..9e34b72 100644 | |
100 | --- a/modules/lookup_file.c | |
101 | +++ b/modules/lookup_file.c | |
102 | @@ -1069,14 +1069,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
103 | if (key_len > KEY_MAX_LEN) | |
104 | return NSS_STATUS_NOTFOUND; | |
105 | ||
106 | - /* Check if we recorded a mount fail for this key */ | |
107 | - cache_readlock(mc); | |
108 | - me = cache_lookup_distinct(mc, key); | |
109 | - if (me && me->status >= time(NULL)) { | |
110 | - cache_unlock(mc); | |
111 | - return NSS_STATUS_UNAVAIL; | |
112 | + /* Check if we recorded a mount fail for this key anywhere */ | |
113 | + me = lookup_source_mapent(ap, key, LKP_DISTINCT); | |
114 | + if (me) { | |
115 | + if (me->status >= time(NULL)) { | |
116 | + cache_unlock(me->mc); | |
117 | + return NSS_STATUS_NOTFOUND; | |
118 | + } | |
119 | + | |
120 | + /* Negative timeout expired for non-existent entry. */ | |
121 | + if (!me->mapent) | |
122 | + cache_delete(me->mc, key); | |
123 | + | |
124 | + cache_unlock(me->mc); | |
125 | } | |
126 | - cache_unlock(mc); | |
127 | ||
128 | /* | |
129 | * We can't check the direct mount map as if it's not in | |
130 | diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c | |
131 | index bf24d7f..f8d4269 100644 | |
132 | --- a/modules/lookup_hosts.c | |
133 | +++ b/modules/lookup_hosts.c | |
134 | @@ -136,12 +136,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
135 | ||
136 | mc = source->mc; | |
137 | ||
138 | + /* Check if we recorded a mount fail for this key anywhere */ | |
139 | + me = lookup_source_mapent(ap, name, LKP_DISTINCT); | |
140 | + if (me) { | |
141 | + if (me->status >= time(NULL)) { | |
142 | + cache_unlock(me->mc); | |
143 | + return NSS_STATUS_NOTFOUND; | |
144 | + } | |
145 | + | |
146 | + if (!me->mapent) { | |
147 | + cache_delete(me->mc, name); | |
148 | + me = NULL; | |
149 | + } | |
150 | + | |
151 | + cache_unlock(me->mc); | |
152 | + } | |
153 | + | |
154 | cache_readlock(mc); | |
155 | me = cache_lookup_distinct(mc, name); | |
156 | - if (me && me->status >= time(NULL)) { | |
157 | - cache_unlock(mc); | |
158 | - return NSS_STATUS_NOTFOUND; | |
159 | - } else if (!me) { | |
160 | + if (!me) { | |
161 | cache_unlock(mc); | |
162 | /* | |
163 | * We haven't read the list of hosts into the | |
164 | diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c | |
165 | index 31c2c13..42c3235 100644 | |
166 | --- a/modules/lookup_ldap.c | |
167 | +++ b/modules/lookup_ldap.c | |
168 | @@ -2709,14 +2709,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
169 | if (key_len > KEY_MAX_LEN) | |
170 | return NSS_STATUS_NOTFOUND; | |
171 | ||
172 | - /* Check if we recorded a mount fail for this key */ | |
173 | - cache_readlock(mc); | |
174 | - me = cache_lookup_distinct(mc, key); | |
175 | - if (me && me->status >= time(NULL)) { | |
176 | - cache_unlock(mc); | |
177 | - return NSS_STATUS_NOTFOUND; | |
178 | + /* Check if we recorded a mount fail for this key anywhere */ | |
179 | + me = lookup_source_mapent(ap, key, LKP_DISTINCT); | |
180 | + if (me) { | |
181 | + if (me->status >= time(NULL)) { | |
182 | + cache_unlock(me->mc); | |
183 | + return NSS_STATUS_NOTFOUND; | |
184 | + } | |
185 | + | |
186 | + /* Negative timeout expired for non-existent entry. */ | |
187 | + if (!me->mapent) | |
188 | + cache_delete(me->mc, key); | |
189 | + | |
190 | + cache_unlock(me->mc); | |
191 | } | |
192 | - cache_unlock(mc); | |
193 | ||
194 | /* | |
195 | * We can't check the direct mount map as if it's not in | |
196 | diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c | |
197 | index 755556d..f15465f 100644 | |
198 | --- a/modules/lookup_nisplus.c | |
199 | +++ b/modules/lookup_nisplus.c | |
200 | @@ -493,13 +493,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
201 | if (key_len > KEY_MAX_LEN) | |
202 | return NSS_STATUS_NOTFOUND; | |
203 | ||
204 | - cache_readlock(mc); | |
205 | - me = cache_lookup_distinct(mc, key); | |
206 | - if (me && me->status >= time(NULL)) { | |
207 | - cache_unlock(mc); | |
208 | - return NSS_STATUS_NOTFOUND; | |
209 | + /* Check if we recorded a mount fail for this key anywhere */ | |
210 | + me = lookup_source_mapent(ap, key, LKP_DISTINCT); | |
211 | + if (me) { | |
212 | + if (me->status >= time(NULL)) { | |
213 | + cache_unlock(me->mc); | |
214 | + return NSS_STATUS_NOTFOUND; | |
215 | + } | |
216 | + | |
217 | + /* Negative timeout expired for non-existent entry. */ | |
218 | + if (!me->mapent) | |
219 | + cache_delete(me->mc, key); | |
220 | + | |
221 | + cache_unlock(me->mc); | |
222 | } | |
223 | - cache_unlock(mc); | |
224 | ||
225 | /* | |
226 | * We can't check the direct mount map as if it's not in | |
227 | diff --git a/modules/lookup_program.c b/modules/lookup_program.c | |
228 | index daf874d..bf32d3b 100644 | |
229 | --- a/modules/lookup_program.c | |
230 | +++ b/modules/lookup_program.c | |
231 | @@ -131,13 +131,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
232 | ||
233 | mc = source->mc; | |
234 | ||
235 | + /* Check if we recorded a mount fail for this key anywhere */ | |
236 | + me = lookup_source_mapent(ap, name, LKP_DISTINCT); | |
237 | + if (me) { | |
238 | + if (me->status >= time(NULL)) { | |
239 | + cache_unlock(me->mc); | |
240 | + return NSS_STATUS_NOTFOUND; | |
241 | + } | |
242 | + | |
243 | + /* Negative timeout expired for non-existent entry. */ | |
244 | + if (!me->mapent) | |
245 | + cache_delete(me->mc, name); | |
246 | + | |
247 | + cache_unlock(me->mc); | |
248 | + } | |
249 | + | |
250 | /* Catch installed direct offset triggers */ | |
251 | - cache_readlock(mc); | |
252 | + cache_writelock(mc); | |
253 | me = cache_lookup_distinct(mc, name); | |
254 | - if (me && me->status >= time(NULL)) { | |
255 | - cache_unlock(mc); | |
256 | - return NSS_STATUS_NOTFOUND; | |
257 | - } else if (!me) { | |
258 | + if (!me) { | |
259 | cache_unlock(mc); | |
260 | /* | |
261 | * If there's a '/' in the name and the offset is not in | |
262 | @@ -149,8 +161,6 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
263 | return NSS_STATUS_NOTFOUND; | |
264 | } | |
265 | } else { | |
266 | - cache_unlock(mc); | |
267 | - | |
268 | /* Otherwise we found a valid offset so try mount it */ | |
269 | debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent); | |
270 | ||
271 | @@ -163,19 +173,28 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
272 | */ | |
273 | if (strchr(name, '/') || | |
274 | me->age + ap->negative_timeout > time(NULL)) { | |
275 | + char *ent = NULL; | |
276 | + | |
277 | + if (me->mapent) { | |
278 | + ent = alloca(strlen(me->mapent) + 1); | |
279 | + strcpy(ent, me->mapent); | |
280 | + } | |
281 | + cache_unlock(mc); | |
282 | master_source_current_wait(ap->entry); | |
283 | ap->entry->current = source; | |
284 | ret = ctxt->parse->parse_mount(ap, name, | |
285 | - name_len, me->mapent, ctxt->parse->context); | |
286 | + name_len, ent, ctxt->parse->context); | |
287 | goto out_free; | |
288 | } else { | |
289 | if (me->multi) { | |
290 | + cache_unlock(mc); | |
291 | warn(ap->logopt, MODPREFIX | |
292 | "unexpected lookup for active multi-mount" | |
293 | " key %s, returning fail", name); | |
294 | return NSS_STATUS_UNAVAIL; | |
295 | } | |
296 | cache_delete(mc, name); | |
297 | + cache_unlock(mc); | |
298 | } | |
299 | } | |
300 | ||
301 | diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c | |
302 | index 8b6408b..1b62f57 100644 | |
303 | --- a/modules/lookup_yp.c | |
304 | +++ b/modules/lookup_yp.c | |
305 | @@ -603,13 +603,20 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * | |
306 | if (key_len > KEY_MAX_LEN) | |
307 | return NSS_STATUS_NOTFOUND; | |
308 | ||
309 | - cache_readlock(mc); | |
310 | - me = cache_lookup_distinct(mc, key); | |
311 | - if (me && me->status >= time(NULL)) { | |
312 | - cache_unlock(mc); | |
313 | - return NSS_STATUS_NOTFOUND; | |
314 | + /* Check if we recorded a mount fail for this key anywhere */ | |
315 | + me = lookup_source_mapent(ap, key, LKP_DISTINCT); | |
316 | + if (me) { | |
317 | + if (me->status >= time(NULL)) { | |
318 | + cache_unlock(me->mc); | |
319 | + return NSS_STATUS_NOTFOUND; | |
320 | + } | |
321 | + | |
322 | + /* Negative timeout expired for non-existent entry. */ | |
323 | + if (!me->mapent) | |
324 | + cache_delete(me->mc, key); | |
325 | + | |
326 | + cache_unlock(me->mc); | |
327 | } | |
328 | - cache_unlock(mc); | |
329 | ||
330 | /* | |
331 | * We can't check the direct mount map as if it's not in |