autofs-5.1.3 - only take master map mutex for master map update
From: Ian Kent <raven@themaw.net>
When a map read is done it's neccessary to re-initialize the lookup
context which requires a write lock to be taken on the master map
entry source. Currently a map re-read also takes the master map lock
which will block new lookups.
If the lookup module thinks the map has been modified it will queue
a map read which will take these locks.
Now, when a bind mount (or symlink) is triggered by a lookup it's
necessary to trigger automounts that are included in the target path
for the dependent path to be valid.
When the target path triggers automounts in this way and refers to the
same master map entry, and a map re-read is scheduled and started and
manages to take the master map lock before the dependent lookup gets
past the master map lock check, the dependent path lookup will deadlock.
But the master map lock is meant to gaurd against master map entries
going away during lookups so isn't really needed for map reads as long
as the master map lock is held during the update of the mounted
automounts.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1 +
daemon/state.c | 3 ---
lib/master.c | 45 +++++++++++++++++++++++++++++++++++++--------
3 files changed, 38 insertions(+), 11 deletions(-)
--- autofs-5.0.7.orig/daemon/state.c
+++ autofs-5.0.7/daemon/state.c
@@ -484,12 +484,9 @@ static void *do_readmap(void *arg)
info(ap->logopt, "re-reading map for %s", ap->path);
- pthread_cleanup_push(master_mutex_lock_cleanup, NULL);
- master_mutex_lock();
status = lookup_nss_read_map(ap, NULL, now);
if (!status)
pthread_exit(NULL);
- pthread_cleanup_pop(1);
if (ap->type == LKP_INDIRECT) {
struct ioctl_ops *ops = get_ioctl_ops();
--- autofs-5.0.7.orig/lib/master.c
+++ autofs-5.0.7/lib/master.c
@@ -1089,6 +1089,39 @@ next:
free(paths);
}
+static void wait_for_lookups_and_lock(struct master *master)
+{
+ struct list_head *p, *head;
+ int status;
+
+again:
+ master_mutex_lock();
+
+ head = &master->mounts;
+ p = head->next;
+ while (p != head) {
+ struct master_mapent *this;
+
+ this = list_entry(p, struct master_mapent, list);
+
+ status = pthread_rwlock_trywrlock(&this->source_lock);
+ if (status) {
+ struct timespec t = { 0, 200000000 };
+ struct timespec r;
+
+ master_mutex_unlock();
+
+ while (nanosleep(&t, &r) == -1 && errno == EINTR)
+ memcpy(&t, &r, sizeof(struct timespec));
+
+ goto again;
+ }
+ master_source_unlock(this);
+
+ p = p->next;
+ }
+}
+
int master_read_master(struct master *master, time_t age, int readall)
{
unsigned int logopt = master->logopt;
@@ -1098,7 +1131,7 @@ int master_read_master(struct master *ma
* We need to clear and re-populate the null map entry cache
* before alowing anyone else to use it.
*/
- master_mutex_lock();
+ wait_for_lookups_and_lock(master);
if (master->nc) {
cache_writelock(master->nc);
nc = master->nc;
@@ -1118,21 +1151,19 @@ int master_read_master(struct master *ma
lookup_nss_read_master(master, age);
cache_unlock(nc);
master_add_amd_mount_section_mounts(master, age);
- master_mutex_unlock();
if (!master->read_fail)
master_mount_mounts(master, age, readall);
else {
master->read_fail = 0;
/* HUP signal sets readall == 1 only */
- if (!readall)
+ if (!readall) {
+ master_mutex_unlock();
return 0;
- else
+ } else
master_mount_mounts(master, age, readall);
}
- master_mutex_lock();
-
if (list_empty(&master->mounts))
warn(logopt, "no mounts in table");
@@ -1422,7 +1453,6 @@ int master_mount_mounts(struct master *m
int cur_state;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
- master_mutex_lock();
head = &master->mounts;
p = head->next;
@@ -1510,7 +1540,6 @@ cont:
}
}
- master_mutex_unlock();
pthread_setcancelstate(cur_state, NULL);
return 1;
--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -257,6 +257,7 @@
- fix some man page problems.
- allow dot in OPTIONSTR value lexer pattern.
- revert fix argc off by one in mount_autofs.c.
+- only take master map mutex for master map update.
25/07/2012 autofs-5.0.7
=======================