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);