- add command line option to override is running check. - don't use proc fs for is running check. - fix fail on included browse map not found. - fix incorrect multi source messages. - clear stale flag on map read. - fix proximity other rpc ping timeout. - refactor mount request vars code. - make handle_mounts startup condition distinct. - fix submount shutdown handling. - try not to block on expire. - add configuration paramter UMOUNT_WAIT. - fix multi mount race. - fix nfs4 colon escape handling. - check replicated list after probe. - add replicated server selection debug logging. - update replicated server selection documentation. - use /dev/urandom instead of /dev/random. - check for mtab pointing to /proc/mounts. - fix interface config buffer size. - fix percent hack heap corruption.
496 lines
14 KiB
Diff
496 lines
14 KiB
Diff
autofs-5.0.3 - try not to block on expire
|
|
|
|
From: Ian Kent <raven@themaw.net>
|
|
|
|
When a server is not available umount and any stat statfs and related
|
|
function calls may block for a significant amount of time. This effects
|
|
expire timeouts a lot due to their synchronous nature. This patch limits
|
|
the time we wait on spawned umounts and elininates calls to functions
|
|
that would block. This allows us to retry the umount on the next expire
|
|
event and continue the expire of remaining mounts.
|
|
---
|
|
|
|
CHANGELOG | 2 ++
|
|
daemon/automount.c | 34 ++++++++++++++++++------------
|
|
daemon/direct.c | 29 +++++---------------------
|
|
daemon/indirect.c | 26 +++++++++--------------
|
|
daemon/spawn.c | 59 ++++++++++++++++++++++++++++++++++++++++++----------
|
|
include/master.h | 1 +
|
|
lib/master.c | 23 ++++++++++++++++++++
|
|
lib/mounts.c | 48 ++----------------------------------------
|
|
8 files changed, 112 insertions(+), 110 deletions(-)
|
|
|
|
|
|
diff --git a/CHANGELOG b/CHANGELOG
|
|
index ff04985..ff44cc7 100644
|
|
--- a/CHANGELOG
|
|
+++ b/CHANGELOG
|
|
@@ -27,6 +27,8 @@
|
|
- don't use proc file system when checking if the daemon is running.
|
|
- make handle_mounts startup condition distinct.
|
|
- fix submount shutdown recovery handling.
|
|
+- avoid stat of possibly dead mount points and limit time to wait for
|
|
+ umount during expire.
|
|
|
|
14/01/2008 autofs-5.0.3
|
|
-----------------------
|
|
diff --git a/daemon/automount.c b/daemon/automount.c
|
|
index 68bf1d3..5bd5f6d 100644
|
|
--- a/daemon/automount.c
|
|
+++ b/daemon/automount.c
|
|
@@ -247,9 +247,17 @@ static int walk_tree(const char *base, int (*fn) (unsigned logopt,
|
|
int, void *), int incl, unsigned logopt, void *arg)
|
|
{
|
|
char buf[PATH_MAX + 1];
|
|
- struct stat st;
|
|
+ struct stat st, *pst = &st;
|
|
+ int ret;
|
|
+
|
|
+ if (!is_mounted(_PATH_MOUNTED, base, MNTS_REAL))
|
|
+ ret = lstat(base, pst);
|
|
+ else {
|
|
+ pst = NULL;
|
|
+ ret = 0;
|
|
+ }
|
|
|
|
- if (lstat(base, &st) != -1 && (fn) (logopt, base, &st, 0, arg)) {
|
|
+ if (ret != -1 && (fn) (logopt, base, pst, 0, arg)) {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
struct dirent **de;
|
|
int n;
|
|
@@ -283,7 +291,7 @@ static int walk_tree(const char *base, int (*fn) (unsigned logopt,
|
|
free(de);
|
|
}
|
|
if (incl)
|
|
- (fn) (logopt, base, &st, 1, arg);
|
|
+ (fn) (logopt, base, pst, 1, arg);
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -294,6 +302,9 @@ static int rm_unwanted_fn(unsigned logopt, const char *file, const struct stat *
|
|
char buf[MAX_ERR_BUF];
|
|
struct stat newst;
|
|
|
|
+ if (!st)
|
|
+ return 0;
|
|
+
|
|
if (when == 0) {
|
|
if (st->st_dev != dev)
|
|
return 0;
|
|
@@ -344,8 +355,8 @@ static int counter_fn(unsigned logopt, const char *file, const struct stat *st,
|
|
{
|
|
struct counter_args *counter = (struct counter_args *) arg;
|
|
|
|
- if (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode)
|
|
- && st->st_dev != counter->dev)) {
|
|
+ if (!st || (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode)
|
|
+ && st->st_dev != counter->dev))) {
|
|
counter->count++;
|
|
return 0;
|
|
}
|
|
@@ -512,9 +523,8 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
|
|
int umount_multi(struct autofs_point *ap, const char *path, int incl)
|
|
{
|
|
struct mapent_cache *nc;
|
|
- struct statfs fs;
|
|
int is_autofs_fs;
|
|
- int ret, left;
|
|
+ int left;
|
|
|
|
debug(ap->logopt, "path %s incl %d", path, incl);
|
|
|
|
@@ -526,13 +536,9 @@ int umount_multi(struct autofs_point *ap, const char *path, int incl)
|
|
}
|
|
cache_unlock(nc);
|
|
|
|
- ret = statfs(path, &fs);
|
|
- if (ret == -1) {
|
|
- error(ap->logopt, "could not stat fs of %s", path);
|
|
- return 1;
|
|
- }
|
|
-
|
|
- is_autofs_fs = fs.f_type == (__SWORD_TYPE) AUTOFS_SUPER_MAGIC ? 1 : 0;
|
|
+ is_autofs_fs = 0;
|
|
+ if (master_find_submount(ap, path))
|
|
+ is_autofs_fs = 1;
|
|
|
|
left = 0;
|
|
|
|
diff --git a/daemon/direct.c b/daemon/direct.c
|
|
index 334a4b6..7fb78a3 100644
|
|
--- a/daemon/direct.c
|
|
+++ b/daemon/direct.c
|
|
@@ -152,7 +152,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
|
|
|
|
retries = UMOUNT_RETRIES;
|
|
while ((rv = umount(me->key)) == -1 && retries--) {
|
|
- struct timespec tm = {0, 100000000};
|
|
+ struct timespec tm = {0, 200000000};
|
|
if (errno != EBUSY)
|
|
break;
|
|
nanosleep(&tm, NULL);
|
|
@@ -604,7 +604,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
|
|
|
|
retries = UMOUNT_RETRIES;
|
|
while ((rv = umount(me->key)) == -1 && retries--) {
|
|
- struct timespec tm = {0, 100000000};
|
|
+ struct timespec tm = {0, 200000000};
|
|
if (errno != EBUSY)
|
|
break;
|
|
nanosleep(&tm, NULL);
|
|
@@ -705,7 +705,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
|
|
* the kernel NFS client.
|
|
*/
|
|
if (me->multi != me &&
|
|
- is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL))
|
|
+ is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL))
|
|
return MOUNT_OFFSET_IGNORE;
|
|
|
|
/*
|
|
@@ -807,17 +807,7 @@ out_err:
|
|
|
|
static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
|
|
{
|
|
- char buf[MAX_ERR_BUF];
|
|
- int ret, retries;
|
|
- struct stat st;
|
|
-
|
|
- if (fstat(ioctlfd, &st) == -1) {
|
|
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
- debug(logopt, "fstat failed: %s", estr);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
|
|
+ int ret, retries = EXPIRE_RETRIES;
|
|
|
|
while (retries--) {
|
|
struct timespec tm = {0, 100000000};
|
|
@@ -911,7 +901,6 @@ void *expire_proc_direct(void *arg)
|
|
|
|
if (!strcmp(next->fs_type, "autofs")) {
|
|
struct stat st;
|
|
- struct statfs fs;
|
|
int ioctlfd;
|
|
|
|
cache_unlock(me->mc);
|
|
@@ -932,14 +921,8 @@ void *expire_proc_direct(void *arg)
|
|
continue;
|
|
}
|
|
|
|
- if (statfs(next->path, &fs) == -1) {
|
|
- pthread_setcancelstate(cur_state, NULL);
|
|
- warn(ap->logopt,
|
|
- "fstatfs failed for %s", next->path);
|
|
- continue;
|
|
- }
|
|
-
|
|
- if (fs.f_type != (__SWORD_TYPE) AUTOFS_SUPER_MAGIC) {
|
|
+ /* It's got a mount, deal with in the outer loop */
|
|
+ if (tree_is_mounted(mnts, me->key, MNTS_REAL)) {
|
|
pthread_setcancelstate(cur_state, NULL);
|
|
continue;
|
|
}
|
|
diff --git a/daemon/indirect.c b/daemon/indirect.c
|
|
index 17bed3e..e832cd4 100644
|
|
--- a/daemon/indirect.c
|
|
+++ b/daemon/indirect.c
|
|
@@ -285,7 +285,7 @@ int umount_autofs_indirect(struct autofs_point *ap)
|
|
|
|
retries = UMOUNT_RETRIES;
|
|
while ((rv = umount(ap->path)) == -1 && retries--) {
|
|
- struct timespec tm = {0, 100000000};
|
|
+ struct timespec tm = {0, 200000000};
|
|
if (errno != EBUSY)
|
|
break;
|
|
nanosleep(&tm, NULL);
|
|
@@ -368,17 +368,7 @@ force_umount:
|
|
|
|
static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when)
|
|
{
|
|
- char buf[MAX_ERR_BUF];
|
|
- int ret, retries;
|
|
- struct stat st;
|
|
-
|
|
- if (fstat(ioctlfd, &st) == -1) {
|
|
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
- debug(ap->logopt, "fstat failed: %s", estr);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
|
|
+ int ret, retries = EXPIRE_RETRIES;
|
|
|
|
while (retries--) {
|
|
struct timespec tm = {0, 100000000};
|
|
@@ -512,7 +502,6 @@ void *expire_proc_indirect(void *arg)
|
|
left++;
|
|
pthread_setcancelstate(cur_state, NULL);
|
|
}
|
|
- pthread_cleanup_pop(1);
|
|
|
|
/*
|
|
* If there are no more real mounts left we could still
|
|
@@ -520,12 +509,17 @@ void *expire_proc_indirect(void *arg)
|
|
* umount them here.
|
|
*/
|
|
if (mnts) {
|
|
+ int retries;
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
|
|
- ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
|
|
- if (!ret)
|
|
- left++;
|
|
+ retries = (count_mounts(ap->logopt, ap->path, ap->dev) + 1);
|
|
+ while (retries--) {
|
|
+ ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
|
|
+ if (!ret)
|
|
+ left++;
|
|
+ }
|
|
pthread_setcancelstate(cur_state, NULL);
|
|
}
|
|
+ pthread_cleanup_pop(1);
|
|
|
|
count = offsets = submnts = 0;
|
|
mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
|
|
diff --git a/daemon/spawn.c b/daemon/spawn.c
|
|
index 78d69c6..e3c355e 100644
|
|
--- a/daemon/spawn.c
|
|
+++ b/daemon/spawn.c
|
|
@@ -89,13 +89,43 @@ void reset_signals(void)
|
|
|
|
#define ERRBUFSIZ 2047 /* Max length of error string excl \0 */
|
|
|
|
-static int do_spawn(unsigned logopt, unsigned int options, const char *prog, const char *const *argv)
|
|
+static int timed_read(int pipe, char *buf, size_t len, int time)
|
|
+{
|
|
+ struct timeval timeout = { 0, 0 };
|
|
+ struct timeval *tout = NULL;
|
|
+ fd_set wset, rset;
|
|
+ int ret;
|
|
+
|
|
+ FD_ZERO(&rset);
|
|
+ FD_SET(pipe, &rset);
|
|
+ wset = rset;
|
|
+
|
|
+ if (time != -1) {
|
|
+ timeout.tv_sec = time;
|
|
+ tout = &timeout;
|
|
+ }
|
|
+
|
|
+ ret = select(pipe + 1, &rset, &wset, NULL, tout);
|
|
+ if (ret <= 0) {
|
|
+ if (ret == 0)
|
|
+ ret = -ETIMEDOUT;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ while ((ret = read(pipe, buf, len)) == -1 && errno == EINTR);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int do_spawn(unsigned logopt, unsigned int wait,
|
|
+ unsigned int options, const char *prog,
|
|
+ const char *const *argv)
|
|
{
|
|
pid_t f;
|
|
int ret, status, pipefd[2];
|
|
char errbuf[ERRBUFSIZ + 1], *p, *sp;
|
|
int errp, errn;
|
|
- int cancel_state;
|
|
+ int flags, cancel_state;
|
|
unsigned int use_lock = options & SPAWN_OPT_LOCK;
|
|
unsigned int use_access = options & SPAWN_OPT_ACCESS;
|
|
sigset_t allsigs, tmpsig, oldsig;
|
|
@@ -183,12 +213,15 @@ static int do_spawn(unsigned logopt, unsigned int options, const char *prog, con
|
|
return -1;
|
|
}
|
|
|
|
+ if ((flags = fcntl(pipefd[0], F_GETFD, 0)) != -1) {
|
|
+ flags |= FD_CLOEXEC;
|
|
+ fcntl(pipefd[0], F_SETFD, flags);
|
|
+ }
|
|
+
|
|
errp = 0;
|
|
do {
|
|
- while ((errn =
|
|
- read(pipefd[0], errbuf + errp, ERRBUFSIZ - errp)) == -1
|
|
- && errno == EINTR);
|
|
-
|
|
+ errn = timed_read(pipefd[0],
|
|
+ errbuf + errp, ERRBUFSIZ - errp, wait);
|
|
if (errn > 0) {
|
|
errp += errn;
|
|
|
|
@@ -213,6 +246,9 @@ static int do_spawn(unsigned logopt, unsigned int options, const char *prog, con
|
|
}
|
|
} while (errn > 0);
|
|
|
|
+ if (errn == -ETIMEDOUT)
|
|
+ kill(f, SIGTERM);
|
|
+
|
|
close(pipefd[0]);
|
|
|
|
if (errp > 0) {
|
|
@@ -238,7 +274,7 @@ static int do_spawn(unsigned logopt, unsigned int options, const char *prog, con
|
|
|
|
int spawnv(unsigned logopt, const char *prog, const char *const *argv)
|
|
{
|
|
- return do_spawn(logopt, SPAWN_OPT_NONE, prog, argv);
|
|
+ return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, argv);
|
|
}
|
|
|
|
int spawnl(unsigned logopt, const char *prog, ...)
|
|
@@ -259,7 +295,7 @@ int spawnl(unsigned logopt, const char *prog, ...)
|
|
while ((*p++ = va_arg(arg, char *)));
|
|
va_end(arg);
|
|
|
|
- return do_spawn(logopt, SPAWN_OPT_NONE, prog, (const char **) argv);
|
|
+ return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, (const char **) argv);
|
|
}
|
|
|
|
int spawn_mount(unsigned logopt, ...)
|
|
@@ -307,7 +343,7 @@ int spawn_mount(unsigned logopt, ...)
|
|
va_end(arg);
|
|
|
|
while (retries--) {
|
|
- ret = do_spawn(logopt, options, prog, (const char **) argv);
|
|
+ ret = do_spawn(logopt, -1, options, prog, (const char **) argv);
|
|
if (ret & MTAB_NOTUPDATED) {
|
|
struct timespec tm = {3, 0};
|
|
|
|
@@ -406,7 +442,7 @@ int spawn_bind_mount(unsigned logopt, ...)
|
|
va_end(arg);
|
|
|
|
while (retries--) {
|
|
- ret = do_spawn(logopt, options, prog, (const char **) argv);
|
|
+ ret = do_spawn(logopt, -1, options, prog, (const char **) argv);
|
|
if (ret & MTAB_NOTUPDATED) {
|
|
struct timespec tm = {3, 0};
|
|
|
|
@@ -466,6 +502,7 @@ int spawn_umount(unsigned logopt, ...)
|
|
unsigned int options;
|
|
unsigned int retries = MTAB_LOCK_RETRIES;
|
|
int ret, printed = 0;
|
|
+ unsigned int wait = 12;
|
|
|
|
#ifdef ENABLE_MOUNT_LOCKING
|
|
options = SPAWN_OPT_LOCK;
|
|
@@ -488,7 +525,7 @@ int spawn_umount(unsigned logopt, ...)
|
|
va_end(arg);
|
|
|
|
while (retries--) {
|
|
- ret = do_spawn(logopt, options, prog, (const char **) argv);
|
|
+ ret = do_spawn(logopt, wait, options, prog, (const char **) argv);
|
|
if (ret & MTAB_NOTUPDATED) {
|
|
/*
|
|
* If the mount succeeded but the mtab was not
|
|
diff --git a/include/master.h b/include/master.h
|
|
index 86ae045..a397a75 100644
|
|
--- a/include/master.h
|
|
+++ b/include/master.h
|
|
@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *);
|
|
void master_source_current_wait(struct master_mapent *);
|
|
void master_source_current_signal(struct master_mapent *);
|
|
struct master_mapent *master_find_mapent(struct master *, const char *);
|
|
+struct autofs_point *master_find_submount(struct autofs_point *, const char *);
|
|
struct master_mapent *master_new_mapent(struct master *, const char *, time_t);
|
|
void master_add_mapent(struct master *, struct master_mapent *);
|
|
void master_remove_mapent(struct master_mapent *);
|
|
diff --git a/lib/master.c b/lib/master.c
|
|
index 522b919..71ba04a 100644
|
|
--- a/lib/master.c
|
|
+++ b/lib/master.c
|
|
@@ -602,6 +602,29 @@ struct master_mapent *master_find_mapent(struct master *master, const char *path
|
|
return NULL;
|
|
}
|
|
|
|
+struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
|
|
+{
|
|
+ struct list_head *head, *p;
|
|
+
|
|
+ mounts_mutex_lock(ap);
|
|
+
|
|
+ head = &ap->submounts;
|
|
+ list_for_each(p, head) {
|
|
+ struct autofs_point *submount;
|
|
+
|
|
+ submount = list_entry(p, struct autofs_point, mounts);
|
|
+
|
|
+ if (!strcmp(submount->path, path)) {
|
|
+ mounts_mutex_unlock(ap);
|
|
+ return submount;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mounts_mutex_unlock(ap);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age)
|
|
{
|
|
struct master_mapent *entry;
|
|
diff --git a/lib/mounts.c b/lib/mounts.c
|
|
index a4bf86c..d77a6b0 100644
|
|
--- a/lib/mounts.c
|
|
+++ b/lib/mounts.c
|
|
@@ -1073,55 +1073,11 @@ free_tsv:
|
|
|
|
int umount_ent(struct autofs_point *ap, const char *path)
|
|
{
|
|
- struct stat st;
|
|
- struct statfs fs;
|
|
- int sav_errno;
|
|
- int status, is_smbfs = 0;
|
|
- int ret, rv = 1;
|
|
-
|
|
- ret = statfs(path, &fs);
|
|
- if (ret == -1) {
|
|
- warn(ap->logopt, "could not stat fs of %s", path);
|
|
- is_smbfs = 0;
|
|
- } else {
|
|
- int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER;
|
|
- int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC;
|
|
- is_smbfs = (cifsfs | smbfs) ? 1 : 0;
|
|
- }
|
|
-
|
|
- status = lstat(path, &st);
|
|
- sav_errno = errno;
|
|
-
|
|
- if (status < 0)
|
|
- warn(ap->logopt, "lstat of %s failed with %d", path, status);
|
|
-
|
|
- /*
|
|
- * lstat failed and we're an smbfs fs returning an error that is not
|
|
- * EIO or EBADSLT or the lstat failed so it's a bad path. Return
|
|
- * a fail.
|
|
- *
|
|
- * EIO appears to correspond to an smb mount that has gone away
|
|
- * and EBADSLT relates to CD changer not responding.
|
|
- */
|
|
- if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
|
|
- rv = spawn_umount(ap->logopt, path, NULL);
|
|
- } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
|
|
- rv = spawn_umount(ap->logopt, path, NULL);
|
|
- }
|
|
+ int rv;
|
|
|
|
+ rv = spawn_umount(ap->logopt, path, NULL);
|
|
/* We are doing a forced shutcwdown down so unlink busy mounts */
|
|
if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) {
|
|
- ret = stat(path, &st);
|
|
- if (ret == -1 && errno == ENOENT) {
|
|
- warn(ap->logopt, "mount point does not exist");
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (ret == 0 && !S_ISDIR(st.st_mode)) {
|
|
- warn(ap->logopt, "mount point is not a directory");
|
|
- return 0;
|
|
- }
|
|
-
|
|
if (ap->state == ST_SHUTDOWN_FORCE) {
|
|
info(ap->logopt, "forcing umount of %s", path);
|
|
rv = spawn_umount(ap->logopt, "-l", path, NULL);
|