[Midnightbsd-cvs] src [10024] trunk/sys/fs/autofs: add autofs from freebsd

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun May 27 18:18:02 EDT 2018


Revision: 10024
          http://svnweb.midnightbsd.org/src/?rev=10024
Author:   laffer1
Date:     2018-05-27 18:18:02 -0400 (Sun, 27 May 2018)
Log Message:
-----------
add autofs from freebsd

Added Paths:
-----------
    trunk/sys/fs/autofs/
    trunk/sys/fs/autofs/autofs.c
    trunk/sys/fs/autofs/autofs.h
    trunk/sys/fs/autofs/autofs_ioctl.h
    trunk/sys/fs/autofs/autofs_vfsops.c
    trunk/sys/fs/autofs/autofs_vnops.c

Added: trunk/sys/fs/autofs/autofs.c
===================================================================
--- trunk/sys/fs/autofs/autofs.c	                        (rev 0)
+++ trunk/sys/fs/autofs/autofs.c	2018-05-27 22:18:02 UTC (rev 10024)
@@ -0,0 +1,701 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1995
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+ __FBSDID("$FreeBSD: stable/10/sys/fs/autofs/autofs.c 279749 2015-03-07 20:00:26Z trasz $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/ioccom.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/refcount.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/syscallsubr.h>
+#include <sys/taskqueue.h>
+#include <sys/vnode.h>
+#include <machine/atomic.h>
+#include <vm/uma.h>
+
+#include <fs/autofs/autofs.h>
+#include <fs/autofs/autofs_ioctl.h>
+
+MALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem");
+
+uma_zone_t autofs_request_zone;
+uma_zone_t autofs_node_zone;
+
+static int	autofs_open(struct cdev *dev, int flags, int fmt,
+		    struct thread *td);
+static int	autofs_close(struct cdev *dev, int flag, int fmt,
+		    struct thread *td);
+static int	autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
+		    int mode, struct thread *td);
+
+static struct cdevsw autofs_cdevsw = {
+     .d_version = D_VERSION,
+     .d_open   = autofs_open,
+     .d_close   = autofs_close,
+     .d_ioctl   = autofs_ioctl,
+     .d_name    = "autofs",
+};
+
+/*
+ * List of signals that can interrupt an autofs trigger.  Might be a good
+ * idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c.
+ */
+int autofs_sig_set[] = {
+	SIGINT,
+	SIGTERM,
+	SIGHUP,
+	SIGKILL,
+	SIGQUIT
+};
+
+struct autofs_softc	*autofs_softc;
+
+SYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD, 0, "Automounter filesystem");
+int autofs_debug = 1;
+TUNABLE_INT("vfs.autofs.debug", &autofs_debug);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN,
+    &autofs_debug, 1, "Enable debug messages");
+int autofs_mount_on_stat = 0;
+TUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN,
+    &autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint");
+int autofs_timeout = 30;
+TUNABLE_INT("vfs.autofs.timeout", &autofs_timeout);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN,
+    &autofs_timeout, 30, "Number of seconds to wait for automountd(8)");
+int autofs_cache = 600;
+TUNABLE_INT("vfs.autofs.cache", &autofs_cache);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN,
+    &autofs_cache, 600, "Number of seconds to wait before reinvoking "
+    "automountd(8) for any given file or directory");
+int autofs_retry_attempts = 3;
+TUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN,
+    &autofs_retry_attempts, 3, "Number of attempts before failing mount");
+int autofs_retry_delay = 1;
+TUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN,
+    &autofs_retry_delay, 1, "Number of seconds before retrying");
+int autofs_interruptible = 1;
+TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible);
+SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN,
+    &autofs_interruptible, 1, "Allow requests to be interrupted by signal");
+
+int
+autofs_init(struct vfsconf *vfsp)
+{
+	int error;
+
+	KASSERT(autofs_softc == NULL,
+	    ("softc %p, should be NULL", autofs_softc));
+
+	autofs_softc = malloc(sizeof(*autofs_softc), M_AUTOFS,
+	    M_WAITOK | M_ZERO);
+
+	autofs_request_zone = uma_zcreate("autofs_request",
+	    sizeof(struct autofs_request), NULL, NULL, NULL, NULL,
+	    UMA_ALIGN_PTR, 0);
+	autofs_node_zone = uma_zcreate("autofs_node",
+	    sizeof(struct autofs_node), NULL, NULL, NULL, NULL,
+	    UMA_ALIGN_PTR, 0);
+
+	TAILQ_INIT(&autofs_softc->sc_requests);
+	cv_init(&autofs_softc->sc_cv, "autofscv");
+	sx_init(&autofs_softc->sc_lock, "autofslk");
+
+	error = make_dev_p(MAKEDEV_CHECKNAME, &autofs_softc->sc_cdev,
+	    &autofs_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "autofs");
+	if (error != 0) {
+		AUTOFS_WARN("failed to create device node, error %d", error);
+		uma_zdestroy(autofs_request_zone);
+		uma_zdestroy(autofs_node_zone);
+		free(autofs_softc, M_AUTOFS);
+
+		return (error);
+	}
+	autofs_softc->sc_cdev->si_drv1 = autofs_softc;
+
+	return (0);
+}
+
+int
+autofs_uninit(struct vfsconf *vfsp)
+{
+
+	sx_xlock(&autofs_softc->sc_lock);
+	if (autofs_softc->sc_dev_opened) {
+		sx_xunlock(&autofs_softc->sc_lock);
+		return (EBUSY);
+	}
+	if (autofs_softc->sc_cdev != NULL)
+		destroy_dev(autofs_softc->sc_cdev);
+
+	uma_zdestroy(autofs_request_zone);
+	uma_zdestroy(autofs_node_zone);
+
+	sx_xunlock(&autofs_softc->sc_lock);
+	/*
+	 * XXX: Race with open?
+	 */
+	free(autofs_softc, M_AUTOFS);
+
+	return (0);
+}
+
+bool
+autofs_ignore_thread(const struct thread *td)
+{
+	struct proc *p;
+
+	p = td->td_proc;
+
+	if (autofs_softc->sc_dev_opened == false)
+		return (false);
+
+	PROC_LOCK(p);
+	if (p->p_session->s_sid == autofs_softc->sc_dev_sid) {
+		PROC_UNLOCK(p);
+		return (true);
+	}
+	PROC_UNLOCK(p);
+
+	return (false);
+}
+
+static char *
+autofs_path(struct autofs_node *anp)
+{
+	struct autofs_mount *amp;
+	char *path, *tmp;
+
+	amp = anp->an_mount;
+
+	path = strdup("", M_AUTOFS);
+	for (; anp->an_parent != NULL; anp = anp->an_parent) {
+		tmp = malloc(strlen(anp->an_name) + strlen(path) + 2,
+		    M_AUTOFS, M_WAITOK);
+		strcpy(tmp, anp->an_name);
+		strcat(tmp, "/");
+		strcat(tmp, path);
+		free(path, M_AUTOFS);
+		path = tmp;
+	}
+
+	tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2,
+	    M_AUTOFS, M_WAITOK);
+	strcpy(tmp, amp->am_mountpoint);
+	strcat(tmp, "/");
+	strcat(tmp, path);
+	free(path, M_AUTOFS);
+	path = tmp;
+
+	return (path);
+}
+
+static void
+autofs_task(void *context, int pending)
+{
+	struct autofs_request *ar;
+
+	ar = context;
+
+	sx_xlock(&autofs_softc->sc_lock);
+	AUTOFS_WARN("request %d for %s timed out after %d seconds",
+	    ar->ar_id, ar->ar_path, autofs_timeout);
+	/*
+	 * XXX: EIO perhaps?
+	 */
+	ar->ar_error = ETIMEDOUT;
+	ar->ar_wildcards = true;
+	ar->ar_done = true;
+	ar->ar_in_progress = false;
+	cv_broadcast(&autofs_softc->sc_cv);
+	sx_xunlock(&autofs_softc->sc_lock);
+}
+
+bool
+autofs_cached(struct autofs_node *anp, const char *component, int componentlen)
+{
+	int error;
+	struct autofs_mount *amp;
+
+	amp = anp->an_mount;
+
+	AUTOFS_ASSERT_UNLOCKED(amp);
+
+	/*
+	 * For root node we need to request automountd(8) assistance even
+	 * if the node is marked as cached, but the requested top-level
+	 * directory does not exist.  This is necessary for wildcard indirect
+	 * map keys to work.  We don't do this if we know that there are
+	 * no wildcards.
+	 */
+	if (anp->an_parent == NULL && componentlen != 0 && anp->an_wildcards) {
+		AUTOFS_SLOCK(amp);
+		error = autofs_node_find(anp, component, componentlen, NULL);
+		AUTOFS_SUNLOCK(amp);
+		if (error != 0)
+			return (false);
+	}
+
+	return (anp->an_cached);
+}
+
+static void
+autofs_cache_callout(void *context)
+{
+	struct autofs_node *anp;
+
+	anp = context;
+	anp->an_cached = false;
+}
+
+void
+autofs_flush(struct autofs_mount *amp)
+{
+
+	/*
+	 * XXX: This will do for now, but ideally we should iterate
+	 * 	over all the nodes.
+	 */
+	amp->am_root->an_cached = false;
+	AUTOFS_DEBUG("%s flushed", amp->am_mountpoint);
+}
+
+/*
+ * The set/restore sigmask functions are used to (temporarily) overwrite
+ * the thread td_sigmask during triggering.
+ */
+static void
+autofs_set_sigmask(sigset_t *oldset)
+{
+	sigset_t newset;
+	int i;
+
+	SIGFILLSET(newset);
+	/* Remove the autofs set of signals from newset */
+	PROC_LOCK(curproc);
+	mtx_lock(&curproc->p_sigacts->ps_mtx);
+	for (i = 0 ; i < sizeof(autofs_sig_set)/sizeof(int) ; i++) {
+		/*
+		 * But make sure we leave the ones already masked
+		 * by the process, i.e. remove the signal from the
+		 * temporary signalmask only if it wasn't already
+		 * in p_sigmask.
+		 */
+		if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) &&
+		    !SIGISMEMBER(curproc->p_sigacts->ps_sigignore,
+		    autofs_sig_set[i])) {
+			SIGDELSET(newset, autofs_sig_set[i]);
+		}
+	}
+	mtx_unlock(&curproc->p_sigacts->ps_mtx);
+	kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset,
+	    SIGPROCMASK_PROC_LOCKED);
+	PROC_UNLOCK(curproc);
+}
+
+static void
+autofs_restore_sigmask(sigset_t *set)
+{
+
+	kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0);
+}
+
+static int
+autofs_trigger_one(struct autofs_node *anp,
+    const char *component, int componentlen)
+{
+	sigset_t oldset;
+	struct autofs_mount *amp;
+	struct autofs_node *firstanp;
+	struct autofs_request *ar;
+	char *key, *path;
+	int error = 0, request_error, last;
+	bool wildcards;
+
+	amp = anp->an_mount;
+
+	sx_assert(&autofs_softc->sc_lock, SA_XLOCKED);
+
+	if (anp->an_parent == NULL) {
+		key = strndup(component, componentlen, M_AUTOFS);
+	} else {
+		for (firstanp = anp; firstanp->an_parent->an_parent != NULL;
+		    firstanp = firstanp->an_parent)
+			continue;
+		key = strdup(firstanp->an_name, M_AUTOFS);
+	}
+
+	path = autofs_path(anp);
+
+	TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
+		if (strcmp(ar->ar_path, path) != 0)
+			continue;
+		if (strcmp(ar->ar_key, key) != 0)
+			continue;
+
+		KASSERT(strcmp(ar->ar_from, amp->am_from) == 0,
+		    ("from changed; %s != %s", ar->ar_from, amp->am_from));
+		KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0,
+		    ("prefix changed; %s != %s",
+		     ar->ar_prefix, amp->am_prefix));
+		KASSERT(strcmp(ar->ar_options, amp->am_options) == 0,
+		    ("options changed; %s != %s",
+		     ar->ar_options, amp->am_options));
+
+		break;
+	}
+
+	if (ar != NULL) {
+		refcount_acquire(&ar->ar_refcount);
+	} else {
+		ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO);
+		ar->ar_mount = amp;
+
+		ar->ar_id =
+		    atomic_fetchadd_int(&autofs_softc->sc_last_request_id, 1);
+		strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from));
+		strlcpy(ar->ar_path, path, sizeof(ar->ar_path));
+		strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix));
+		strlcpy(ar->ar_key, key, sizeof(ar->ar_key));
+		strlcpy(ar->ar_options,
+		    amp->am_options, sizeof(ar->ar_options));
+
+		TIMEOUT_TASK_INIT(taskqueue_thread, &ar->ar_task, 0,
+		    autofs_task, ar);
+		error = taskqueue_enqueue_timeout(taskqueue_thread,
+		    &ar->ar_task, autofs_timeout * hz);
+		if (error != 0) {
+			AUTOFS_WARN("taskqueue_enqueue_timeout() failed "
+			    "with error %d", error);
+		}
+		refcount_init(&ar->ar_refcount, 1);
+		TAILQ_INSERT_TAIL(&autofs_softc->sc_requests, ar, ar_next);
+	}
+
+	cv_broadcast(&autofs_softc->sc_cv);
+	while (ar->ar_done == false) {
+		if (autofs_interruptible != 0) {
+			autofs_set_sigmask(&oldset);
+			error = cv_wait_sig(&autofs_softc->sc_cv,
+			    &autofs_softc->sc_lock);
+			autofs_restore_sigmask(&oldset);
+			if (error != 0) {
+				AUTOFS_WARN("cv_wait_sig for %s failed "
+				    "with error %d", ar->ar_path, error);
+				break;
+			}
+		} else {
+			cv_wait(&autofs_softc->sc_cv, &autofs_softc->sc_lock);
+		}
+	}
+
+	request_error = ar->ar_error;
+	if (request_error != 0) {
+		AUTOFS_WARN("request for %s completed with error %d",
+		    ar->ar_path, request_error);
+	}
+
+	wildcards = ar->ar_wildcards;
+
+	last = refcount_release(&ar->ar_refcount);
+	if (last) {
+		TAILQ_REMOVE(&autofs_softc->sc_requests, ar, ar_next);
+		/*
+		 * Unlock the sc_lock, so that autofs_task() can complete.
+		 */
+		sx_xunlock(&autofs_softc->sc_lock);
+		taskqueue_cancel_timeout(taskqueue_thread, &ar->ar_task, NULL);
+		taskqueue_drain_timeout(taskqueue_thread, &ar->ar_task);
+		uma_zfree(autofs_request_zone, ar);
+		sx_xlock(&autofs_softc->sc_lock);
+	}
+
+	/*
+	 * Note that we do not do negative caching on purpose.  This
+	 * way the user can retry access at any time, e.g. after fixing
+	 * the failure reason, without waiting for cache timer to expire.
+	 */
+	if (error == 0 && request_error == 0 && autofs_cache > 0) {
+		anp->an_cached = true;
+		anp->an_wildcards = wildcards;
+		callout_reset(&anp->an_callout, autofs_cache * hz,
+		    autofs_cache_callout, anp);
+	}
+
+	free(key, M_AUTOFS);
+	free(path, M_AUTOFS);
+
+	if (error != 0)
+		return (error);
+	return (request_error);
+}
+
+/*
+ * Send request to automountd(8) and wait for completion.
+ */
+int
+autofs_trigger(struct autofs_node *anp,
+    const char *component, int componentlen)
+{
+	int error;
+
+	for (;;) {
+		error = autofs_trigger_one(anp, component, componentlen);
+		if (error == 0) {
+			anp->an_retries = 0;
+			return (0);
+		}
+		if (error == EINTR || error == ERESTART) {
+			AUTOFS_DEBUG("trigger interrupted by signal, "
+			    "not retrying");
+			anp->an_retries = 0;
+			return (error);
+		}
+		anp->an_retries++;
+		if (anp->an_retries >= autofs_retry_attempts) {
+			AUTOFS_DEBUG("trigger failed %d times; returning "
+			    "error %d", anp->an_retries, error);
+			anp->an_retries = 0;
+			return (error);
+
+		}
+		AUTOFS_DEBUG("trigger failed with error %d; will retry in "
+		    "%d seconds, %d attempts left", error, autofs_retry_delay,
+		    autofs_retry_attempts - anp->an_retries);
+		sx_xunlock(&autofs_softc->sc_lock);
+		pause("autofs_retry", autofs_retry_delay * hz);
+		sx_xlock(&autofs_softc->sc_lock);
+	}
+}
+
+static int
+autofs_ioctl_request(struct autofs_daemon_request *adr)
+{
+	struct autofs_request *ar;
+	int error;
+
+	sx_xlock(&autofs_softc->sc_lock);
+	for (;;) {
+		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
+			if (ar->ar_done)
+				continue;
+			if (ar->ar_in_progress)
+				continue;
+
+			break;
+		}
+
+		if (ar != NULL)
+			break;
+
+		error = cv_wait_sig(&autofs_softc->sc_cv,
+		    &autofs_softc->sc_lock);
+		if (error != 0) {
+			sx_xunlock(&autofs_softc->sc_lock);
+			AUTOFS_DEBUG("failed with error %d", error);
+			return (error);
+		}
+	}
+
+	ar->ar_in_progress = true;
+	sx_xunlock(&autofs_softc->sc_lock);
+
+	adr->adr_id = ar->ar_id;
+	strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from));
+	strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path));
+	strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix));
+	strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key));
+	strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options));
+
+	PROC_LOCK(curproc);
+	autofs_softc->sc_dev_sid = curproc->p_session->s_sid;
+	PROC_UNLOCK(curproc);
+
+	return (0);
+}
+
+static int
+autofs_ioctl_done_101(struct autofs_daemon_done_101 *add)
+{
+	struct autofs_request *ar;
+
+	sx_xlock(&autofs_softc->sc_lock);
+	TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
+		if (ar->ar_id == add->add_id)
+			break;
+	}
+
+	if (ar == NULL) {
+		sx_xunlock(&autofs_softc->sc_lock);
+		AUTOFS_DEBUG("id %d not found", add->add_id);
+		return (ESRCH);
+	}
+
+	ar->ar_error = add->add_error;
+	ar->ar_wildcards = true;
+	ar->ar_done = true;
+	ar->ar_in_progress = false;
+	cv_broadcast(&autofs_softc->sc_cv);
+
+	sx_xunlock(&autofs_softc->sc_lock);
+
+	return (0);
+}
+
+static int
+autofs_ioctl_done(struct autofs_daemon_done *add)
+{
+	struct autofs_request *ar;
+
+	sx_xlock(&autofs_softc->sc_lock);
+	TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
+		if (ar->ar_id == add->add_id)
+			break;
+	}
+
+	if (ar == NULL) {
+		sx_xunlock(&autofs_softc->sc_lock);
+		AUTOFS_DEBUG("id %d not found", add->add_id);
+		return (ESRCH);
+	}
+
+	ar->ar_error = add->add_error;
+	ar->ar_wildcards = add->add_wildcards;
+	ar->ar_done = true;
+	ar->ar_in_progress = false;
+	cv_broadcast(&autofs_softc->sc_cv);
+
+	sx_xunlock(&autofs_softc->sc_lock);
+
+	return (0);
+}
+
+static int
+autofs_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+
+	sx_xlock(&autofs_softc->sc_lock);
+	/*
+	 * We must never block automountd(8) and its descendants, and we use
+	 * session ID to determine that: we store session id of the process
+	 * that opened the device, and then compare it with session ids
+	 * of triggering processes.  This means running a second automountd(8)
+	 * instance would break the previous one.  The check below prevents
+	 * it from happening.
+	 */
+	if (autofs_softc->sc_dev_opened) {
+		sx_xunlock(&autofs_softc->sc_lock);
+		return (EBUSY);
+	}
+
+	autofs_softc->sc_dev_opened = true;
+	sx_xunlock(&autofs_softc->sc_lock);
+
+	return (0);
+}
+
+static int
+autofs_close(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
+
+	sx_xlock(&autofs_softc->sc_lock);
+	KASSERT(autofs_softc->sc_dev_opened, ("not opened?"));
+	autofs_softc->sc_dev_opened = false;
+	sx_xunlock(&autofs_softc->sc_lock);
+
+	return (0);
+}
+
+static int
+autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
+    struct thread *td)
+{
+
+	KASSERT(autofs_softc->sc_dev_opened, ("not opened?"));
+
+	switch (cmd) {
+	case AUTOFSREQUEST:
+		return (autofs_ioctl_request(
+		    (struct autofs_daemon_request *)arg));
+	case AUTOFSDONE101:
+		return (autofs_ioctl_done_101(
+		    (struct autofs_daemon_done_101 *)arg));
+	case AUTOFSDONE:
+		return (autofs_ioctl_done(
+		    (struct autofs_daemon_done *)arg));
+	default:
+		AUTOFS_DEBUG("invalid cmd %lx", cmd);
+		return (EINVAL);
+	}
+}


Property changes on: trunk/sys/fs/autofs/autofs.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/autofs/autofs.h
===================================================================
--- trunk/sys/fs/autofs/autofs.h	                        (rev 0)
+++ trunk/sys/fs/autofs/autofs.h	2018-05-27 22:18:02 UTC (rev 10024)
@@ -0,0 +1,147 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/autofs/autofs.h 279742 2015-03-07 19:36:06Z trasz $
+ */
+
+#ifndef AUTOFS_H
+#define	AUTOFS_H
+
+#define VFSTOAUTOFS(mp)    ((struct autofs_mount *)((mp)->mnt_data))
+
+MALLOC_DECLARE(M_AUTOFS);
+
+extern uma_zone_t autofs_request_zone;
+extern uma_zone_t autofs_node_zone;
+
+extern int autofs_debug;
+extern int autofs_mount_on_stat;
+
+#define	AUTOFS_DEBUG(X, ...)						\
+	do {								\
+		if (autofs_debug > 1)					\
+			printf("%s: " X "\n", __func__, ## __VA_ARGS__);\
+	} while (0)
+
+#define	AUTOFS_WARN(X, ...)						\
+	do {								\
+		if (autofs_debug > 0) {					\
+			printf("WARNING: %s: " X "\n",			\
+		    	    __func__, ## __VA_ARGS__);			\
+		}							\
+	} while (0)
+
+#define AUTOFS_SLOCK(X)		sx_slock(&X->am_lock)
+#define AUTOFS_XLOCK(X)		sx_xlock(&X->am_lock)
+#define AUTOFS_SUNLOCK(X)	sx_sunlock(&X->am_lock)
+#define AUTOFS_XUNLOCK(X)	sx_xunlock(&X->am_lock)
+#define AUTOFS_ASSERT_LOCKED(X)		sx_assert(&X->am_lock, SA_LOCKED)
+#define AUTOFS_ASSERT_XLOCKED(X)	sx_assert(&X->am_lock, SA_XLOCKED)
+#define AUTOFS_ASSERT_UNLOCKED(X)	sx_assert(&X->am_lock, SA_UNLOCKED)
+
+struct autofs_node {
+	TAILQ_ENTRY(autofs_node)	an_next;
+	char				*an_name;
+	int				an_fileno;
+	struct autofs_node		*an_parent;
+	TAILQ_HEAD(, autofs_node)	an_children;
+	struct autofs_mount		*an_mount;
+	struct vnode			*an_vnode;
+	struct sx			an_vnode_lock;
+	bool				an_cached;
+	bool				an_wildcards;
+	struct callout			an_callout;
+	int				an_retries;
+	struct timespec			an_ctime;
+};
+
+struct autofs_mount {
+	TAILQ_ENTRY(autofs_mount)	am_next;
+	struct autofs_node		*am_root;
+	struct mount			*am_mp;
+	struct sx			am_lock;
+	char				am_from[MAXPATHLEN];
+	char				am_mountpoint[MAXPATHLEN];
+	char				am_options[MAXPATHLEN];
+	char				am_prefix[MAXPATHLEN];
+	int				am_last_fileno;
+};
+
+struct autofs_request {
+	TAILQ_ENTRY(autofs_request)	ar_next;
+	struct autofs_mount		*ar_mount;
+	int				ar_id;
+	bool				ar_done;
+	int				ar_error;
+	bool				ar_wildcards;
+	bool				ar_in_progress;
+	char				ar_from[MAXPATHLEN];
+	char				ar_path[MAXPATHLEN];
+	char				ar_prefix[MAXPATHLEN];
+	char				ar_key[MAXPATHLEN];
+	char				ar_options[MAXPATHLEN];
+	struct timeout_task		ar_task;
+	volatile u_int			ar_refcount;
+};
+
+struct autofs_softc {
+	device_t			sc_dev;
+	struct cdev			*sc_cdev;
+	struct cv			sc_cv;
+	struct sx			sc_lock;
+	TAILQ_HEAD(, autofs_request)	sc_requests;
+	bool				sc_dev_opened;
+	pid_t				sc_dev_sid;
+	int				sc_last_request_id;
+};
+
+/*
+ * Limits and constants
+ */
+#define AUTOFS_NAMELEN		24
+#define AUTOFS_FSNAMELEN	16	/* equal to MFSNAMELEN */
+#define AUTOFS_DELEN		(8 + AUTOFS_NAMELEN)
+
+int	autofs_init(struct vfsconf *vfsp);
+int	autofs_uninit(struct vfsconf *vfsp);
+int	autofs_trigger(struct autofs_node *anp, const char *component,
+	    int componentlen);
+bool	autofs_cached(struct autofs_node *anp, const char *component,
+	    int componentlen);
+void	autofs_flush(struct autofs_mount *amp);
+bool	autofs_ignore_thread(const struct thread *td);
+int	autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp,
+	    const char *name, int namelen, struct autofs_node **anpp);
+int	autofs_node_find(struct autofs_node *parent,
+	    const char *name, int namelen, struct autofs_node **anpp);
+void	autofs_node_delete(struct autofs_node *anp);
+int	autofs_node_vn(struct autofs_node *anp, struct mount *mp,
+	    int flags, struct vnode **vpp);
+
+#endif /* !AUTOFS_H */


Property changes on: trunk/sys/fs/autofs/autofs.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/autofs/autofs_ioctl.h
===================================================================
--- trunk/sys/fs/autofs/autofs_ioctl.h	                        (rev 0)
+++ trunk/sys/fs/autofs/autofs_ioctl.h	2018-05-27 22:18:02 UTC (rev 10024)
@@ -0,0 +1,117 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/autofs/autofs_ioctl.h 279741 2015-03-07 19:32:19Z trasz $
+ */
+
+#ifndef AUTOFS_IOCTL_H
+#define	AUTOFS_IOCTL_H
+
+#define	AUTOFS_PATH		"/dev/autofs"
+
+struct autofs_daemon_request {
+	/*
+	 * Request identifier.
+	 */
+	int		adr_id;
+
+	/*
+	 * The "from" field, containing map name.  For example,
+	 * when accessing '/net/192.168.1.3/tank/vm/', that would
+	 * be '-hosts'.
+	 */
+	char		adr_from[MAXPATHLEN];
+
+	/*
+	 * Full path to the node being looked up; for requests that result
+	 * in actual mount it is the full mount path.
+	 */
+	char		adr_path[MAXPATHLEN];
+
+	/*
+	 * Prefix, which is basically the mountpoint from auto_master(5).
+	 * In example above that would be "/net"; for direct maps it is "/".
+	 */
+	char		adr_prefix[MAXPATHLEN];
+
+	/*
+	 * Map key, also used as command argument for dynamic maps; in example
+	 * above that would be '192.168.1.3'.
+	 */
+	char		adr_key[MAXPATHLEN];
+
+	/*
+	 * Mount options from auto_master(5).
+	 */
+	char		adr_options[MAXPATHLEN];
+};
+
+/*
+ * Compatibility with 10.1-RELEASE automountd(8).
+ */
+struct autofs_daemon_done_101 {
+	/*
+	 * Identifier, copied from adr_id.
+	 */
+	int		add_id;
+
+	/*
+	 * Error number, possibly returned to userland.
+	 */
+	int		add_error;
+};
+
+struct autofs_daemon_done {
+	/*
+	 * Identifier, copied from adr_id.
+	 */
+	int		add_id;
+
+	/*
+	 * Set to 1 if the map may contain wildcard entries;
+	 * otherwise autofs will do negative caching.
+	 */
+	int		add_wildcards;
+
+	/*
+	 * Error number, possibly returned to userland.
+	 */
+	int		add_error;
+
+	/*
+	 * Reserved for future use.
+	 */
+	int		add_spare[7];
+};
+
+#define	AUTOFSREQUEST	_IOR('I', 0x01, struct autofs_daemon_request)
+#define	AUTOFSDONE101	_IOW('I', 0x02, struct autofs_daemon_done_101)
+#define	AUTOFSDONE	_IOW('I', 0x03, struct autofs_daemon_done)
+
+#endif /* !AUTOFS_IOCTL_H */


Property changes on: trunk/sys/fs/autofs/autofs_ioctl.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/autofs/autofs_vfsops.c
===================================================================
--- trunk/sys/fs/autofs/autofs_vfsops.c	                        (rev 0)
+++ trunk/sys/fs/autofs/autofs_vfsops.c	2018-05-27 22:18:02 UTC (rev 10024)
@@ -0,0 +1,218 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+ __FBSDID("$FreeBSD: stable/10/sys/fs/autofs/autofs_vfsops.c 279742 2015-03-07 19:36:06Z trasz $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/condvar.h>
+#include <sys/ioccom.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+#include <sys/vnode.h>
+
+#include <fs/autofs/autofs.h>
+
+static const char *autofs_opts[] = {
+	"from", "master_options", "master_prefix", NULL
+};
+
+extern struct autofs_softc	*autofs_softc;
+
+static int
+autofs_mount(struct mount *mp)
+{
+	struct autofs_mount *amp;
+	char *from, *fspath, *options, *prefix;
+	int error;
+
+	if (vfs_filteropt(mp->mnt_optnew, autofs_opts))
+		return (EINVAL);
+
+	if (mp->mnt_flag & MNT_UPDATE) {
+		autofs_flush(VFSTOAUTOFS(mp));
+		return (0);
+	}
+
+	if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL))
+		return (EINVAL);
+
+	if (vfs_getopt(mp->mnt_optnew, "fspath", (void **)&fspath, NULL))
+		return (EINVAL);
+
+	if (vfs_getopt(mp->mnt_optnew, "master_options", (void **)&options, NULL))
+		return (EINVAL);
+
+	if (vfs_getopt(mp->mnt_optnew, "master_prefix", (void **)&prefix, NULL))
+		return (EINVAL);
+
+	amp = malloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO);
+	mp->mnt_data = amp;
+	amp->am_mp = mp;
+	strlcpy(amp->am_from, from, sizeof(amp->am_from));
+	strlcpy(amp->am_mountpoint, fspath, sizeof(amp->am_mountpoint));
+	strlcpy(amp->am_options, options, sizeof(amp->am_options));
+	strlcpy(amp->am_prefix, prefix, sizeof(amp->am_prefix));
+	sx_init(&amp->am_lock, "autofslk");
+	amp->am_last_fileno = 1;
+
+	vfs_getnewfsid(mp);
+
+	MNT_ILOCK(mp);
+	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED;
+	MNT_IUNLOCK(mp);
+
+	AUTOFS_XLOCK(amp);
+	error = autofs_node_new(NULL, amp, ".", -1, &amp->am_root);
+	if (error != 0) {
+		AUTOFS_XUNLOCK(amp);
+		free(amp, M_AUTOFS);
+		return (error);
+	}
+	AUTOFS_XUNLOCK(amp);
+
+	vfs_mountedfrom(mp, from);
+
+	return (0);
+}
+
+static int
+autofs_unmount(struct mount *mp, int mntflags)
+{
+	struct autofs_mount *amp;
+	struct autofs_node *anp;
+	struct autofs_request *ar;
+	int error, flags;
+	bool found;
+
+	amp = VFSTOAUTOFS(mp);
+
+	flags = 0;
+	if (mntflags & MNT_FORCE)
+		flags |= FORCECLOSE;
+	error = vflush(mp, 0, flags, curthread);
+	if (error != 0) {
+		AUTOFS_WARN("vflush failed with error %d", error);
+		return (error);
+	}
+
+	/*
+	 * All vnodes are gone, and new one will not appear - so,
+	 * no new triggerings.  We can iterate over outstanding
+	 * autofs_requests and terminate them.
+	 */
+	for (;;) {
+		found = false;
+		sx_xlock(&autofs_softc->sc_lock);
+		TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
+			if (ar->ar_mount != amp)
+				continue;
+			ar->ar_error = ENXIO;
+			ar->ar_done = true;
+			ar->ar_in_progress = false;
+			found = true;
+		}
+		sx_xunlock(&autofs_softc->sc_lock);
+		if (found == false)
+			break;
+
+		cv_broadcast(&autofs_softc->sc_cv);
+		pause("autofs_umount", 1);
+	}
+
+	AUTOFS_XLOCK(amp);
+
+	/*
+	 * Not terribly efficient, but at least not recursive.
+	 */
+	while (!TAILQ_EMPTY(&amp->am_root->an_children)) {
+		anp = TAILQ_FIRST(&amp->am_root->an_children);
+		while (!TAILQ_EMPTY(&anp->an_children))
+			anp = TAILQ_FIRST(&anp->an_children);
+		autofs_node_delete(anp);
+	}
+	autofs_node_delete(amp->am_root);
+
+	mp->mnt_data = NULL;
+	AUTOFS_XUNLOCK(amp);
+
+	sx_destroy(&amp->am_lock);
+
+	free(amp, M_AUTOFS);
+
+	return (0);
+}
+
+static int
+autofs_root(struct mount *mp, int flags, struct vnode **vpp)
+{
+	struct autofs_mount *amp;
+	int error;
+
+	amp = VFSTOAUTOFS(mp);
+
+	error = autofs_node_vn(amp->am_root, mp, flags, vpp);
+
+	return (error);
+}
+
+static int
+autofs_statfs(struct mount *mp, struct statfs *sbp)
+{
+
+	sbp->f_bsize = 512;
+	sbp->f_iosize = 0;
+	sbp->f_blocks = 0;
+	sbp->f_bfree = 0;
+	sbp->f_bavail = 0;
+	sbp->f_files = 0;
+	sbp->f_ffree = 0;
+
+	return (0);
+}
+
+static struct vfsops autofs_vfsops = {
+	.vfs_fhtovp =		NULL, /* XXX */
+	.vfs_mount =		autofs_mount,
+	.vfs_unmount =		autofs_unmount,
+	.vfs_root =		autofs_root,
+	.vfs_statfs =		autofs_statfs,
+	.vfs_init =		autofs_init,
+	.vfs_uninit =		autofs_uninit,
+};
+
+VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_NETWORK);
+MODULE_VERSION(autofs, 1);


Property changes on: trunk/sys/fs/autofs/autofs_vfsops.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/autofs/autofs_vnops.c
===================================================================
--- trunk/sys/fs/autofs/autofs_vnops.c	                        (rev 0)
+++ trunk/sys/fs/autofs/autofs_vnops.c	2018-05-27 22:18:02 UTC (rev 10024)
@@ -0,0 +1,657 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/fs/autofs/autofs_vnops.c 274239 2014-11-07 15:52:32Z trasz $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/condvar.h>
+#include <sys/dirent.h>
+#include <sys/fcntl.h>
+#include <sys/lock.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/signalvar.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+#include <sys/vnode.h>
+#include <machine/atomic.h>
+#include <vm/uma.h>
+
+#include <fs/autofs/autofs.h>
+
+static int	autofs_trigger_vn(struct vnode *vp, const char *path,
+		    int pathlen, struct vnode **newvp);
+
+extern struct autofs_softc	*autofs_softc;
+
+static int
+autofs_access(struct vop_access_args *ap)
+{
+
+	/*
+	 * Nothing to do here; the only kind of access control
+	 * needed is in autofs_mkdir().
+	 */
+
+	return (0);
+}
+
+static int
+autofs_getattr(struct vop_getattr_args *ap)
+{
+	struct vnode *vp, *newvp;
+	struct autofs_node *anp;
+	struct mount *mp;
+	struct vattr *vap;
+	int error;
+
+	vp = ap->a_vp;
+	anp = vp->v_data;
+	mp = vp->v_mount;
+	vap = ap->a_vap;
+
+	KASSERT(ap->a_vp->v_type == VDIR, ("!VDIR"));
+
+	/*
+	 * The reason we must do this is that some tree-walking software,
+	 * namely fts(3), assumes that stat(".") results will not change
+	 * between chdir("subdir") and chdir(".."), and fails with ENOENT
+	 * otherwise.
+	 */
+	if (autofs_mount_on_stat && autofs_cached(anp, NULL, 0) == false &&
+	    autofs_ignore_thread(curthread) == false) {
+		error = autofs_trigger_vn(vp, "", 0, &newvp);
+		if (error != 0)
+			return (error);
+
+		if (newvp != NULL) {
+			error = VOP_GETATTR(newvp, ap->a_vap,
+			    ap->a_cred);
+			vput(newvp);
+			return (error);
+		}
+	}
+
+	vap->va_type = VDIR;
+	vap->va_mode = 0755;
+	vap->va_nlink = 3; /* XXX */
+	vap->va_uid = 0;
+	vap->va_gid = 0;
+	vap->va_rdev = NODEV;
+	vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
+	vap->va_fileid = anp->an_fileno;
+	vap->va_size = 512; /* XXX */
+	vap->va_blocksize = 512;
+	vap->va_mtime = anp->an_ctime;
+	vap->va_atime = anp->an_ctime;
+	vap->va_ctime = anp->an_ctime;
+	vap->va_birthtime = anp->an_ctime;
+	vap->va_gen = 0;
+	vap->va_flags = 0;
+	vap->va_rdev = 0;
+	vap->va_bytes = 512; /* XXX */
+	vap->va_filerev = 0;
+	vap->va_spare = 0;
+
+	return (0);
+}
+
+/*
+ * Unlock the vnode, request automountd(8) action, and then lock it back.
+ * If anything got mounted on top of the vnode, return the new filesystem's
+ * root vnode in 'newvp', locked.
+ */
+static int
+autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen,
+    struct vnode **newvp)
+{
+	struct autofs_node *anp;
+	struct autofs_mount *amp;
+	int error, lock_flags;
+
+	anp = vp->v_data;
+	amp = VFSTOAUTOFS(vp->v_mount);
+
+	/*
+	 * Release the vnode lock, so that other operations, in partcular
+	 * mounting a filesystem on top of it, can proceed.  Increase use
+	 * count, to prevent the vnode from being deallocated and to prevent
+	 * filesystem from being unmounted.
+	 */
+	lock_flags = VOP_ISLOCKED(vp);
+	vref(vp);
+	VOP_UNLOCK(vp, 0);
+
+	sx_xlock(&autofs_softc->sc_lock);
+
+	/*
+	 * XXX: Workaround for mounting the same thing multiple times; revisit.
+	 */
+	if (vp->v_mountedhere != NULL) {
+		error = 0;
+		goto mounted;
+	}
+
+	error = autofs_trigger(anp, path, pathlen);
+mounted:
+	sx_xunlock(&autofs_softc->sc_lock);
+	vn_lock(vp, lock_flags | LK_RETRY);
+	vunref(vp);
+	if ((vp->v_iflag & VI_DOOMED) != 0) {
+		AUTOFS_DEBUG("VI_DOOMED");
+		return (ENOENT);
+	}
+
+	if (error != 0)
+		return (error);
+
+	if (vp->v_mountedhere == NULL) {
+		*newvp = NULL;
+		return (0);
+	} else {
+		/*
+		 * If the operation that succeeded was mount, then mark
+		 * the node as non-cached.  Otherwise, if someone unmounts
+		 * the filesystem before the cache times out, we will fail
+		 * to trigger.
+		 */
+		anp->an_cached = false;
+	}
+
+	error = VFS_ROOT(vp->v_mountedhere, lock_flags, newvp);
+	if (error != 0) {
+		AUTOFS_WARN("VFS_ROOT() failed with error %d", error);
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+autofs_vget_callback(struct mount *mp, void *arg, int flags,
+    struct vnode **vpp)
+{
+
+
+	return (autofs_node_vn(arg, mp, flags, vpp));
+}
+
+static int
+autofs_lookup(struct vop_lookup_args *ap)
+{
+	struct vnode *dvp, *newvp, **vpp;
+	struct mount *mp;
+	struct autofs_mount *amp;
+	struct autofs_node *anp, *child;
+	struct componentname *cnp;
+	int error, lock_flags;
+
+	dvp = ap->a_dvp;
+	vpp = ap->a_vpp;
+	mp = dvp->v_mount;
+	amp = VFSTOAUTOFS(mp);
+	anp = dvp->v_data;
+	cnp = ap->a_cnp;
+
+	if (cnp->cn_flags & ISDOTDOT) {
+		KASSERT(anp->an_parent != NULL, ("NULL parent"));
+		/*
+		 * Note that in this case, dvp is the child vnode, and we
+		 * are looking up the parent vnode - exactly reverse from
+		 * normal operation.  Unlocking dvp requires some rather
+		 * tricky unlock/relock dance to prevent mp from being freed;
+		 * use vn_vget_ino_gen() which takes care of all that.
+		 */
+		error = vn_vget_ino_gen(dvp, autofs_vget_callback,
+		    anp->an_parent, cnp->cn_lkflags, vpp);
+		if (error != 0) {
+			AUTOFS_WARN("vn_vget_ino_gen() failed with error %d",
+			    error);
+			return (error);
+		}
+		return (error);
+	}
+
+	if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
+		vref(dvp);
+		*vpp = dvp;
+
+		return (0);
+	}
+
+	if (autofs_cached(anp, cnp->cn_nameptr, cnp->cn_namelen) == false &&
+	    autofs_ignore_thread(cnp->cn_thread) == false) {
+		error = autofs_trigger_vn(dvp,
+		    cnp->cn_nameptr, cnp->cn_namelen, &newvp);
+		if (error != 0)
+			return (error);
+
+		if (newvp != NULL) {
+			error = VOP_LOOKUP(newvp, ap->a_vpp, ap->a_cnp);
+
+			/*
+			 * Instead of figuring out whether our vnode should
+			 * be locked or not given the error and cnp flags,
+			 * just "copy" the lock status from vnode returned
+			 * by mounted filesystem's VOP_LOOKUP().  Get rid
+			 * of that new vnode afterwards.
+			 */
+			lock_flags = VOP_ISLOCKED(newvp);
+			if (lock_flags == 0) {
+				VOP_UNLOCK(dvp, 0);
+				vrele(newvp);
+			} else {
+				vput(newvp);
+			}
+			return (error);
+		}
+	}
+
+	AUTOFS_SLOCK(amp);
+	error = autofs_node_find(anp, cnp->cn_nameptr, cnp->cn_namelen, &child);
+	if (error != 0) {
+		if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
+			AUTOFS_SUNLOCK(amp);
+			return (EJUSTRETURN);
+		}
+
+		AUTOFS_SUNLOCK(amp);
+		return (ENOENT);
+	}
+
+	/*
+	 * XXX: Dropping the node here is ok, because we never remove nodes.
+	 */
+	AUTOFS_SUNLOCK(amp);
+
+	error = autofs_node_vn(child, mp, cnp->cn_lkflags, vpp);
+	if (error != 0) {
+		if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE)
+			return (EJUSTRETURN);
+
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+autofs_mkdir(struct vop_mkdir_args *ap)
+{
+	struct vnode *vp;
+	struct autofs_node *anp;
+	struct autofs_mount *amp;
+	struct autofs_node *child;
+	int error;
+
+	vp = ap->a_dvp;
+	anp = vp->v_data;
+	amp = VFSTOAUTOFS(vp->v_mount);
+
+	/*
+	 * Do not allow mkdir() if the calling thread is not
+	 * automountd(8) descendant.
+	 */
+	if (autofs_ignore_thread(curthread) == false)
+		return (EPERM);
+
+	AUTOFS_XLOCK(amp);
+	error = autofs_node_new(anp, amp, ap->a_cnp->cn_nameptr,
+	    ap->a_cnp->cn_namelen, &child);
+	if (error != 0) {
+		AUTOFS_XUNLOCK(amp);
+		return (error);
+	}
+	AUTOFS_XUNLOCK(amp);
+
+	error = autofs_node_vn(child, vp->v_mount, LK_EXCLUSIVE, ap->a_vpp);
+
+	return (error);
+}
+
+static int
+autofs_readdir_one(struct uio *uio, const char *name, int fileno)
+{
+	struct dirent dirent;
+	int error, i;
+
+	memset(&dirent, 0, sizeof(dirent));
+	dirent.d_type = DT_DIR;
+	dirent.d_reclen = AUTOFS_DELEN;
+	dirent.d_fileno = fileno;
+	/* PFS_DELEN was picked to fit PFS_NAMLEN */
+	for (i = 0; i < AUTOFS_NAMELEN - 1 && name[i] != '\0'; ++i)
+		dirent.d_name[i] = name[i];
+	dirent.d_name[i] = 0;
+	dirent.d_namlen = i;
+
+	error = uiomove(&dirent, AUTOFS_DELEN, uio);
+	return (error);
+}
+
+static int
+autofs_readdir(struct vop_readdir_args *ap)
+{
+	struct vnode *vp, *newvp;
+	struct autofs_mount *amp;
+	struct autofs_node *anp, *child;
+	struct uio *uio;
+	off_t offset;
+	int error, i, resid;
+
+	vp = ap->a_vp;
+	amp = VFSTOAUTOFS(vp->v_mount);
+	anp = vp->v_data;
+	uio = ap->a_uio;
+
+	KASSERT(vp->v_type == VDIR, ("!VDIR"));
+
+	if (autofs_cached(anp, NULL, 0) == false &&
+	    autofs_ignore_thread(curthread) == false) {
+		error = autofs_trigger_vn(vp, "", 0, &newvp);
+		if (error != 0)
+			return (error);
+
+		if (newvp != NULL) {
+			error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred,
+			    ap->a_eofflag, ap->a_ncookies, ap->a_cookies);
+			vput(newvp);
+			return (error);
+		}
+	}
+
+	/* only allow reading entire entries */
+	offset = uio->uio_offset;
+	resid = uio->uio_resid;
+	if (offset < 0 || offset % AUTOFS_DELEN != 0 ||
+	    (resid && resid < AUTOFS_DELEN))
+		return (EINVAL);
+	if (resid == 0)
+		return (0);
+
+	if (ap->a_eofflag != NULL)
+		*ap->a_eofflag = TRUE;
+
+	if (offset == 0 && resid >= AUTOFS_DELEN) {
+		error = autofs_readdir_one(uio, ".", anp->an_fileno);
+		if (error != 0)
+			return (error);
+		offset += AUTOFS_DELEN;
+		resid -= AUTOFS_DELEN;
+	}
+
+	if (offset == AUTOFS_DELEN && resid >= AUTOFS_DELEN) {
+		if (anp->an_parent == NULL) {
+			/*
+			 * XXX: Right?
+			 */
+			error = autofs_readdir_one(uio, "..", anp->an_fileno);
+		} else {
+			error = autofs_readdir_one(uio, "..",
+			    anp->an_parent->an_fileno);
+		}
+		if (error != 0)
+			return (error);
+		offset += AUTOFS_DELEN;
+		resid -= AUTOFS_DELEN;
+	}
+
+	i = 2; /* Account for "." and "..". */
+	AUTOFS_SLOCK(amp);
+	TAILQ_FOREACH(child, &anp->an_children, an_next) {
+		if (resid < AUTOFS_DELEN) {
+			if (ap->a_eofflag != NULL)
+				*ap->a_eofflag = 0;
+			break;
+		}
+
+		/*
+		 * Skip entries returned by previous call to getdents().
+		 */
+		i++;
+		if (i * AUTOFS_DELEN <= offset)
+			continue;
+
+		error = autofs_readdir_one(uio, child->an_name,
+		    child->an_fileno);
+		if (error != 0) {
+			AUTOFS_SUNLOCK(amp);
+			return (error);
+		}
+		offset += AUTOFS_DELEN;
+		resid -= AUTOFS_DELEN;
+	}
+
+	AUTOFS_SUNLOCK(amp);
+	return (0);
+}
+
+static int
+autofs_reclaim(struct vop_reclaim_args *ap)
+{
+	struct vnode *vp;
+	struct autofs_node *anp;
+
+	vp = ap->a_vp;
+	anp = vp->v_data;
+
+	/*
+	 * We do not free autofs_node here; instead we are
+	 * destroying them in autofs_node_delete().
+	 */
+	sx_xlock(&anp->an_vnode_lock);
+	anp->an_vnode = NULL;
+	vp->v_data = NULL;
+	sx_xunlock(&anp->an_vnode_lock);
+
+	return (0);
+}
+
+struct vop_vector autofs_vnodeops = {
+	.vop_default =		&default_vnodeops,
+
+	.vop_access =		autofs_access,
+	.vop_lookup =		autofs_lookup,
+	.vop_create =		VOP_EOPNOTSUPP,
+	.vop_getattr =		autofs_getattr,
+	.vop_link =		VOP_EOPNOTSUPP,
+	.vop_mkdir =		autofs_mkdir,
+	.vop_mknod =		VOP_EOPNOTSUPP,
+	.vop_read =		VOP_EOPNOTSUPP,
+	.vop_readdir =		autofs_readdir,
+	.vop_remove =		VOP_EOPNOTSUPP,
+	.vop_rename =		VOP_EOPNOTSUPP,
+	.vop_rmdir =		VOP_EOPNOTSUPP,
+	.vop_setattr =		VOP_EOPNOTSUPP,
+	.vop_symlink =		VOP_EOPNOTSUPP,
+	.vop_write =		VOP_EOPNOTSUPP,
+	.vop_reclaim =		autofs_reclaim,
+};
+
+int
+autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp,
+    const char *name, int namelen, struct autofs_node **anpp)
+{
+	struct autofs_node *anp;
+
+	if (parent != NULL) {
+		AUTOFS_ASSERT_XLOCKED(parent->an_mount);
+
+		KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT,
+		    ("node \"%s\" already exists", name));
+	}
+
+	anp = uma_zalloc(autofs_node_zone, M_WAITOK | M_ZERO);
+	if (namelen >= 0)
+		anp->an_name = strndup(name, namelen, M_AUTOFS);
+	else
+		anp->an_name = strdup(name, M_AUTOFS);
+	anp->an_fileno = atomic_fetchadd_int(&amp->am_last_fileno, 1);
+	callout_init(&anp->an_callout, 1);
+	/*
+	 * The reason for SX_NOWITNESS here is that witness(4)
+	 * cannot tell vnodes apart, so the following perfectly
+	 * valid lock order...
+	 *
+	 * vnode lock A -> autofsvlk B -> vnode lock B
+	 *
+	 * ... gets reported as a LOR.
+	 */
+	sx_init_flags(&anp->an_vnode_lock, "autofsvlk", SX_NOWITNESS);
+	getnanotime(&anp->an_ctime);
+	anp->an_parent = parent;
+	anp->an_mount = amp;
+	if (parent != NULL)
+		TAILQ_INSERT_TAIL(&parent->an_children, anp, an_next);
+	TAILQ_INIT(&anp->an_children);
+
+	*anpp = anp;
+	return (0);
+}
+
+int
+autofs_node_find(struct autofs_node *parent, const char *name,
+    int namelen, struct autofs_node **anpp)
+{
+	struct autofs_node *anp;
+
+	AUTOFS_ASSERT_LOCKED(parent->an_mount);
+
+	TAILQ_FOREACH(anp, &parent->an_children, an_next) {
+		if (namelen >= 0) {
+			if (strlen(anp->an_name) != namelen)
+				continue;
+			if (strncmp(anp->an_name, name, namelen) != 0)
+				continue;
+		} else {
+			if (strcmp(anp->an_name, name) != 0)
+				continue;
+		}
+
+		if (anpp != NULL)
+			*anpp = anp;
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
+void
+autofs_node_delete(struct autofs_node *anp)
+{
+	struct autofs_node *parent;
+
+	AUTOFS_ASSERT_XLOCKED(anp->an_mount);
+	KASSERT(TAILQ_EMPTY(&anp->an_children), ("have children"));
+
+	callout_drain(&anp->an_callout);
+
+	parent = anp->an_parent;
+	if (parent != NULL)
+		TAILQ_REMOVE(&parent->an_children, anp, an_next);
+	sx_destroy(&anp->an_vnode_lock);
+	free(anp->an_name, M_AUTOFS);
+	uma_zfree(autofs_node_zone, anp);
+}
+
+int
+autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags,
+    struct vnode **vpp)
+{
+	struct vnode *vp;
+	int error;
+
+	AUTOFS_ASSERT_UNLOCKED(anp->an_mount);
+
+	sx_xlock(&anp->an_vnode_lock);
+
+	vp = anp->an_vnode;
+	if (vp != NULL) {
+		error = vget(vp, flags | LK_RETRY, curthread);
+		if (error != 0) {
+			AUTOFS_WARN("vget failed with error %d", error);
+			sx_xunlock(&anp->an_vnode_lock);
+			return (error);
+		}
+		if (vp->v_iflag & VI_DOOMED) {
+			/*
+			 * We got forcibly unmounted.
+			 */
+			AUTOFS_DEBUG("doomed vnode");
+			sx_xunlock(&anp->an_vnode_lock);
+			vput(vp);
+
+			return (ENOENT);
+		}
+
+		*vpp = vp;
+		sx_xunlock(&anp->an_vnode_lock);
+		return (0);
+	}
+
+	error = getnewvnode("autofs", mp, &autofs_vnodeops, &vp);
+	if (error != 0) {
+		sx_xunlock(&anp->an_vnode_lock);
+		return (error);
+	}
+
+	error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	if (error != 0) {
+		sx_xunlock(&anp->an_vnode_lock);
+		vdrop(vp);
+		return (error);
+	}
+
+	vp->v_type = VDIR;
+	if (anp->an_parent == NULL)
+		vp->v_vflag |= VV_ROOT;
+	vp->v_data = anp;
+
+	VN_LOCK_ASHARE(vp);
+
+	error = insmntque(vp, mp);
+	if (error != 0) {
+		AUTOFS_WARN("insmntque() failed with error %d", error);
+		sx_xunlock(&anp->an_vnode_lock);
+		return (error);
+	}
+
+	KASSERT(anp->an_vnode == NULL, ("lost race"));
+	anp->an_vnode = vp;
+
+	sx_xunlock(&anp->an_vnode_lock);
+
+	*vpp = vp;
+	return (0);
+}


Property changes on: trunk/sys/fs/autofs/autofs_vnops.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list