Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 29

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.3 - add autofs mount contol library

From: Ian Kent <raven@themaw.net>

This patch adds a library for autofs mount point control functions.
It will use either the standard ioctl interface or, if detected, the
newer miscellaneous device file ioctl interface.

It isolates the use of autofs control functions to one place and
provides a common call interface for the daemon to use.

In addition it will check to see if the kernel supports the newer
miscellaneous device node ioctl interface and uses it if present.
---

 daemon/automount.c             |   38 -
 daemon/direct.c                |  263 +++++--------
 daemon/indirect.c              |  137 +++----
 daemon/lookup.c                |    3 
 daemon/state.c                 |    8 
 include/automount.h            |    3 
 include/dev-ioctl-lib.h        |   63 +++
 include/linux/auto_dev-ioctl.h |  225 +++++++++++
 include/linux/auto_fs4.h       |    9 
 include/mounts.h               |   14 
 lib/Makefile                   |    5 
 lib/dev-ioctl-lib.c            |  788 +++++++++++++++++++++++++++++++++++++++++
 lib/master_parse.y             |    3 
 lib/mounts.c                   |   29 -
 modules/parse_sun.c            |    3 
 redhat/autofs.init.in          |   17 
 redhat/autofs.sysconfig.in     |    5 
 samples/autofs.conf.default.in |    5 
 samples/rc.autofs.in           |   16 
 19 files changed, 1344 insertions(+), 290 deletions(-)
 create mode 100644 include/dev-ioctl-lib.h
 create mode 100644 include/linux/auto_dev-ioctl.h
 create mode 100644 lib/dev-ioctl-lib.c


--- autofs-5.0.1.orig/daemon/automount.c
+++ autofs-5.0.1/daemon/automount.c
@@ -590,40 +590,6 @@ int umount_autofs(struct autofs_point *a
 	return ret;
 }
 
-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
-{
-	char buf[MAX_ERR_BUF];
-
-	if (wait_queue_token == 0)
-		return 0;
-
-	debug(logopt, "token = %d", wait_queue_token);
-
-	if (ioctl(ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr("AUTOFS_IOC_READY: error %s", estr);
-		return 1;
-	}
-	return 0;
-}
-
-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
-{
-	char buf[MAX_ERR_BUF];
-
-	if (wait_queue_token == 0)
-		return 0;
-
-	debug(logopt, "token = %d", wait_queue_token);
-
-	if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr("AUTOFS_IOC_FAIL: error %s", estr);
-		return 1;
-	}
-	return 0;
-}
-
 static int fullread(int fd, void *ptr, size_t len)
 {
 	char *buf = (char *) ptr;
@@ -2112,6 +2078,8 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
+	init_ioctl_ctl();
+
 	if (!alarm_start_handler()) {
 		logerr("%s: failed to create alarm handler thread!", program);
 		master_kill(master_list);
@@ -2161,6 +2129,8 @@ int main(int argc, char *argv[])
 	if (dh_xml2)
 		dlclose(dh_xml2);
 #endif
+	close_ioctl_ctl();
+
 	info(logging, "autofs stopped");
 
 	exit(0);
--- autofs-5.0.1.orig/daemon/direct.c
+++ autofs-5.0.1/daemon/direct.c
@@ -86,6 +86,7 @@ static void mnts_cleanup(void *arg)
 
 int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
 	int ioctlfd, rv, left, retries;
 
@@ -104,23 +105,13 @@ int do_umount_autofs_direct(struct autof
 			return 1;
 		}
 		ioctlfd = me->ioctlfd;
-	} else {
-		int cl_flags;
-
-		ioctlfd = open(me->key, O_RDONLY);
-		if (ioctlfd != -1) {
-			if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
-				cl_flags |= FD_CLOEXEC;
-				fcntl(ioctlfd, F_SETFD, cl_flags);
-			}
-		}
-	}
-
+	} else
+		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
 
 	if (ioctlfd >= 0) {
-		int status = 1;
+		unsigned int status = 1;
 
-		rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+		rv = ops->askumount(ap->logopt, ioctlfd, &status);
 		if (rv) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			error(ap->logopt, "ioctl failed: %s", estr);
@@ -133,19 +124,17 @@ int do_umount_autofs_direct(struct autof
 				return 1;
 			} else {
 				me->ioctlfd = -1;
-				ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
-				close(ioctlfd);
+				ops->catatonic(ap->logopt, ioctlfd);
+				ops->close(ap->logopt, ioctlfd);
 				goto force_umount;
 			}
 		}
 		me->ioctlfd = -1;
-		ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
-		close(ioctlfd);
+		ops->catatonic(ap->logopt, ioctlfd);
+		ops->close(ap->logopt, ioctlfd);
 	} else {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		error(ap->logopt,
 		      "couldn't get ioctl fd for direct mount %s", me->key);
-		debug(ap->logopt, "open: %s", estr);
 		return 1;
 	}
 
@@ -292,10 +281,11 @@ static int unlink_mount_tree(struct auto
 
 int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct mnt_params *mp;
 	time_t timeout = ap->exp_timeout;
 	struct stat st;
-	int status, ret, ioctlfd, cl_flags;
+	int status, ret, ioctlfd;
 	struct list_head list;
 	const char *map_name;
 
@@ -308,16 +298,9 @@ int do_mount_autofs_direct(struct autofs
 
 			save_ioctlfd = ioctlfd = me->ioctlfd;
 
-			if (ioctlfd == -1) {
-				ioctlfd = open(me->key, O_RDONLY);
-				if (ioctlfd != -1) {
-					cl_flags = fcntl(ioctlfd, F_GETFD, 0);
-					if (cl_flags != -1) {
-						cl_flags |= FD_CLOEXEC;
-						fcntl(ioctlfd, F_SETFD, cl_flags);
-					}
-				}
-			}
+			if (ioctlfd == -1)
+				ops->open(ap->logopt,
+					  &ioctlfd, me->dev, me->key);
 
 			if (ioctlfd < 0) {
 				error(ap->logopt,
@@ -326,13 +309,14 @@ int do_mount_autofs_direct(struct autofs
 				return 0;
 			}
 
-			ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
+			ops->timeout(ap->logopt, ioctlfd, &tout);
 
 			if (save_ioctlfd == -1)
-				close(ioctlfd);
+				ops->close(ap->logopt, ioctlfd);
 
 			return 0;
 		}
+
 		if (!unlink_mount_tree(ap, &list)) {
 			debug(ap->logopt,
 			      "already mounted as other than autofs "
@@ -397,22 +381,23 @@ int do_mount_autofs_direct(struct autofs
 		goto out_err;
 	}
 
-	/* Root directory for ioctl()'s */
-	ioctlfd = open(me->key, O_RDONLY);
-	if (ioctlfd < 0) {
-		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
+	ret = stat(me->key, &st);
+	if (ret == -1) {
+		error(ap->logopt,
+		      "failed to stat direct mount trigger %s", me->key);
 		goto out_umount;
 	}
 
-	if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
-		cl_flags |= FD_CLOEXEC;
-		fcntl(ioctlfd, F_SETFD, cl_flags);
+	ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key);
+	if (ioctlfd < 0) {
+		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
+		goto out_umount;
 	}
 
 	/* Calculate the timeouts */
 	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
 
-	ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+	ops->timeout(ap->logopt, ioctlfd, &timeout);
 
 	if (ap->exp_timeout)
 		info(ap->logopt,
@@ -425,22 +410,14 @@ int do_mount_autofs_direct(struct autofs
 		     "mounted direct mount on %s with timeouts disabled",
 		     me->key);
 
-	ret = fstat(ioctlfd, &st);
-	if (ret == -1) {
-		error(ap->logopt,
-		      "failed to stat direct mount trigger %s", me->key);
-		goto out_close;
-	}
 	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
 
-	close(ioctlfd);
+	ops->close(ap->logopt, ioctlfd);
 
 	debug(ap->logopt, "mounted trigger %s", me->key);
 
 	return 0;
 
-out_close:
-	close(ioctlfd);
 out_umount:
 	/* TODO: maybe force umount (-l) */
 	umount(me->key);
@@ -532,8 +509,9 @@ int mount_autofs_direct(struct autofs_po
 
 int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
-	int ioctlfd, cl_flags, rv = 1, retries;
+	int ioctlfd, rv = 1, retries;
 
 	if (me->ioctlfd != -1) {
 		if (is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) {
@@ -550,20 +528,13 @@ int umount_autofs_offset(struct autofs_p
 			      me->key);
 			return 0;
 		}
-
-		ioctlfd = open(me->key, O_RDONLY);
-		if (ioctlfd != -1) {
-			if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
-				cl_flags |= FD_CLOEXEC;
-				fcntl(ioctlfd, F_SETFD, cl_flags);
-			}
-		}
+		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
 	}
 
 	if (ioctlfd >= 0) {
-		int status = 1;
+		unsigned int status = 1;
 
-		rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+		rv = ops->askumount(ap->logopt, ioctlfd, &status);
 		if (rv) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			logerr("ioctl failed: %s", estr);
@@ -577,14 +548,14 @@ int umount_autofs_offset(struct autofs_p
 				return 1;
 			} else {
 				me->ioctlfd = -1;
-				ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
-				close(ioctlfd);
+				ops->catatonic(ap->logopt, ioctlfd);
+				ops->close(ap->logopt, ioctlfd);
 				goto force_umount;
 			}
 		}
 		me->ioctlfd = -1;
-		ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
-		close(ioctlfd);
+		ops->catatonic(ap->logopt, ioctlfd);
+		ops->close(ap->logopt, ioctlfd);
 	} else {
 		struct stat st;
 		char *estr;
@@ -649,11 +620,12 @@ force_umount:
 
 int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
 	struct mnt_params *mp;
 	time_t timeout = ap->exp_timeout;
 	struct stat st;
-	int ioctlfd, cl_flags, status, ret;
+	int ioctlfd, status, ret;
 	const char *type, *map_name = NULL;
 	char mountpoint[PATH_MAX];
 
@@ -766,37 +738,27 @@ int mount_autofs_offset(struct autofs_po
 		goto out_err;
 	}
 
-	/* Root directory for ioctl()'s */
-	ioctlfd = open(mountpoint, O_RDONLY);
-	if (ioctlfd < 0) {
-		crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
-		goto out_umount;
-	}
-
-	if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
-		cl_flags |= FD_CLOEXEC;
-		fcntl(ioctlfd, F_SETFD, cl_flags);
-	}
-
-	ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
-
-	ret = fstat(ioctlfd, &st);
+	ret = stat(mountpoint, &st);
 	if (ret == -1) {
 		error(ap->logopt,
 		     "failed to stat direct mount trigger %s", mountpoint);
-		goto out_close;
+		goto out_umount;
 	}
 
-	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
+	ops->open(ap->logopt, &ioctlfd, st.st_dev, mountpoint);
+	if (ioctlfd < 0) {
+		crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
+		goto out_umount;
+	}
 
-	close(ioctlfd);
+	ops->timeout(ap->logopt, ioctlfd, &timeout);
+	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
+	ops->close(ap->logopt, ioctlfd);
 
 	debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
 
 	return MOUNT_OFFSET_OK;
 
-out_close:
-	close(ioctlfd);
 out_umount:
 	umount(mountpoint);
 out_err:
@@ -806,38 +768,9 @@ out_err:
 	return MOUNT_OFFSET_FAIL;
 }
 
-static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
-{
-	int ret, retries = EXPIRE_RETRIES;
-
-	while (retries--) {
-		struct timespec tm = {0, 100000000};
-
-		/* Ggenerate expire message for the mount. */
-		ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
-		if (ret == -1) {
-			/* Mount has gone away */
-			if (errno == EBADF || errno == EINVAL)
-				return 1;
-
-			/* Other than need to wait for the kernel ? */
-			if (errno != EAGAIN)
-				return 0;
-		}
-
-		nanosleep(&tm, NULL);
-	}
-
-	if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
-		if (!ret)
-			return 0;
-	}
-
-	return 1;
-}
-
 void *expire_proc_direct(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct mnt_list *mnts = NULL, *next;
 	struct list_head list, *p;
 	struct expire_args *ea;
@@ -936,28 +869,33 @@ void *expire_proc_direct(void *arg)
 			 */
 
 			/* Offsets always have a real mount at their base */
+			cache_writelock(me->mc);
 			if (strstr(next->opts, "offset")) {
-				close(me->ioctlfd);
+				ops->close(ap->logopt, me->ioctlfd);
 				me->ioctlfd = -1;
+				cache_unlock(me->mc);
 				pthread_setcancelstate(cur_state, NULL);
 				continue;
 			}
+			cache_unlock(me->mc);
 
 			ioctlfd = me->ioctlfd;
 
-			ret = expire_direct(ioctlfd, next->path, now, ap->logopt);
-			if (!ret) {
+			ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+			if (ret) {
 				left++;
 				pthread_setcancelstate(cur_state, NULL);
 				continue;
 			}
 
+			cache_writelock(me->mc);
 			if (me->ioctlfd != -1 && 
 			    fstat(ioctlfd, &st) != -1 &&
 			    !count_mounts(ap->logopt, next->path, st.st_dev)) {
-				close(ioctlfd);
+				ops->close(ap->logopt, ioctlfd);
 				me->ioctlfd = -1;
 			}
+			cache_unlock(me->mc);
 
 			pthread_setcancelstate(cur_state, NULL);
 			continue;
@@ -978,8 +916,8 @@ void *expire_proc_direct(void *arg)
 		debug(ap->logopt, "send expire to trigger %s", next->path);
 
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-		ret = expire_direct(ioctlfd, next->path, now, ap->logopt);
-		if (!ret)
+		ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+		if (ret)
 			left++;
 		pthread_setcancelstate(cur_state, NULL);
 	}
@@ -1010,8 +948,11 @@ static void pending_cond_destroy(void *a
 
 static void expire_send_fail(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt = arg;
-	send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+	struct autofs_point *ap = mt->ap;
+	ops->send_fail(ap->logopt,
+		       mt->ioctlfd, mt->wait_queue_token, -ENOENT);
 }
 
 static void free_pending_args(void *arg)
@@ -1029,6 +970,7 @@ static void expire_mutex_unlock(void *ar
 
 static void *do_expire_direct(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt;
 	struct autofs_point *ap;
 	size_t len;
@@ -1063,15 +1005,16 @@ static void *do_expire_direct(void *arg)
 	status = do_expire(ap, mt->name, len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status)
-		send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       mt->ioctlfd, mt->wait_queue_token, -ENOENT);
 	else {
 		struct mapent *me;
-		cache_readlock(mt->mc);
+		cache_writelock(mt->mc);
 		me = cache_lookup_distinct(mt->mc, mt->name);
 		me->ioctlfd = -1;
 		cache_unlock(mt->mc);
-		send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
-		close(mt->ioctlfd);
+		ops->send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+		ops->close(ap->logopt, mt->ioctlfd);
 	}
 	pthread_setcancelstate(state, NULL);
 
@@ -1084,6 +1027,7 @@ static void *do_expire_direct(void *arg)
 
 int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_direct_t *pkt)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct map_source *map;
 	struct mapent_cache *mc = NULL;
 	struct mapent *me = NULL;
@@ -1132,15 +1076,16 @@ int handle_packet_expire_direct(struct a
 
 	/* Can't expire it if it isn't mounted */
 	if (me->ioctlfd == -1) {
-		int ioctlfd = open(me->key, O_RDONLY);
+		int ioctlfd;
+		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
 		if (ioctlfd == -1) {
 			crit(ap->logopt, "can't open ioctlfd for %s",
 			     me->key);
 			pthread_setcancelstate(state, NULL);
 			return 1;
 		}
-		send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token);
-		close(ioctlfd);
+		ops->send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token);
+		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
@@ -1151,7 +1096,8 @@ int handle_packet_expire_direct(struct a
 	if (!mt) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		error(ap->logopt, "malloc: %s", estr);
-		send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       me->ioctlfd, pkt->wait_queue_token, -ENOMEM);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
@@ -1181,7 +1127,8 @@ int handle_packet_expire_direct(struct a
 	status = pthread_create(&thid, &th_attr_detached, do_expire_direct, mt);
 	if (status) {
 		error(ap->logopt, "expire thread create failed");
-		send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       mt->ioctlfd, pkt->wait_queue_token, -status);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		expire_mutex_unlock(NULL);
@@ -1214,9 +1161,11 @@ int handle_packet_expire_direct(struct a
 
 static void mount_send_fail(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt = arg;
-	send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
-	close(mt->ioctlfd);
+	struct autofs_point *ap = mt->ap;
+	ops->send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token, -ENOENT);
+	ops->close(ap->logopt, mt->ioctlfd);
 }
 
 static void pending_mutex_destroy(void *arg)
@@ -1237,6 +1186,7 @@ static void mount_mutex_unlock(void *arg
 
 static void *do_mount_direct(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *args, mt;
 	struct autofs_point *ap;
 	struct stat st;
@@ -1267,9 +1217,9 @@ static void *do_mount_direct(void *arg)
 	if (status == -1) {
 		error(ap->logopt,
 		      "can't stat direct mount trigger %s", mt.name);
-		send_fail(ap->logopt,
-			  mt.ioctlfd, mt.wait_queue_token);
-		close(mt.ioctlfd);
+		ops->send_fail(ap->logopt,
+			       mt.ioctlfd, mt.wait_queue_token, -ENOENT);
+		ops->close(ap->logopt, mt.ioctlfd);
 		pthread_setcancelstate(state, NULL);
 		pthread_exit(NULL);
 	}
@@ -1279,8 +1229,8 @@ static void *do_mount_direct(void *arg)
 		error(ap->logopt,
 		     "direct trigger not valid or already mounted %s",
 		     mt.name);
-		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
-		close(mt.ioctlfd);
+		ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+		ops->close(ap->logopt, mt.ioctlfd);
 		pthread_setcancelstate(state, NULL);
 		pthread_exit(NULL);
 	}
@@ -1318,14 +1268,16 @@ static void *do_mount_direct(void *arg)
 			if (!close_fd)
 				me->ioctlfd = mt.ioctlfd;
 		}
-		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+		ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
 		cache_unlock(mt.mc);
 		if (close_fd)
-			close(mt.ioctlfd);
+			ops->close(ap->logopt, mt.ioctlfd);
 		info(ap->logopt, "mounted %s", mt.name);
 	} else {
-		send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
-		close(mt.ioctlfd);
+		/* TODO: get mount return status from lookup_nss_mount */
+		ops->send_fail(ap->logopt,
+			       mt.ioctlfd, mt.wait_queue_token, -ENOENT);
+		ops->close(ap->logopt, mt.ioctlfd);
 		info(ap->logopt, "failed to mount %s", mt.name);
 	}
 	pthread_setcancelstate(state, NULL);
@@ -1337,6 +1289,7 @@ static void *do_mount_direct(void *arg)
 
 int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct map_source *map;
 	struct mapent_cache *mc = NULL;
 	struct mapent *me = NULL;
@@ -1346,7 +1299,7 @@ int handle_packet_missing_direct(struct 
 	int status = 0;
 	struct timespec wait;
 	struct timeval now;
-	int ioctlfd, cl_flags, state;
+	int ioctlfd, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
@@ -1396,7 +1349,7 @@ int handle_packet_missing_direct(struct 
 		ioctlfd = me->ioctlfd;
 		me->ioctlfd = -1;
 	} else
-		ioctlfd = open(me->key, O_RDONLY);
+		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
 
 	if (ioctlfd == -1) {
 		cache_unlock(mc);
@@ -1407,18 +1360,14 @@ int handle_packet_missing_direct(struct 
 		return 1;
 	}
 
-	if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
-		cl_flags |= FD_CLOEXEC;
-		fcntl(ioctlfd, F_SETFD, cl_flags);
-	}
-
 	debug(ap->logopt, "token %ld, name %s, request pid %u",
 		  (unsigned long) pkt->wait_queue_token, me->key, pkt->pid);
 
 	/* Ignore packet if we're trying to shut down */
 	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
-		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
-		close(ioctlfd);
+		ops->send_fail(ap->logopt,
+			       ioctlfd, pkt->wait_queue_token, -ENOENT);
+		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
@@ -1429,8 +1378,9 @@ int handle_packet_missing_direct(struct 
 	if (!mt) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		error(ap->logopt, "malloc: %s", estr);
-		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
-		close(ioctlfd);
+		ops->send_fail(ap->logopt,
+			       ioctlfd, pkt->wait_queue_token, -ENOMEM);
+		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
@@ -1463,8 +1413,9 @@ int handle_packet_missing_direct(struct 
 	status = pthread_create(&thid, &th_attr_detached, do_mount_direct, mt);
 	if (status) {
 		error(ap->logopt, "missing mount thread create failed");
-		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
-		close(ioctlfd);
+		ops->send_fail(ap->logopt,
+			       ioctlfd, pkt->wait_queue_token, -status);
+		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		mount_mutex_unlock(mt);
--- autofs-5.0.1.orig/daemon/indirect.c
+++ autofs-5.0.1/daemon/indirect.c
@@ -86,19 +86,20 @@ static int unlink_mount_tree(struct auto
 
 static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	time_t timeout = ap->exp_timeout;
 	char *options = NULL;
 	const char *type, *map_name = NULL;
 	struct stat st;
 	struct mnt_list *mnts;
-	int cl_flags, ret;
+	int ret;
 
 	mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
 	if (mnts) {
 		ret = unlink_mount_tree(ap, mnts);
 		free_mnt_list(mnts);
 		if (!ret) {
-			debug(ap->logopt,
+			error(ap->logopt,
 			      "already mounted as other than autofs "
 			      "or failed to unlink entry in tree");
 			goto out_err;
@@ -106,8 +107,10 @@ static int do_mount_autofs_indirect(stru
 	}
 
 	options = make_options_string(ap->path, ap->kpipefd, NULL);
-	if (!options)
+	if (!options) {
+		error(ap->logopt, "options string error");
 		goto out_err;
+	}
 
 	/* In case the directory doesn't exist, try to mkdir it */
 	if (mkdir_path(root, 0555) < 0) {
@@ -144,24 +147,25 @@ static int do_mount_autofs_indirect(stru
 
 	free(options);
 
+	ret = stat(root, &st);
+	if (ret == -1) {
+		crit(ap->logopt,
+		     "failed to stat mount for autofs path %s", ap->path);
+		goto out_umount;
+	}
+
 	options = NULL;
 
-	/* Root directory for ioctl()'s */
-	ap->ioctlfd = open(root, O_RDONLY);
-	if (ap->ioctlfd < 0) {
+	if (ops->open(ap->logopt, &ap->ioctlfd, st.st_dev, root)) {
 		crit(ap->logopt,
 		     "failed to create ioctl fd for autofs path %s", ap->path);
 		goto out_umount;
 	}
 
-	if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
-		cl_flags |= FD_CLOEXEC;
-		fcntl(ap->ioctlfd, F_SETFD, cl_flags);
-	}
-
+	ap->dev = st.st_dev;	/* Device number for mount point checks */
 	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
 
-	ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+	ops->timeout(ap->logopt, ap->ioctlfd, &timeout);
 
 	if (ap->exp_timeout)
 		info(ap->logopt,
@@ -174,9 +178,6 @@ static int do_mount_autofs_indirect(stru
 		    "mounted indirect mount for %s with timeouts disabled",
 		    ap->path);
 
-	fstat(ap->ioctlfd, &st);
-	ap->dev = st.st_dev;	/* Device number for mount point checks */
-
 	return 0;
 
 out_umount:
@@ -259,9 +260,11 @@ void close_mount_fds(struct autofs_point
 
 int umount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
 	char mountpoint[PATH_MAX + 1];
-	int ret, rv, retries;
+	int rv, retries;
+	unsigned int unused;
 
 	if (root)
 		strcpy(mountpoint, root);
@@ -269,12 +272,12 @@ int umount_autofs_indirect(struct autofs
 		strcpy(mountpoint, ap->path);
 
 	/* If we are trying to shutdown make sure we can umount */
-	rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
+	rv = ops->askumount(ap->logopt, ap->ioctlfd, &unused);
 	if (rv == -1) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		logerr("ioctl failed: %s", estr);
 		return 1;
-	} else if (!ret) {
+	} else if (!unused) {
 #if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN)
 		if (!ap->shutdown)
 			return 1;
@@ -285,9 +288,9 @@ int umount_autofs_indirect(struct autofs
 	}
 
 	if (ap->shutdown)
-		ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+		ops->catatonic(ap->logopt, ap->ioctlfd);
 
-	close(ap->ioctlfd);
+	ops->close(ap->logopt, ap->ioctlfd);
 	ap->ioctlfd = -1;
 	sched_yield();
 
@@ -315,7 +318,6 @@ int umount_autofs_indirect(struct autofs
 				close_mount_fds(ap);
 				goto force_umount;
 			} else {
-				int cl_flags;
 				/*
 				 * If the umount returns EBUSY there may be
 				 * a mount request in progress so we need to
@@ -329,7 +331,8 @@ int umount_autofs_indirect(struct autofs
 					return 0;
 				}
 #endif
-				ap->ioctlfd = open(mountpoint, O_RDONLY);
+				ops->open(ap->logopt,
+					  &ap->ioctlfd, ap->dev, mountpoint);
 				if (ap->ioctlfd < 0) {
 					warn(ap->logopt,
 					     "could not recover autofs path %s",
@@ -337,11 +340,6 @@ int umount_autofs_indirect(struct autofs
 					close_mount_fds(ap);
 					return 0;
 				}
-
-				if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
-					cl_flags |= FD_CLOEXEC;
-					fcntl(ap->ioctlfd, F_SETFD, cl_flags);
-				}
 			}
 			break;
 		case ENOTDIR:
@@ -374,36 +372,6 @@ force_umount:
 	return rv;
 }
 
-static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when)
-{
-	int ret, retries = EXPIRE_RETRIES;
-
-	while (retries--) {
-		struct timespec tm = {0, 100000000};
-
-		/* Ggenerate expire message for the mount. */
-		ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
-		if (ret == -1) {
-			/* Mount has gone away */
-			if (errno == EBADF || errno == EINVAL)
-				return 1;
-
-			/* Other than need to wait for the kernel ? */
-			if (errno != EAGAIN)
-				return 0;
-		}
-
-		nanosleep(&tm, NULL);
-	}
-
-	if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
-		if (!ret)
-			return 0;
-	}
-
-	return 1;
-}
-
 static void mnts_cleanup(void *arg)
 {
 	struct mnt_list *mnts = (struct mnt_list *) arg;
@@ -413,6 +381,7 @@ static void mnts_cleanup(void *arg)
 
 void *expire_proc_indirect(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct autofs_point *ap;
 	struct mapent *me = NULL;
 	struct mnt_list *mnts = NULL, *next;
@@ -503,8 +472,8 @@ void *expire_proc_indirect(void *arg)
 		debug(ap->logopt, "expire %s", next->path);
 
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-		ret = expire_indirect(ap, ioctlfd, next->path, now);
-		if (!ret)
+		ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+		if (ret)
 			left++;
 		pthread_setcancelstate(cur_state, NULL);
 	}
@@ -519,8 +488,8 @@ void *expire_proc_indirect(void *arg)
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 		retries = (count_mounts(ap->logopt, ap->path, ap->dev) + 1);
 		while (retries--) {
-			ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
-			if (!ret)
+			ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, now);
+			if (ret)
 				left++;
 		}
 		pthread_setcancelstate(cur_state, NULL);
@@ -544,8 +513,8 @@ void *expire_proc_indirect(void *arg)
 	pthread_cleanup_pop(1);
 
 	if (submnts)
-		debug(ap->logopt,
-		      "%d submounts remaining in %s", submnts, ap->path);
+		info(ap->logopt,
+		     "%d submounts remaining in %s", submnts, ap->path);
 
 	/* 
 	 * EXPIRE_MULTI is synchronous, so we can be sure (famous last
@@ -576,8 +545,11 @@ static void pending_cond_destroy(void *a
 
 static void expire_send_fail(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt = arg;
-	send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+	struct autofs_point *ap = mt->ap;
+	ops->send_fail(ap->logopt,
+		       ap->ioctlfd, mt->wait_queue_token, -ENOENT);
 }
 
 static void free_pending_args(void *arg)
@@ -595,6 +567,7 @@ static void expire_mutex_unlock(void *ar
 
 static void *do_expire_indirect(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt;
 	struct autofs_point *ap;
 	int status, state;
@@ -621,9 +594,11 @@ static void *do_expire_indirect(void *ar
 	status = do_expire(mt->ap, mt->name, mt->len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status)
-		send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, mt->wait_queue_token, -status);
 	else
-		send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+		ops->send_ready(ap->logopt,
+				ap->ioctlfd, mt->wait_queue_token);
 	pthread_setcancelstate(state, NULL);
 
 	pthread_cleanup_pop(0);
@@ -635,6 +610,7 @@ static void *do_expire_indirect(void *ar
 
 int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_indirect_t *pkt)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt;
 	char buf[MAX_ERR_BUF];
 	pthread_t thid;
@@ -651,7 +627,8 @@ int handle_packet_expire_indirect(struct
 	if (!mt) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		logerr("malloc: %s", estr);
-		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -673,7 +650,8 @@ int handle_packet_expire_indirect(struct
 	status = pthread_create(&thid, &th_attr_detached, do_expire_indirect, mt);
 	if (status) {
 		error(ap->logopt, "expire thread create failed");
-		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, pkt->wait_queue_token, -status);
 		expire_mutex_unlock(NULL);
 		pending_cond_destroy(mt);
 		free_pending_args(mt);
@@ -701,8 +679,11 @@ int handle_packet_expire_indirect(struct
 
 static void mount_send_fail(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *mt = arg;
-	send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+	struct autofs_point *ap = mt->ap;
+	ops->send_fail(ap->logopt,
+		       ap->ioctlfd, mt->wait_queue_token, -ENOENT);
 }
 
 static void pending_mutex_destroy(void *arg)
@@ -723,6 +704,7 @@ static void mount_mutex_unlock(void *arg
 
 static void *do_mount_indirect(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	struct pending_args *args, mt;
 	struct autofs_point *ap;
 	char buf[PATH_MAX + 1];
@@ -774,10 +756,13 @@ static void *do_mount_indirect(void *arg
 	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status) {
-		send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token);
+		ops->send_ready(ap->logopt,
+				ap->ioctlfd, mt.wait_queue_token);
 		info(ap->logopt, "mounted %s", buf);
 	} else {
-		send_fail(ap->logopt, ap->ioctlfd, mt.wait_queue_token);
+		/* TODO: get mount return status from lookup_nss_mount */
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, mt.wait_queue_token, -ENOENT);
 		info(ap->logopt, "failed to mount %s", buf);
 	}
 	pthread_setcancelstate(state, NULL);
@@ -789,6 +774,7 @@ static void *do_mount_indirect(void *arg
 
 int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	pthread_t thid;
 	char buf[MAX_ERR_BUF];
 	struct pending_args *mt;
@@ -803,7 +789,8 @@ int handle_packet_missing_indirect(struc
 
 	/* Ignore packet if we're trying to shut down */
 	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
-		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, pkt->wait_queue_token, -ENOENT);
 		pthread_setcancelstate(state, NULL);
 		return 0;
 	}
@@ -812,7 +799,8 @@ int handle_packet_missing_indirect(struc
 	if (!mt) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		logerr("malloc: %s", estr);
-		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -842,7 +830,8 @@ int handle_packet_missing_indirect(struc
 	status = pthread_create(&thid, &th_attr_detached, do_mount_indirect, mt);
 	if (status) {
 		error(ap->logopt, "expire thread create failed");
-		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+		ops->send_fail(ap->logopt,
+			       ap->ioctlfd, pkt->wait_queue_token, -status);
 		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
 		pending_mutex_destroy(mt);
--- autofs-5.0.1.orig/daemon/lookup.c
+++ autofs-5.0.1/daemon/lookup.c
@@ -1193,7 +1193,8 @@ int lookup_source_close_ioctlfd(struct a
 		me = cache_lookup_distinct(mc, key);
 		if (me) {
 			if (me->ioctlfd != -1) {
-				close(me->ioctlfd);
+				struct ioctl_ops *ops = get_ioctl_ops();
+				ops->close(ap->logopt, me->ioctlfd);
 				me->ioctlfd = -1;
 			}
 			cache_unlock(mc);
--- autofs-5.0.1.orig/daemon/state.c
+++ autofs-5.0.1/daemon/state.c
@@ -94,6 +94,7 @@ void nextstate(int statefd, enum states 
  */
 void expire_cleanup(void *arg)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	pthread_t thid = pthread_self();
 	struct expire_args *ec;
 	struct autofs_point *ap;
@@ -112,7 +113,8 @@ void expire_cleanup(void *arg)
 
 	/* Check to see if expire process finished */
 	if (thid == ap->exp_thread) {
-		int rv, idle;
+		unsigned int idle;
+		int rv;
 
 		ap->exp_thread = 0;
 
@@ -134,7 +136,7 @@ void expire_cleanup(void *arg)
 			 * allowing it to shutdown.
 			 */
 			if (ap->submount && !success) {
-				rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle);
+				rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
 				if (!rv && idle && ap->submount > 1) {
 					next = ST_SHUTDOWN_PENDING;
 					break;
@@ -159,7 +161,7 @@ void expire_cleanup(void *arg)
 			 * shutdown return to ready state unless we have
 			 * been signaled to shutdown.
 			 */
-			rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle);
+			rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
 			if (!idle && !ap->shutdown) {
 				next = ST_READY;
 				if (!ap->submount)
--- autofs-5.0.1.orig/include/automount.h
+++ autofs-5.0.1/include/automount.h
@@ -30,6 +30,7 @@
 #include "rpc_subs.h"
 #include "mounts.h"
 #include "parse_subs.h"
+#include "dev-ioctl-lib.h"
 
 #ifdef WITH_DMALLOC
 #include <dmalloc.h>
@@ -422,8 +423,6 @@ struct autofs_point {
 
 void *handle_mounts(void *arg);
 int umount_multi(struct autofs_point *ap, const char *path, int incl);
-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
 int do_expire(struct autofs_point *ap, const char *name, int namelen);
 void *expire_proc_indirect(void *);
 void *expire_proc_direct(void *);
--- /dev/null
+++ autofs-5.0.1/include/dev-ioctl-lib.h
@@ -0,0 +1,63 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *  dev-ioctl-lib.h - autofs device control.
+ *
+ *   Copyright 2008 Red Hat, Inc. All rights reserved.
+ *   Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef AUTOFS_DEV_IOCTL_LIB_H
+#define AUTOFS_DEV_IOCTL_LIB_H
+
+#include <sys/types.h>
+#include "linux/auto_dev-ioctl.h"
+
+#define CONTROL_DEVICE  "/dev/autofs"
+
+#define DEV_IOCTL_IS_MOUNTED	0x0001
+#define DEV_IOCTL_IS_AUTOFS	0x0002
+#define DEV_IOCTL_IS_OTHER	0x0004
+
+struct ioctl_ctl {
+	int devfd;
+	struct ioctl_ops *ops;
+};
+
+struct ioctl_ops {
+	int (*version)(unsigned int, int, struct autofs_dev_ioctl *);
+	int (*protover)(unsigned int, int, unsigned int *);
+	int (*protosubver)(unsigned int, int, unsigned int *);
+	int (*mount_device)(unsigned int, const char *, unsigned int, dev_t *);
+	int (*open)(unsigned int, int *, dev_t, const char *);
+	int (*close)(unsigned int, int);
+	int (*send_ready)(unsigned int, int, unsigned int);
+	int (*send_fail)(unsigned int, int, unsigned int, int);
+	int (*setpipefd)(unsigned int, int, int);
+	int (*catatonic)(unsigned int, int);
+	int (*timeout)(unsigned int, int, time_t *);
+	int (*requestor)(unsigned int, int, const char *, uid_t *, gid_t *);
+	int (*expire)(unsigned int, int, const char *, unsigned int);
+	int (*askumount)(unsigned int, int, unsigned int *);
+	int (*ismountpoint)(unsigned int, int, const char *, unsigned int *);
+};
+
+void init_ioctl_ctl(void);
+void close_ioctl_ctl(void);
+struct ioctl_ops *get_ioctl_ops(void);
+struct autofs_dev_ioctl *alloc_ioctl_ctl_open(const char *, unsigned int);
+void free_ioctl_ctl_open(struct autofs_dev_ioctl *);
+
+#endif
+
--- /dev/null
+++ autofs-5.0.1/include/linux/auto_dev-ioctl.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#ifndef _LINUX_AUTO_DEV_IOCTL_H
+#define _LINUX_AUTO_DEV_IOCTL_H
+
+#include <linux/types.h>
+
+#define AUTOFS_DEVICE_NAME		"autofs"
+
+#define AUTOFS_DEV_IOCTL_VERSION_MAJOR	1
+#define AUTOFS_DEV_IOCTL_VERSION_MINOR	0
+
+#define AUTOFS_DEVID_LEN		16
+
+#define AUTOFS_DEV_IOCTL_IOC_FIRST	(AUTOFS_DEV_IOCTL_VERSION)
+#define AUTOFS_DEV_IOCTL_IOC_COUNT	(AUTOFS_IOC_COUNT - 11)
+
+#define AUTOFS_DEV_IOCTL_SIZE		sizeof(struct autofs_dev_ioctl)
+
+/*
+ * An ioctl interface for autofs mount point control.
+ */
+
+struct args_protover {
+	 __u32   version;
+};
+
+struct args_protosubver {
+	__u32   sub_version;
+};
+
+struct args_openmount {
+	__u32   devid;
+};
+
+struct args_ready {
+	__u32   token;
+};
+
+struct args_fail {
+	__u32   token;
+	__s32   status;
+};
+
+struct args_setpipefd {
+	__s32   pipefd;
+};
+
+struct args_timeout {
+	__u64   timeout;
+};
+
+struct args_requester {
+	__u32   uid;
+	__u32   gid;
+};
+
+struct args_expire {
+	__u32   how;
+};
+
+struct args_askumount {
+	 __u32   may_umount;
+};
+
+struct args_ismountpoint {
+	union {
+		struct args_in {
+			__u32   type;
+		} in;
+		struct args_out {
+			__u32   devid;
+			__u32   magic;
+		} out;
+	};
+};
+
+/*
+ * All the ioctls use this structure.
+ * When sending a path size must account for the total length
+ * of the chunk of memory otherwise is is the size of the
+ * structure.
+ */
+
+struct autofs_dev_ioctl {
+	__u32 ver_major;
+	__u32 ver_minor;
+	__u32 size;		/* total size of data passed in
+				 * including this struct */
+	__s32 ioctlfd;		/* automount command fd */
+
+	/* Command parameters */
+
+	union {
+		struct args_protover            protover;
+		struct args_protosubver         protosubver;
+		struct args_openmount           openmount;
+		struct args_ready               ready;
+		struct args_fail                fail;
+		struct args_setpipefd           setpipefd;
+		struct args_timeout             timeout;
+		struct args_requester           requester;
+		struct args_expire              expire;
+		struct args_askumount           askumount;
+		struct args_ismountpoint        ismountpoint;
+	};
+
+	char path[0];
+};
+
+static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+{
+	in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+	in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+	in->size = sizeof(struct autofs_dev_ioctl);
+	in->ioctlfd = -1;
+	return;
+}
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to autofs-dev-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Get various version info */
+	AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
+	AUTOFS_DEV_IOCTL_PROTOVER_CMD,
+	AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
+
+	/* Open mount ioctl fd */
+	AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
+
+	/* Close mount ioctl fd */
+	AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
+
+	/* Mount/expire status returns */
+	AUTOFS_DEV_IOCTL_READY_CMD,
+	AUTOFS_DEV_IOCTL_FAIL_CMD,
+
+	/* Activate/deactivate autofs mount */
+	AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
+	AUTOFS_DEV_IOCTL_CATATONIC_CMD,
+
+	/* Expiry timeout */
+	AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
+
+	/* Get mount last requesting uid and gid */
+	AUTOFS_DEV_IOCTL_REQUESTER_CMD,
+
+	/* Check for eligible expire candidates */
+	AUTOFS_DEV_IOCTL_EXPIRE_CMD,
+
+	/* Request busy status */
+	AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
+
+	/* Check if path is a mountpoint */
+	AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
+};
+
+#define AUTOFS_IOCTL 0x93
+
+#define AUTOFS_DEV_IOCTL_VERSION \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOVER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOSUBVER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_OPENMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_READY \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_FAIL \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_SETPIPEFD \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CATATONIC \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_TIMEOUT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_REQUESTER \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_EXPIRE \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ASKUMOUNT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \
+	_IOWR(AUTOFS_IOCTL, \
+	      AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
+
+#endif	/* _LINUX_AUTO_DEV_IOCTL_H */
--- autofs-5.0.1.orig/include/linux/auto_fs4.h
+++ autofs-5.0.1/include/linux/auto_fs4.h
@@ -23,12 +23,17 @@
 #define AUTOFS_MIN_PROTO_VERSION	3
 #define AUTOFS_MAX_PROTO_VERSION	5
 
-#define AUTOFS_PROTO_SUBVERSION		0
+#define AUTOFS_PROTO_SUBVERSION		1
 
 /* Mask for expire behaviour */
 #define AUTOFS_EXP_IMMEDIATE		1
 #define AUTOFS_EXP_LEAVES		2
 
+#define AUTOFS_TYPE_ANY		 0x0000
+#define AUTOFS_TYPE_INDIRECT     0x0001
+#define AUTOFS_TYPE_DIRECT       0x0002
+#define AUTOFS_TYPE_OFFSET       0x0004
+
 /* Daemon notification packet types */
 enum autofs_notify {
 	NFY_NONE,
@@ -90,8 +95,6 @@ union autofs_packet_union {
 #define AUTOFS_IOC_EXPIRE_INDIRECT	AUTOFS_IOC_EXPIRE_MULTI
 #define AUTOFS_IOC_EXPIRE_DIRECT	AUTOFS_IOC_EXPIRE_MULTI
 #define AUTOFS_IOC_PROTOSUBVER		_IOR(0x93,0x67,int)
-#define AUTOFS_IOC_ASKREGHOST           _IOR(0x93,0x68,int)
-#define AUTOFS_IOC_TOGGLEREGHOST        _IOR(0x93,0x69,int)
 #define AUTOFS_IOC_ASKUMOUNT		_IOR(0x93,0x70,int)
 
 
--- autofs-5.0.1.orig/include/mounts.h
+++ autofs-5.0.1/include/mounts.h
@@ -16,10 +16,18 @@
 #ifndef MOUNTS_H
 #define MOUNTS_H
 
+#ifndef AUTOFS_TYPE_ANY
 #define AUTOFS_TYPE_ANY		0x0000
+#endif
+#ifndef AUTOFS_TYPE_INDIRECT
 #define AUTOFS_TYPE_INDIRECT	0x0001
+#endif
+#ifndef AUTOFS_TYPE_DIRECT
 #define AUTOFS_TYPE_DIRECT	0x0002
+#endif
+#ifndef AUTOFS_TYPE_OFFSET
 #define AUTOFS_TYPE_OFFSET	0x0004
+#endif
 
 #define MNTS_ALL	0x0001
 #define MNTS_REAL	0x0002
@@ -30,9 +38,9 @@
 #define REMOUNT_STAT_FAIL	0x0002
 #define REMOUNT_READ_MAP	0x0004
 
-extern const unsigned int indirect;
-extern const unsigned int direct;
-extern const unsigned int offset;
+extern const unsigned int t_indirect;
+extern const unsigned int t_direct;
+extern const unsigned int t_offset;
 
 struct mapent;
 
--- autofs-5.0.1.orig/lib/Makefile
+++ autofs-5.0.1/lib/Makefile
@@ -8,12 +8,13 @@ include ../Makefile.rules
 
 SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \
 	master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \
-	args.c alarm.c macros.c master.c defaults.c parse_subs.c
+	args.c alarm.c macros.c master.c defaults.c parse_subs.c \
+	dev-ioctl-lib.c
 RPCS = mount.h mount_clnt.c mount_xdr.c
 OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \
 	mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \
 	nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \
-	defaults.o parse_subs.o
+	defaults.o parse_subs.o dev-ioctl-lib.o
 
 YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \
 	  master_tok.c master_parse.tab.c master_parse.tab.h
--- /dev/null
+++ autofs-5.0.1/lib/dev-ioctl-lib.c
@@ -0,0 +1,788 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *  ctl-dev-lib.c - module for Linux automount mount table lookup functions
+ *
+ *  Copyright 2008 Red Hat, Inc. All rights reserved.
+ *  Copyright 2008 Ian Kent <raven@themaw.net> - All Rights Reserved
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *  USA; either version 2 of the License, or (at your option) any later
+ *  version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <sys/vfs.h>
+
+#include "automount.h"
+
+/* ioctld control function interface */
+static struct ioctl_ctl ctl = { -1, NULL };
+
+#ifndef AUTOFS_SUPER_MAGIC
+#define AUTOFS_SUPER_MAGIC      0x0187
+#endif
+
+/*
+ * Define functions for autofs ioctl control.
+ *
+ * We provide two interfaces. One which routes ioctls via a
+ * miscelaneous device node and can be used to obtain an ioctl
+ * file descriptor for autofs mounts that are covered by an
+ * active mount (eg. active direct or multi-mount offsets).
+ * The other provides the traditional autofs ioctl implementation.
+ *
+ * The miscielaneous device control functions are prefixed with
+ * dev_ctl_ and the traditional ones are prefixed with ioctl_.
+ */
+static int dev_ioctl_version(unsigned int, int, struct autofs_dev_ioctl *);
+static int dev_ioctl_protover(unsigned int, int, unsigned int *);
+static int dev_ioctl_protosubver(unsigned int, int, unsigned int *);
+static int dev_ioctl_mount_device(unsigned int, const char *, unsigned int, dev_t *);
+static int dev_ioctl_open(unsigned int, int *, dev_t, const char *);
+static int dev_ioctl_close(unsigned int, int);
+static int dev_ioctl_send_ready(unsigned int, int, unsigned int);
+static int dev_ioctl_send_fail(unsigned int, int, unsigned int, int);
+static int dev_ioctl_setpipefd(unsigned int, int, int);
+static int dev_ioctl_catatonic(unsigned int, int);
+static int dev_ioctl_timeout(unsigned int, int, time_t *);
+static int dev_ioctl_requestor(unsigned int, int, const char *, uid_t *, gid_t *);
+static int dev_ioctl_expire(unsigned int, int, const char *, unsigned int);
+static int dev_ioctl_askumount(unsigned int, int, unsigned int *);
+static int dev_ioctl_ismountpoint(unsigned int, int, const char *, unsigned int *);
+
+static int ioctl_protover(unsigned int, int, unsigned int *);
+static int ioctl_protosubver(unsigned int, int, unsigned int *);
+static int ioctl_mount_device(unsigned int, const char *, unsigned int, dev_t *);
+static int ioctl_open(unsigned int, int *, dev_t, const char *);
+static int ioctl_close(unsigned int, int);
+static int ioctl_send_ready(unsigned int, int, unsigned int);
+static int ioctl_send_fail(unsigned int, int, unsigned int, int);
+static int ioctl_catatonic(unsigned int, int);
+static int ioctl_timeout(unsigned int, int, time_t *);
+static int ioctl_expire(unsigned int, int, const char *, unsigned int);
+static int ioctl_askumount(unsigned int, int, unsigned int *);
+
+static struct ioctl_ops dev_ioctl_ops = {
+	.version	= dev_ioctl_version,
+	.protover	= dev_ioctl_protover,
+	.protosubver	= dev_ioctl_protosubver,
+	.mount_device	= dev_ioctl_mount_device,
+	.open		= dev_ioctl_open,
+	.close		= dev_ioctl_close,
+	.send_ready	= dev_ioctl_send_ready,
+	.send_fail	= dev_ioctl_send_fail,
+	.setpipefd	= dev_ioctl_setpipefd,
+	.catatonic	= dev_ioctl_catatonic,
+	.timeout	= dev_ioctl_timeout,
+	.requestor	= dev_ioctl_requestor,
+	.expire		= dev_ioctl_expire,
+	.askumount	= dev_ioctl_askumount,
+	.ismountpoint	= dev_ioctl_ismountpoint
+};
+
+static struct ioctl_ops ioctl_ops = {
+	.version	= NULL,
+	.protover	= ioctl_protover,
+	.protosubver	= ioctl_protosubver,
+	.mount_device	= ioctl_mount_device,
+	.open		= ioctl_open,
+	.close		= ioctl_close,
+	.send_ready	= ioctl_send_ready,
+	.send_fail	= ioctl_send_fail,
+	.setpipefd	= NULL,
+	.catatonic	= ioctl_catatonic,
+	.timeout	= ioctl_timeout,
+	.requestor	= NULL,
+	.expire		= ioctl_expire,
+	.askumount	= ioctl_askumount,
+	.ismountpoint	= NULL
+};
+
+/*
+ * Allocate the control struct that holds the misc device file
+ * descriptor and operation despatcher table.
+ */
+void init_ioctl_ctl(void)
+{
+	int devfd;
+
+	if (ctl.ops)
+		return;
+
+	devfd = open(CONTROL_DEVICE, O_RDONLY);
+	if (devfd == -1)
+		ctl.ops = &ioctl_ops;
+	else {
+		struct autofs_dev_ioctl param;
+
+		int cl_flags = fcntl(devfd, F_GETFD, 0);
+		if (cl_flags != -1) {
+			cl_flags |= FD_CLOEXEC;
+			fcntl(devfd, F_SETFD, cl_flags);
+		}
+		/*
+		 * Check compile version against kernel.
+		 * Selinux may allow us to open the device but not
+		 * actually allow us to do anything.
+		 */
+		init_autofs_dev_ioctl(&param);
+		if (ioctl(devfd, AUTOFS_DEV_IOCTL_VERSION, &param) == -1) {
+			close(devfd);
+			ctl.ops = &ioctl_ops;
+		} else {
+			ctl.devfd = devfd;
+			ctl.ops = &dev_ioctl_ops;
+		}
+	}
+	return;
+}
+
+void close_ioctl_ctl(void)
+{
+	if (ctl.devfd != -1) {
+		close(ctl.devfd);
+		ctl.devfd = -1;
+	}
+	ctl.ops = NULL;
+	return;
+}
+
+/* Return a pointer to the operations control struct */
+struct ioctl_ops *get_ioctl_ops(void)
+{
+	if (!ctl.ops)
+		init_ioctl_ctl();
+	return ctl.ops;
+}
+
+/* Get kenrel version of misc device code */
+static int dev_ioctl_version(unsigned int logopt,
+			     int ioctlfd, struct autofs_dev_ioctl *param)
+{
+	param->ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_VERSION, param) == -1)
+		return -1;
+
+	return 0;
+}
+
+/* Get major version of autofs kernel module mount protocol */
+static int dev_ioctl_protover(unsigned int logopt,
+			      int ioctlfd, unsigned int *major)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOVER, &param) == -1)
+		return -1;
+
+	*major = param.protover.version;
+
+	return 0;
+}
+
+static int ioctl_protover(unsigned int logopt,
+			  int ioctlfd, unsigned int *major)
+{
+	return ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, major);
+}
+
+/* Get minor version of autofs kernel module mount protocol */
+static int dev_ioctl_protosubver(unsigned int logopt,
+				 int ioctlfd, unsigned int *minor)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) == -1)
+		return -1;
+
+	*minor = param.protosubver.sub_version;
+
+	return 0;
+}
+
+static int ioctl_protosubver(unsigned int logopt,
+			     int ioctlfd, unsigned int *minor)
+{
+	return ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, minor);
+}
+
+/*
+ * Allocate a parameter struct for misc device ioctl used when
+ * opening an autofs mount point. Attach the path to the end
+ * of the struct. and lookup the device number if not given.
+ * Locating the device number relies on the mount option
+ * "dev=<device number>" being present in the autofs fs mount
+ * options.
+ */
+static struct autofs_dev_ioctl *alloc_dev_ioctl_open(const char *path, dev_t devid)
+{
+	struct autofs_dev_ioctl *ioctl;
+	size_t size, p_len;
+	dev_t devno = devid;
+
+	if (!path)
+		return NULL;
+
+	p_len = strlen(path);
+	size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
+	ioctl = malloc(size);
+	if (!ioctl) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	init_autofs_dev_ioctl(ioctl);
+	ioctl->size = size;
+	memcpy(ioctl->path, path, p_len);
+	ioctl->path[p_len] = '\0';
+	ioctl->openmount.devid = devno;
+
+	return ioctl;
+}
+
+static void free_dev_ioctl_open(struct autofs_dev_ioctl *ioctl)
+{
+	free(ioctl);
+	return;
+}
+
+/*
+ * Allocate a parameter struct for misc device ioctl which includes
+ * a path. This is used when getting the last mount requestor uid
+ * and gid and when checking if a path within the autofs filesystem
+ * is a mount point. We add the path to the end of the struct.
+ */
+static struct autofs_dev_ioctl *alloc_dev_ioctl_path(int ioctlfd, const char *path)
+{
+	struct autofs_dev_ioctl *ioctl;
+	size_t size, p_len;
+
+	if (!path)
+		return NULL;
+
+	p_len = strlen(path);
+	size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
+	ioctl = malloc(size);
+	if (!ioctl) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	init_autofs_dev_ioctl(ioctl);
+	ioctl->ioctlfd = ioctlfd;
+	ioctl->size = size;
+	memcpy(ioctl->path, path, p_len);
+	ioctl->path[p_len] = '\0';
+
+	return ioctl;
+}
+
+static void free_dev_ioctl_path(struct autofs_dev_ioctl *ioctl)
+{
+	free(ioctl);
+	return;
+}
+
+/*
+ * Find the device number of an autofs mount with given path and
+ * type (eg..AUTOFS_TYPE_DIRECT). The device number is used by
+ * the kernel to identify the autofs super block when searching
+ * for the mount.
+ */
+static int dev_ioctl_mount_device(unsigned int logopt, const char *path, unsigned int type, dev_t *devid)
+{
+	struct autofs_dev_ioctl *param;
+	int err;
+
+	if (!path) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	*devid = -1;
+
+	param = alloc_dev_ioctl_path(-1, path);
+	if (!param)
+		return -1;
+	param->ismountpoint.in.type = type;
+
+	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param);
+	if (err == -1) {
+		int save_errno = errno;
+		free_dev_ioctl_path(param);
+		errno = save_errno;
+		return -1;
+	}
+
+	if (err)
+		*devid = param->ismountpoint.out.devid;
+
+	free_dev_ioctl_path(param);
+
+	return err;
+}
+
+static int ioctl_mount_device(unsigned int logopt,
+			      const char *path, unsigned int type,
+			      dev_t *devid)
+{
+	return -1;
+}
+
+/* Get a file descriptor for control operations */
+static int dev_ioctl_open(unsigned int logopt,
+			  int *ioctlfd, dev_t devid, const char *path)
+{
+	struct autofs_dev_ioctl *param;
+
+	*ioctlfd = -1;
+
+	param = alloc_dev_ioctl_open(path, devid);
+	if (!param)
+		return -1;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) == -1) {
+		int save_errno = errno;
+		free_dev_ioctl_open(param);
+		errno = save_errno;
+		return -1;
+	}
+
+	*ioctlfd = param->ioctlfd;
+
+	free_dev_ioctl_open(param);
+
+	return 0;
+}
+
+static int ioctl_open(unsigned int logopt,
+		      int *ioctlfd, dev_t devid, const char *path)
+{
+	struct statfs sfs;
+	int save_errno, fd, cl_flags;
+
+	*ioctlfd = -1;
+
+	fd = open(path, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	cl_flags = fcntl(fd, F_GETFD, 0);
+	if (cl_flags != -1) {
+		cl_flags |= FD_CLOEXEC;
+		fcntl(fd, F_SETFD, cl_flags);
+	}
+
+	if (fstatfs(fd, &sfs) == -1) {
+		save_errno = errno;
+		goto err;
+	}
+
+	if (sfs.f_type != AUTOFS_SUPER_MAGIC) {
+		save_errno = ENOENT;
+		goto err;
+	}
+
+	*ioctlfd = fd;
+
+	return 0;
+err:
+	close(fd);
+	errno = save_errno;
+	return -1;
+}
+
+/* Close */
+static int dev_ioctl_close(unsigned int logopt, int ioctlfd)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CLOSEMOUNT, &param) == -1)
+		return -1;
+
+	return 0;
+}
+
+static int ioctl_close(unsigned int logopt, int ioctlfd)
+{
+	return close(ioctlfd);
+}
+
+/* Send ready status for given token */
+static int dev_ioctl_send_ready(unsigned int logopt,
+				int ioctlfd, unsigned int token)
+{
+	struct autofs_dev_ioctl param;
+
+	if (token == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	debug(logopt, "token = %d", token);
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+	param.ready.token = token;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_READY, &param) == -1) {
+		char *estr, buf[MAX_ERR_BUF];
+		int save_errno = errno;
+		estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		logerr("AUTOFS_DEV_IOCTL_READY: error %s", estr);
+		errno = save_errno;
+		return -1;
+	}
+	return 0;
+}
+
+static int ioctl_send_ready(unsigned int logopt,
+			    int ioctlfd, unsigned int token)
+{
+	if (token == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	debug(logopt, "token = %d", token);
+
+	if (ioctl(ioctlfd, AUTOFS_IOC_READY, token) == -1) {
+		char *estr, buf[MAX_ERR_BUF];
+		int save_errno = errno;
+		estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		logerr("AUTOFS_IOC_READY: error %s", estr);
+		errno = save_errno;
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Send ready status for given token.
+ *
+ * The device node ioctl implementation allows for sending a status
+ * of other than ENOENT, unlike the tradional interface.
+ */
+static int dev_ioctl_send_fail(unsigned int logopt,
+			       int ioctlfd, unsigned int token, int status)
+{
+	struct autofs_dev_ioctl param;
+
+	if (token == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	debug(logopt, "token = %d", token);
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+	param.fail.token = token;
+	param.fail.status = status;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_FAIL, &param) == -1) {
+		char *estr, buf[MAX_ERR_BUF];
+		int save_errno = errno;
+		estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		logerr("AUTOFS_DEV_IOCTL_FAIL: error %s", estr);
+		errno = save_errno;
+		return -1;
+	}
+	return 0;
+}
+
+static int ioctl_send_fail(unsigned int logopt,
+			   int ioctlfd, unsigned int token, int status)
+{
+	if (token == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	debug(logopt, "token = %d", token);
+
+	if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, token) == -1) {
+		char *estr, buf[MAX_ERR_BUF];
+		int save_errno = errno;
+		estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		logerr("AUTOFS_IOC_FAIL: error %s", estr);
+		errno = save_errno;
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Set the pipe fd for kernel communication.
+ *
+ * Normally this is set at mount using an option but if we
+ * are reconnecting to a busy mount then we need to use this
+ * to tell the autofs kernel module about the new pipe fd. In
+ * order to protect mounts against incorrectly setting the
+ * pipefd we also require that the autofs mount be catatonic.
+ *
+ * If successful this also sets the process group id used to
+ * identify the controlling process to the process group of
+ * the caller.
+ */
+static int dev_ioctl_setpipefd(unsigned int logopt, int ioctlfd, int pipefd)
+{
+	struct autofs_dev_ioctl param;
+
+	if (pipefd == -1) {
+		errno = EBADF;
+		return -1;
+	}
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+	param.setpipefd.pipefd = pipefd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_SETPIPEFD, &param) == -1)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Make the autofs mount point catatonic, no longer responsive to
+ * mount requests. Also closes the kernel pipe file descriptor.
+ */
+static int dev_ioctl_catatonic(unsigned int logopt, int ioctlfd)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CATATONIC, &param) == -1)
+		return -1;
+
+	return 0;
+}
+
+static int ioctl_catatonic(unsigned int logopt, int ioctlfd)
+{
+	return ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+}
+
+/* Set the autofs mount timeout */
+static int dev_ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+	param.timeout.timeout = *timeout;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) == -1)
+		return -1;
+
+	*timeout = param.timeout.timeout;
+
+	return 0;
+}
+
+static int ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout)
+{
+	return ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, timeout);
+}
+
+/*
+ * Get the uid and gid of the last request for the mountpoint, path.
+ *
+ * When reconstructing an autofs mount tree with active mounts
+ * we need to re-connect to mounts that may have used the original
+ * process uid and gid (or string variations of them) for mount
+ * lookups within the map entry.
+ */
+static int dev_ioctl_requestor(unsigned int logopt,
+			       int ioctlfd, const char *path,
+			       uid_t *uid, gid_t *gid)
+{
+	struct autofs_dev_ioctl *param;
+	int err;
+
+	if (!path)
+		errno = EINVAL;
+
+	*uid = -1;
+	*gid = -1;
+
+
+	param = alloc_dev_ioctl_path(ioctlfd, path);
+	if (!param)
+		return -1;
+
+	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_REQUESTER, param);
+	if (err == -1) {
+		int save_errno = errno;
+		free_dev_ioctl_open(param);
+		errno = save_errno;
+		return -1;
+	}
+
+	*uid = param->requester.uid;
+	*gid = param->requester.gid;
+
+	free_dev_ioctl_path(param);
+
+	return 0;
+}
+
+/*
+ * Call repeatedly until it returns EAGAIN, meaning there's nothing
+ * more that can be done.
+ */
+static int expire(unsigned int logopt,
+		  int cmd, int fd, int ioctlfd, const char *path, void *arg)
+{
+	int ret, retries = EXPIRE_RETRIES;
+	unsigned int may_umount;
+
+	while (retries--) {
+		struct timespec tm = {0, 100000000};
+
+		/* Ggenerate expire message for the mount. */
+		ret = ioctl(fd, cmd, arg);
+		if (ret == -1) {
+			/* Mount has gone away */
+			if (errno == EBADF || errno == EINVAL)
+				return 0;
+
+			/*
+			 * Other than EAGAIN is an expire error so continue.
+			 * Kernel will try the next mount for indirect maps
+			 * and the same mount again for direct maps, limited
+			 * by retries.
+			 */
+			if (errno == EAGAIN)
+				break;
+		}
+		nanosleep(&tm, NULL);
+	}
+
+	may_umount = 0;
+	if (ctl.ops->askumount(logopt, ioctlfd, &may_umount))
+		return -1;
+
+	if (!may_umount)
+		return 1;
+
+	return 0;
+}
+
+static int dev_ioctl_expire(unsigned int logopt,
+			    int ioctlfd, const char *path, unsigned int when)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+	param.expire.how = when;
+
+	return expire(logopt, AUTOFS_DEV_IOCTL_EXPIRE,
+		      ctl.devfd, ioctlfd, path, (void *) &param);
+}
+
+static int ioctl_expire(unsigned int logopt,
+		        int ioctlfd, const char *path, unsigned int when)
+{
+	return expire(logopt, AUTOFS_IOC_EXPIRE_MULTI,
+		      ioctlfd, ioctlfd, path, (void *) &when);
+}
+
+/* Check if autofs mount point is in use */
+static int dev_ioctl_askumount(unsigned int logopt,
+			       int ioctlfd, unsigned int *busy)
+{
+	struct autofs_dev_ioctl param;
+
+	init_autofs_dev_ioctl(&param);
+	param.ioctlfd = ioctlfd;
+
+	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ASKUMOUNT, &param) == -1)
+		return -1;
+
+	*busy = param.askumount.may_umount;
+
+	return 0;
+}
+
+static int ioctl_askumount(unsigned int logopt,
+			   int ioctlfd, unsigned int *busy)
+{
+	return ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, busy);
+}
+
+/*
+ * Check if the given path is a mountpoint.
+ *
+ * The path is considered a mountpoint if it is itself a mountpoint
+ * or contains a mount, such as a multi-mount without a root mount.
+ * In addition, if the path is itself a mountpoint we return whether
+ * the mounted file system is an autofs filesystem or other file
+ * system.
+ */
+static int dev_ioctl_ismountpoint(unsigned int logopt,
+				  int ioctlfd, const char *path,
+				  unsigned int *mountpoint)
+{
+	struct autofs_dev_ioctl *param;
+	int err;
+
+	*mountpoint = 0;
+
+	if (!path) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	param = alloc_dev_ioctl_path(ioctlfd, path);
+	if (!param)
+		return -1;
+	param->ismountpoint.in.type = AUTOFS_TYPE_ANY;
+
+	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param);
+	if (err == -1) {
+		int save_errno = errno;
+		free_dev_ioctl_path(param);
+		errno = save_errno;
+		return -1;
+	}
+
+	if (err) {
+		*mountpoint = DEV_IOCTL_IS_MOUNTED;
+
+		if (param->ismountpoint.out.magic == AUTOFS_SUPER_MAGIC)
+			*mountpoint |= DEV_IOCTL_IS_AUTOFS;
+		else
+			*mountpoint |= DEV_IOCTL_IS_OTHER;
+	}
+
+	free_dev_ioctl_path(param);
+
+	return 0;
+}
--- autofs-5.0.1.orig/lib/master_parse.y
+++ autofs-5.0.1/lib/master_parse.y
@@ -798,6 +798,7 @@ int master_parse_entry(const char *buffe
 			return 0;
 		}
 	} else {
+		struct ioctl_ops *ops = get_ioctl_ops();
 		struct autofs_point *ap = entry->ap;
 		time_t tout = timeout;
 
@@ -809,7 +810,7 @@ int master_parse_entry(const char *buffe
 			ap->exp_timeout = timeout;
 			ap->exp_runfreq = (ap->exp_timeout + CHECK_RATIO - 1) / CHECK_RATIO;
 			if (ap->ioctlfd != -1 && ap->type == LKP_INDIRECT)
-				ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
+				ops->timeout(ap->logopt, ap->ioctlfd, &tout);
 		}
 	}
 	entry->ap->random_selection = random_selection;
--- autofs-5.0.1.orig/lib/mounts.c
+++ autofs-5.0.1/lib/mounts.c
@@ -33,9 +33,9 @@
 #define MAX_OPTIONS_LEN		80
 #define MAX_MNT_NAME_LEN	30
 
-const unsigned int indirect = AUTOFS_TYPE_INDIRECT;
-const unsigned int direct = AUTOFS_TYPE_DIRECT;
-const unsigned int offset = AUTOFS_TYPE_OFFSET;
+const unsigned int t_indirect = AUTOFS_TYPE_INDIRECT;
+const unsigned int t_direct = AUTOFS_TYPE_DIRECT;
+const unsigned int t_offset = AUTOFS_TYPE_OFFSET;
 const unsigned int type_count = 3;
 
 static const char options_template[]       = "fd=%d,pgrp=%u,minproto=5,maxproto=%d";
@@ -47,10 +47,12 @@ static const char kver_options_template[
 
 unsigned int query_kproto_ver(void)
 {
+	struct ioctl_ops *ops = get_ioctl_ops();
 	char dir[] = "/tmp/autoXXXXXX", *t_dir;
 	char options[MAX_OPTIONS_LEN + 1];
 	pid_t pgrp = getpgrp();
 	int pipefd[2], ioctlfd, len;
+	struct stat st;
 
 	t_dir = mkdtemp(dir);
 	if (!t_dir)
@@ -79,7 +81,14 @@ unsigned int query_kproto_ver(void)
 
 	close(pipefd[1]);
 
-	ioctlfd = open(t_dir, O_RDONLY);
+	if (stat(t_dir, &st) == -1) {
+		umount(t_dir);
+		close(pipefd[0]);
+		rmdir(t_dir);
+		return 0;
+	}
+
+	ops->open(LOGOPT_NONE, &ioctlfd, st.st_dev, t_dir);
 	if (ioctlfd == -1) {
 		umount(t_dir);
 		close(pipefd[0]);
@@ -87,11 +96,11 @@ unsigned int query_kproto_ver(void)
 		return 0;
 	}
 
-	ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+	ops->catatonic(LOGOPT_NONE, ioctlfd);
 
 	/* If this ioctl() doesn't work, it is kernel version 2 */
-	if (ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, &kver.major) == -1) {
-		close(ioctlfd);
+	if (ops->protover(LOGOPT_NONE, ioctlfd, &kver.major)) {
+		ops->close(LOGOPT_NONE, ioctlfd);
 		umount(t_dir);
 		close(pipefd[0]);
 		rmdir(t_dir);
@@ -99,15 +108,15 @@ unsigned int query_kproto_ver(void)
 	}
 
 	/* If this ioctl() doesn't work, version is 4 or less */
-	if (ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, &kver.minor) == -1) {
-		close(ioctlfd);
+	if (ops->protosubver(LOGOPT_NONE, ioctlfd, &kver.minor)) {
+		ops->close(LOGOPT_NONE, ioctlfd);
 		umount(t_dir);
 		close(pipefd[0]);
 		rmdir(t_dir);
 		return 0;
 	}
 
-	close(ioctlfd);
+	ops->close(LOGOPT_NONE, ioctlfd);
 	umount(t_dir);
 	close(pipefd[0]);
 	rmdir(t_dir);
--- autofs-5.0.1.orig/modules/parse_sun.c
+++ autofs-5.0.1/modules/parse_sun.c
@@ -1003,6 +1003,7 @@ static void cleanup_multi_root(struct au
 	if (move == MOUNT_MOVE_OTHER)
 		spawn_umount(ap->logopt, root, NULL);
 	else {
+		struct ioctl_ops *ops = get_ioctl_ops();
 		struct autofs_point *submount;
 
 		mounts_mutex_lock(ap);
@@ -1019,7 +1020,7 @@ static void cleanup_multi_root(struct au
 		submount->parent->submnt_count--;
 		list_del_init(&submount->mounts);
 
-		ioctl(submount->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+		ops->catatonic(submount->logopt, submount->ioctlfd);
 
 		mounts_mutex_unlock(ap);
 
--- autofs-5.0.1.orig/redhat/autofs.init.in
+++ autofs-5.0.1/redhat/autofs.init.in
@@ -15,6 +15,7 @@
 DAEMON=@@sbindir@@/automount
 prog=`basename $DAEMON`
 MODULE="autofs4"
+DEVICE="autofs"
 initdir=@@initdir@@
 confdir=@@autofsconfdir@@
 
@@ -58,6 +59,22 @@ function start() {
 		echo
 		return $RETVAL
 	fi
+
+	# Check misc device
+	if [ -n "$USE_MISC_DEVICE" -a "x$USE_MISC_DEVICE" = "xyes" ]; then
+		sleep 1
+		if [ -e "/proc/misc" ]; then
+			MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc`
+			if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then
+				mknod -m 0600 /dev/$DEVICE c 10 $MINOR
+			fi
+		fi
+	else
+		if [ -c /dev/$DEVICE ]; then
+			rm /dev/$DEVICE
+		fi
+	fi
+
 	echo -n $"Starting $prog: "
 	$prog $OPTIONS 
 	RETVAL=$?
--- autofs-5.0.1.orig/redhat/autofs.sysconfig.in
+++ autofs-5.0.1/redhat/autofs.sysconfig.in
@@ -97,5 +97,10 @@ BROWSE_MODE="no"
 #
 # General global options
 #
+# If the kernel supports using the autofs miscellanous device
+# and you wish to use it you must set this configuration option
+# to "yes" otherwise it will not be used.
+#USE_MISC_DEVICE="no"
+#
 #OPTIONS=""
 #
--- autofs-5.0.1.orig/samples/autofs.conf.default.in
+++ autofs-5.0.1/samples/autofs.conf.default.in
@@ -97,5 +97,10 @@ BROWSE_MODE="no"
 #
 # General global options
 #
+# If the kernel supports using the autofs miscellanous device
+# and you wish to use it you must set this configuration option
+# to "yes" otherwise it will not be used.
+#USE_MISC_DEVICE="no"
+#
 #OPTIONS=""
 #
--- autofs-5.0.1.orig/samples/rc.autofs.in
+++ autofs-5.0.1/samples/rc.autofs.in
@@ -14,6 +14,7 @@
 DAEMON=@@sbindir@@/automount
 prog=`basename $DAEMON`
 MODULE="autofs4"
+DEVICE="autofs"
 confdir=@@autofsconfdir@@
 
 test -e $DAEMON || exit 0
@@ -49,6 +50,21 @@ function start() {
 		return 1
 	fi
 
+	# Check misc device
+	if [ -n "$USE_MISC_DEVICE" -a "x$USE_MISC_DEVICE" = "xyes" ]; then
+		sleep 1
+		if [ -e "/proc/misc" ]; then
+			MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc`
+			if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then
+				mknod -m 0600 /dev/$DEVICE c 10 $MINOR
+			fi
+		fi
+	else
+		if [ -c /dev/$DEVICE ]; then
+			rm /dev/$DEVICE
+		fi
+	fi
+
 	$prog $OPTIONS 
 	RETVAL=$?
 	if [ $RETVAL -eq 0 ] ; then