1 autofs-5.0.4 - dont umount existing direct mount on master re-read
3 From: Ian Kent <raven@themaw.net>
5 Since direct mounts can have multiple entries in the master map they each
6 have an instance associated with them. If one entry changes, such as the
7 mount options, the instance comparison test fails and a new instance is
8 added. This causes autofs to get confused because there are now two
9 entries that contain the same mount information in different internal
10 caches. There are several consequences of this, most of which are just
11 noise in the log, but it also causes confuion for the expiration of mounts
12 since, for an active mount, the old cache entry can't be pruned until it's
13 umounted. Also, the map caches were not being properly pruned.
17 daemon/lookup.c | 160 ++++++++++++++++++++++++++++-----------------------
18 daemon/state.c | 90 +++++++++++++++++++++--------
19 include/automount.h | 1
20 4 files changed, 156 insertions(+), 96 deletions(-)
23 diff --git a/CHANGELOG b/CHANGELOG
24 index 387af5e..7ca45fd 100644
28 - use percent hack for master map keys.
29 - use intr option as hosts mount default.
30 - fix kernel includes.
31 +- dont umount existing direct mount on master re-read.
33 4/11/2008 autofs-5.0.4
34 -----------------------
35 diff --git a/daemon/lookup.c b/daemon/lookup.c
36 index fd2ce55..bc94655 100644
39 @@ -1016,96 +1016,114 @@ static char *make_fullpath(const char *root, const char *key)
43 -int lookup_prune_cache(struct autofs_point *ap, time_t age)
44 +void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age)
46 - struct master_mapent *entry = ap->entry;
47 - struct map_source *map;
48 - struct mapent_cache *mc;
49 struct mapent *me, *this;
51 int status = CHE_FAIL;
53 - pthread_cleanup_push(master_source_lock_cleanup, entry);
54 - master_source_readlock(entry);
55 + me = cache_enumerate(mc, NULL);
57 + struct mapent *valid;
58 + char *key = NULL, *next_key = NULL;
62 - /* Is the map stale */
65 + if (me->age >= age) {
66 + me = cache_enumerate(mc, me);
70 - pthread_cleanup_push(cache_lock_cleanup, mc);
72 - me = cache_enumerate(mc, NULL);
74 - char *key = NULL, *next_key = NULL;
76 - if (me->age >= age) {
77 - me = cache_enumerate(mc, me);
80 + key = strdup(me->key);
81 + me = cache_enumerate(mc, me);
82 + if (!key || *key == '*') {
88 - key = strdup(me->key);
89 - me = cache_enumerate(mc, me);
90 - if (!key || *key == '*') {
95 + path = make_fullpath(ap->path, key);
97 + warn(ap->logopt, "can't malloc storage for path");
102 - path = make_fullpath(ap->path, key);
105 - "can't malloc storage for path");
110 + * If this key has another valid entry we want to prune it,
111 + * even if it's a mount, as the valid entry will take the
112 + * mount if it is a direct mount or it's just a stale indirect
115 + valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
117 + is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
119 + "prune check posponed, %s mounted", path);
125 + cache_unlock(valid->mc);
127 - if (is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
129 - "prune check posponed, %s mounted", path);
135 + next_key = strdup(me->key);
138 - next_key = strdup(me->key);
141 + cache_writelock(mc);
142 + this = cache_lookup_distinct(mc, key);
148 - cache_writelock(mc);
149 - this = cache_lookup_distinct(mc, key);
155 - if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
157 - if (this->ioctlfd == -1)
158 - status = cache_delete(mc, key);
159 - if (status != CHE_FAIL) {
160 - if (ap->type == LKP_INDIRECT) {
161 - if (ap->flags & MOUNT_FLAG_GHOST)
162 - rmdir_path(ap, path, ap->dev);
164 - rmdir_path(ap, path, this->dev);
167 + cache_delete(mc, key);
168 + else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
170 + if (this->ioctlfd == -1)
171 + status = cache_delete(mc, key);
172 + if (status != CHE_FAIL) {
173 + if (ap->type == LKP_INDIRECT) {
174 + if (ap->flags & MOUNT_FLAG_GHOST)
175 + rmdir_path(ap, path, ap->dev);
177 + rmdir_path(ap, path, this->dev);
184 - cache_readlock(mc);
186 - me = cache_lookup_distinct(mc, next_key);
191 + cache_readlock(mc);
193 + me = cache_lookup_distinct(mc, next_key);
203 +int lookup_prune_cache(struct autofs_point *ap, time_t age)
205 + struct master_mapent *entry = ap->entry;
206 + struct map_source *map;
208 + pthread_cleanup_push(master_source_lock_cleanup, entry);
209 + master_source_readlock(entry);
213 + /* Is the map stale */
218 + pthread_cleanup_push(cache_lock_cleanup, map->mc);
219 + cache_readlock(map->mc);
220 + lookup_prune_one_cache(ap, map->mc, age);
221 pthread_cleanup_pop(1);
224 @@ -1124,7 +1142,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k
225 struct mapent_cache *mc;
226 struct mapent *me = NULL;
228 - master_source_readlock(entry);
232 @@ -1147,7 +1164,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k
236 - master_source_unlock(entry);
240 diff --git a/daemon/state.c b/daemon/state.c
241 index 533e241..84ccba3 100644
244 @@ -352,6 +352,68 @@ static void tree_mnts_cleanup(void *arg)
248 +static void do_readmap_mount(struct autofs_point *ap, struct mnt_list *mnts,
249 + struct map_source *map, struct mapent *me, time_t now)
251 + struct mapent_cache *nc;
252 + struct mapent *ne, *nested, *valid;
254 + nc = ap->entry->master->nc;
256 + ne = cache_lookup_distinct(nc, me->key);
258 + nested = cache_partial_match(nc, me->key);
261 + "removing invalid nested null entry %s",
263 + nested = cache_partial_match(nc, me->key);
265 + cache_delete(nc, nested->key);
269 + if (me->age < now || (ne && map->master_line > ne->age)) {
271 + * The map instance may have changed, such as the map name or
272 + * the mount options, but the direct map entry may still exist
273 + * in one of the other maps. If so then update the new cache
274 + * entry device and inode so we can find it at lookup. Later,
275 + * the mount for the new cache entry will just update the
278 + * TODO: how do we recognise these orphaned map instances. We
279 + * can't just delete these instances when the cache becomes
280 + * empty because that is a valid state for a master map entry.
281 + * This is becuase of the requirement to continue running with
282 + * an empty cache awaiting a map re-load.
284 + valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT);
286 + struct mapent_cache *vmc = valid->mc;
289 + "updating cache entry for valid direct trigger %s",
291 + cache_writelock(vmc);
292 + valid = cache_lookup_distinct(vmc, me->key);
293 + /* Take over the mount if there is one */
294 + valid->ioctlfd = me->ioctlfd;
296 + /* Set device and inode number of the new mapent */
297 + cache_set_ino_index(vmc, me->key, me->dev, me->ino);
299 + } else if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
300 + do_umount_autofs_direct(ap, mnts, me);
303 + "%s is mounted", me->key);
305 + do_mount_autofs_direct(ap, mnts, me);
310 static void *do_readmap(void *arg)
312 struct autofs_point *ap;
313 @@ -398,7 +460,8 @@ static void *do_readmap(void *arg)
314 lookup_prune_cache(ap, now);
315 status = lookup_ghost(ap, ap->path);
317 - struct mapent *me, *ne, *nested;
320 mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
321 pthread_cleanup_push(tree_mnts_cleanup, mnts);
322 pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
323 @@ -418,31 +481,10 @@ static void *do_readmap(void *arg)
325 me = cache_enumerate(mc, NULL);
327 - ne = cache_lookup_distinct(nc, me->key);
329 - nested = cache_partial_match(nc, me->key);
332 - "removing invalid nested null entry %s",
334 - nested = cache_partial_match(nc, me->key);
336 - cache_delete(nc, nested->key);
340 - /* TODO: check return of do_... */
341 - if (me->age < now || (ne && map->master_line > ne->age)) {
342 - if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
343 - do_umount_autofs_direct(ap, mnts, me);
346 - "%s is mounted", me->key);
348 - do_mount_autofs_direct(ap, mnts, me);
350 + do_readmap_mount(ap, mnts, map, me, now);
351 me = cache_enumerate(mc, me);
353 + lookup_prune_one_cache(ap, map->mc, now);
354 pthread_cleanup_pop(1);
357 diff --git a/include/automount.h b/include/automount.h
358 index d4675bd..ae517a7 100644
359 --- a/include/automount.h
360 +++ b/include/automount.h
361 @@ -238,6 +238,7 @@ int lookup_enumerate(struct autofs_point *ap,
362 int lookup_ghost(struct autofs_point *ap, const char *root);
363 int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len);
364 void lookup_close_lookup(struct autofs_point *ap);
365 +void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age);
366 int lookup_prune_cache(struct autofs_point *ap, time_t age);
367 struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type);
368 struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type);