Date: Sun, 17 Aug 2014 09:44:42 +0000 (UTC) From: Edward Tomasz Napierala <trasz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270096 - in head: etc etc/autofs etc/defaults etc/mtree etc/rc.d sbin/mount share/man/man5 sys/conf sys/fs/autofs sys/kern sys/libkern sys/modules sys/modules/autofs sys/sys usr.sbin u... Message-ID: <201408170944.s7H9igDr008156@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: trasz Date: Sun Aug 17 09:44:42 2014 New Revision: 270096 URL: http://svnweb.freebsd.org/changeset/base/270096 Log: Bring in the new automounter, similar to what's provided in most other UNIX systems, eg. MacOS X and Solaris. It uses Sun-compatible map format, has proper kernel support, and LDAP integration. There are still a few outstanding problems; they will be fixed shortly. Reviewed by: allanjude@, emaste@, kib@, wblock@ (earlier versions) Phabric: D523 MFC after: 2 weeks Relnotes: yes Sponsored by: The FreeBSD Foundation Added: head/etc/auto_master (contents, props changed) head/etc/autofs/ head/etc/autofs/Makefile (contents, props changed) head/etc/autofs/include_ldap (contents, props changed) head/etc/autofs/special_hosts (contents, props changed) head/etc/autofs/special_null (contents, props changed) head/etc/rc.d/automount (contents, props changed) head/etc/rc.d/automountd (contents, props changed) head/etc/rc.d/autounmountd (contents, props changed) head/share/man/man5/autofs.5 (contents, props changed) head/sys/fs/autofs/ head/sys/fs/autofs/autofs.c (contents, props changed) head/sys/fs/autofs/autofs.h (contents, props changed) head/sys/fs/autofs/autofs_ioctl.h (contents, props changed) head/sys/fs/autofs/autofs_vfsops.c (contents, props changed) head/sys/fs/autofs/autofs_vnops.c (contents, props changed) head/sys/libkern/strndup.c (contents, props changed) head/sys/modules/autofs/ head/sys/modules/autofs/Makefile (contents, props changed) head/usr.sbin/autofs/ head/usr.sbin/autofs/Makefile (contents, props changed) head/usr.sbin/autofs/auto_master.5 (contents, props changed) head/usr.sbin/autofs/automount.8 (contents, props changed) head/usr.sbin/autofs/automount.c (contents, props changed) head/usr.sbin/autofs/automountd.8 (contents, props changed) head/usr.sbin/autofs/automountd.c (contents, props changed) head/usr.sbin/autofs/autounmountd.8 (contents, props changed) head/usr.sbin/autofs/autounmountd.c (contents, props changed) head/usr.sbin/autofs/common.c (contents, props changed) head/usr.sbin/autofs/common.h (contents, props changed) head/usr.sbin/autofs/defined.c (contents, props changed) head/usr.sbin/autofs/log.c (contents, props changed) head/usr.sbin/autofs/popen.c (contents, props changed) head/usr.sbin/autofs/token.l (contents, props changed) Modified: head/etc/Makefile head/etc/defaults/rc.conf head/etc/mtree/BSD.root.dist head/etc/rc.d/Makefile head/sbin/mount/mntopts.h head/sbin/mount/mount.c head/share/man/man5/Makefile head/sys/conf/NOTES head/sys/conf/files head/sys/conf/options head/sys/kern/vfs_mount.c head/sys/modules/Makefile head/sys/sys/libkern.h head/sys/sys/mount.h head/usr.sbin/Makefile Modified: head/etc/Makefile ============================================================================== --- head/etc/Makefile Sun Aug 17 09:07:21 2014 (r270095) +++ head/etc/Makefile Sun Aug 17 09:44:42 2014 (r270096) @@ -11,7 +11,8 @@ SUBDIR= sendmail SUBDIR+=tests .endif -BIN1= crontab \ +BIN1= auto_master \ + crontab \ devd.conf \ devfs.conf \ ddb.conf \ @@ -225,6 +226,7 @@ distribution: echo "./etc/spwd.db type=file mode=0600 uname=root gname=wheel"; \ ) | ${METALOG.add} .endif + ${_+_}cd ${.CURDIR}/autofs; ${MAKE} install .if ${MK_BLUETOOTH} != "no" ${_+_}cd ${.CURDIR}/bluetooth; ${MAKE} install .endif Added: head/etc/auto_master ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/auto_master Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,5 @@ +# $FreeBSD$ +# +# Automounter master map, see auto_master(5) for details. +# +/net -hosts -nosuid Added: head/etc/autofs/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/autofs/Makefile Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,9 @@ +# $FreeBSD$ + +FILES= include_ldap special_hosts special_null + +NO_OBJ= +FILESDIR= /etc/autofs +FILESMODE= 755 + +.include <bsd.prog.mk> Added: head/etc/autofs/include_ldap ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/autofs/include_ldap Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,38 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# Modify this to suit your needs. The "$1" is the map name, eg. "auto_master". +# To debug, simply run this script with map name as the only parameter. It's +# supposed to output map contents ("key location" pairs) to standard output. +SEARCHBASE="ou=$1,dc=example,dc=com" +ENTRY_ATTRIBUTE="cn" +VALUE_ATTRIBUTE="automountInformation" + +/usr/local/bin/ldapsearch -LLL -x -o ldif-wrap=no -b "$SEARCHBASE" "$ENTRY_ATTRIBUTE" "$VALUE_ATTRIBUTE" | awk ' +$1 == "'$ENTRY_ATTRIBUTE':" { + key = $2 +} + +$1 == "'$VALUE_ATTRIBUTE':" && key { + printf "%s%s", key, OFS + key = "" + for (i=2; i<NF; i++) { + printf "%s%s", $(i), OFS + } + printf "%s%s", $NF, ORS +} + +# Double colon after attribute name means the value is in Base64. +$1 == "'$VALUE_ATTRIBUTE'::" && key { + printf "%s%s", key, OFS + key = "" + for (i=2; i<NF; i++) { + printf "%s%s", $(i), OFS + } + printf "%s", $NF | "b64decode -rp" + close("b64decode -rp") + printf "%s", ORS +} +' Added: head/etc/autofs/special_hosts ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/autofs/special_hosts Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,17 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +if [ $# -eq 0 ]; then + out=`getent hosts` + [ $? -eq 0 ] || exit 1 + echo "$out" | awk '{ print $2 }' | sort -u + exit 0 +fi + +out=`showmount -e "$1"` +[ $? -eq 0 ] || exit 1 +echo "$out" | awk -v host="$1" \ + 'NR > 1 { printf "%s\t%s:%s ", $1, host, $1 } END { printf "\n" }' + Added: head/etc/autofs/special_null ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/autofs/special_null Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,4 @@ +#!/usr/bin/true +# +# $FreeBSD$ +# Modified: head/etc/defaults/rc.conf ============================================================================== --- head/etc/defaults/rc.conf Sun Aug 17 09:07:21 2014 (r270095) +++ head/etc/defaults/rc.conf Sun Aug 17 09:44:42 2014 (r270096) @@ -306,6 +306,7 @@ amd_enable="NO" # Run amd service with amd_program="/usr/sbin/amd" # path to amd, if you want a different one. amd_flags="-a /.amd_mnt -l syslog /host /etc/amd.map /net /etc/amd.map" amd_map_program="NO" # Can be set to "ypcat -k amd.master" +autofs_enable="NO" # Run automountd(8) nfs_client_enable="NO" # This host is an NFS client (or NO). nfs_access_cache="60" # Client cache timeout in seconds nfs_server_enable="NO" # This host is an NFS server (or NO). Modified: head/etc/mtree/BSD.root.dist ============================================================================== --- head/etc/mtree/BSD.root.dist Sun Aug 17 09:07:21 2014 (r270095) +++ head/etc/mtree/BSD.root.dist Sun Aug 17 09:44:42 2014 (r270096) @@ -24,6 +24,8 @@ etc X11 .. + autofs + .. bluetooth .. casper Modified: head/etc/rc.d/Makefile ============================================================================== --- head/etc/rc.d/Makefile Sun Aug 17 09:07:21 2014 (r270095) +++ head/etc/rc.d/Makefile Sun Aug 17 09:44:42 2014 (r270096) @@ -20,6 +20,9 @@ FILES= DAEMON \ atm3 \ auditd \ auditdistd \ + automount \ + automountd \ + autounmountd \ bgfsck \ ${_bluetooth} \ bootparams \ Added: head/etc/rc.d/automount ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/rc.d/automount Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,31 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: automount +# REQUIRE: nfsclient +# KEYWORD: nojail shutdown + +. /etc/rc.subr + +name="automount" +rcvar="autofs_enable" +start_cmd="automount_start" +stop_cmd="automount_stop" +required_modules="autofs" + +automount_start() +{ + + /usr/sbin/automount +} + +automount_stop() +{ + + /sbin/umount -At autofs +} + +load_rc_config $name +run_rc_command "$1" Added: head/etc/rc.d/automountd ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/rc.d/automountd Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,19 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: automountd +# REQUIRE: automount +# KEYWORD: nojail + +. /etc/rc.subr + +name="automountd" +rcvar="autofs_enable" +pidfile="/var/run/${name}.pid" +command="/usr/sbin/${name}" +required_modules="autofs" + +load_rc_config $name +run_rc_command "$1" Added: head/etc/rc.d/autounmountd ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/rc.d/autounmountd Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,18 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: autounmountd +# REQUIRE: nfsclient +# KEYWORD: nojail + +. /etc/rc.subr + +name="autounmountd" +rcvar="autofs_enable" +pidfile="/var/run/${name}.pid" +command="/usr/sbin/${name}" + +load_rc_config $name +run_rc_command "$1" Modified: head/sbin/mount/mntopts.h ============================================================================== --- head/sbin/mount/mntopts.h Sun Aug 17 09:07:21 2014 (r270095) +++ head/sbin/mount/mntopts.h Sun Aug 17 09:44:42 2014 (r270096) @@ -33,7 +33,7 @@ struct mntopt { const char *m_option; /* option name */ int m_inverse; /* if a negative option, e.g. "atime" */ - int m_flag; /* bit to set, e.g. MNT_RDONLY */ + long long m_flag; /* bit to set, e.g. MNT_RDONLY */ int m_altloc; /* 1 => set bit in altflags */ }; @@ -55,6 +55,7 @@ struct mntopt { #define MOPT_MULTILABEL { "multilabel", 0, MNT_MULTILABEL, 0 } #define MOPT_ACLS { "acls", 0, MNT_ACLS, 0 } #define MOPT_NFS4ACLS { "nfsv4acls", 0, MNT_NFS4ACLS, 0 } +#define MOPT_AUTOMOUNTED { "automounted",0, MNT_AUTOMOUNTED, 0 } /* Control flags. */ #define MOPT_FORCE { "force", 0, MNT_FORCE, 0 } @@ -89,7 +90,8 @@ struct mntopt { MOPT_NOCLUSTERW, \ MOPT_MULTILABEL, \ MOPT_ACLS, \ - MOPT_NFS4ACLS + MOPT_NFS4ACLS, \ + MOPT_AUTOMOUNTED void getmntopts(const char *, const struct mntopt *, int *, int *); void rmslashes(char *, char *); Modified: head/sbin/mount/mount.c ============================================================================== --- head/sbin/mount/mount.c Sun Aug 17 09:07:21 2014 (r270095) +++ head/sbin/mount/mount.c Sun Aug 17 09:44:42 2014 (r270096) @@ -114,6 +114,7 @@ static struct opt { { MNT_ACLS, "acls" }, { MNT_NFS4ACLS, "nfsv4acls" }, { MNT_GJOURNAL, "gjournal" }, + { MNT_AUTOMOUNTED, "automounted" }, { 0, NULL } }; Modified: head/share/man/man5/Makefile ============================================================================== --- head/share/man/man5/Makefile Sun Aug 17 09:07:21 2014 (r270095) +++ head/share/man/man5/Makefile Sun Aug 17 09:44:42 2014 (r270096) @@ -7,6 +7,7 @@ MAN= acct.5 \ ar.5 \ a.out.5 \ + autofs.5 \ bluetooth.device.conf.5 \ bluetooth.hosts.5 \ bluetooth.protocols.5 \ Added: head/share/man/man5/autofs.5 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man5/autofs.5 Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,99 @@ +.\" 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 AUTHORS 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 AUTHORS 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$ +.\" +.Dd July 14, 2014 +.Dt AUTOFS 5 +.Os +.Sh NAME +.Nm autofs +.Nd "automounter filesystem" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in the +kernel configuration file: +.Bd -ragged -offset indent +.Cd "options AUTOFS" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +autofs_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver is the kernel component of the automounter infrastructure. +Its job is to pass mount requests to the +.Xr automountd 8 +daemon, and pause the processes trying to access the automounted filesystem +until the mount is completed. +It is mounted by the +.Xr automount 8 . +.Sh OPTIONS +These options are available when +mounting +.Nm +file systems: +.Bl -tag -width indent +.It Cm master_options +Mount options for all filesystems specified in the map entry. +.It Cm master_prefix +Filesystem mountpoint prefix. +.El +.Sh EXAMPLES +To unmount all mounted +.Nm +filesystems: +.Pp +.Dl "umount -At autofs" +.Pp +To mount +.Nm +filesystems specified in +.Xr auto_master 5 : +.Pp +.Dl "automount" +.Sh SEE ALSO +.Xr auto_master 5 , +.Xr automount 8 , +.Xr automountd 8 , +.Xr autounmountd 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 10.2 . +.Sh AUTHORS +The +.Nm +was developed by +.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org +under sponsorship from the FreeBSD Foundation. Modified: head/sys/conf/NOTES ============================================================================== --- head/sys/conf/NOTES Sun Aug 17 09:07:21 2014 (r270095) +++ head/sys/conf/NOTES Sun Aug 17 09:44:42 2014 (r270096) @@ -1012,6 +1012,7 @@ options FFS #Fast filesystem options NFSCLIENT #Network File System client # The rest are optional: +options AUTOFS #Automounter filesystem options CD9660 #ISO 9660 filesystem options FDESCFS #File descriptor filesystem options FUSE #FUSE support module Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Sun Aug 17 09:07:21 2014 (r270095) +++ head/sys/conf/files Sun Aug 17 09:44:42 2014 (r270096) @@ -2627,6 +2627,9 @@ dev/xen/timer/timer.c optional xen | xe dev/xen/pvcpu/pvcpu.c optional xen | xenhvm dev/xl/if_xl.c optional xl pci dev/xl/xlphy.c optional xl pci +fs/autofs/autofs.c optional autofs +fs/autofs/autofs_vfsops.c optional autofs +fs/autofs/autofs_vnops.c optional autofs fs/deadfs/dead_vnops.c standard fs/devfs/devfs_devs.c standard fs/devfs/devfs_dir.c standard @@ -3164,6 +3167,7 @@ libkern/strcmp.c standard libkern/strcpy.c standard libkern/strcspn.c standard libkern/strdup.c standard +libkern/strndup.c standard libkern/strlcat.c standard libkern/strlcpy.c standard libkern/strlen.c standard Modified: head/sys/conf/options ============================================================================== --- head/sys/conf/options Sun Aug 17 09:07:21 2014 (r270095) +++ head/sys/conf/options Sun Aug 17 09:44:42 2014 (r270096) @@ -221,6 +221,7 @@ INCLUDE_CONFIG_FILE opt_config.h # time, since the corresponding lkms cannot work if there are any static # dependencies. Unusability is enforced by hiding the defines for the # options in a never-included header. +AUTOFS opt_dontuse.h CD9660 opt_dontuse.h EXT2FS opt_dontuse.h FDESCFS opt_dontuse.h Added: head/sys/fs/autofs/autofs.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/fs/autofs/autofs.c Sun Aug 17 09:44:42 2014 (r270096) @@ -0,0 +1,637 @@ +/*- + * 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$ + */ +/*- + * 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/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/vnode.h> +#include <machine/atomic.h> +#include <vm/uma.h> + +#include "autofs.h" +#include "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 *sc; + +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; + + sc = malloc(sizeof(*sc), 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(&sc->sc_requests); + cv_init(&sc->sc_cv, "autofscv"); + sx_init(&sc->sc_lock, "autofslk"); + + error = make_dev_p(MAKEDEV_CHECKNAME, &sc->sc_cdev, &autofs_cdevsw, + NULL, UID_ROOT, GID_WHEEL, 0600, "autofs"); + if (error != 0) { + AUTOFS_WARN("failed to create device node, error %d", error); + free(sc, M_AUTOFS); + return (error); + } + sc->sc_cdev->si_drv1 = sc; + + return (0); +} + +int +autofs_uninit(struct vfsconf *vfsp) +{ + + sx_xlock(&sc->sc_lock); + if (sc->sc_dev_opened) { + sx_xunlock(&sc->sc_lock); + return (EBUSY); + } + if (sc->sc_cdev != NULL) + destroy_dev(sc->sc_cdev); + + uma_zdestroy(autofs_request_zone); + uma_zdestroy(autofs_node_zone); + + sx_xunlock(&sc->sc_lock); + /* + * XXX: Race with open? + */ + free(sc, M_AUTOFS); + + return (0); +} + +bool +autofs_ignore_thread(const struct thread *td) +{ + struct proc *p; + + p = td->td_proc; + + if (sc->sc_dev_opened == false) + return (false); + + PROC_LOCK(p); + if (p->p_session->s_sid == sc->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_callout(void *context) +{ + struct autofs_request *ar; + struct autofs_softc *sc; + + ar = context; + sc = ar->ar_mount->am_softc; + + sx_xlock(&sc->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_done = true; + ar->ar_in_progress = false; + cv_broadcast(&sc->sc_cv); + sx_xunlock(&sc->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 top-level nodes we need to request automountd(8) + * assistance even if the node is marked as cached, + * but the requested subdirectory does not exist. This + * is necessary for wildcard indirect map keys to work. + */ + if (anp->an_parent == NULL && componentlen != 0) { + AUTOFS_LOCK(amp); + error = autofs_node_find(anp, component, componentlen, NULL); + AUTOFS_UNLOCK(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; +} + +/* + * 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_softc *sc; + struct autofs_node *firstanp; + struct autofs_request *ar; + char *key, *path; + int error = 0, request_error, last; + + amp = VFSTOAUTOFS(anp->an_vnode->v_mount); + sc = amp->am_softc; + + sx_assert(&sc->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, &sc->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(&sc->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)); + + callout_init(&ar->ar_callout, 1); + callout_reset(&ar->ar_callout, + autofs_timeout * hz, autofs_callout, ar); + refcount_init(&ar->ar_refcount, 1); + TAILQ_INSERT_TAIL(&sc->sc_requests, ar, ar_next); + } + + cv_broadcast(&sc->sc_cv); + while (ar->ar_done == false) { + if (autofs_interruptible != 0) { + autofs_set_sigmask(&oldset); + error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); + autofs_restore_sigmask(&oldset); + if (error != 0) { + /* + * XXX: For some reson this returns -1 + * instead of EINTR, wtf?! + */ + error = EINTR; + AUTOFS_WARN("cv_wait_sig for %s failed " + "with error %d", ar->ar_path, error); + break; + } + } else { + cv_wait(&sc->sc_cv, &sc->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); + } + + last = refcount_release(&ar->ar_refcount); + if (last) { + TAILQ_REMOVE(&sc->sc_requests, ar, ar_next); + /* + * XXX: Is it safe? + */ + sx_xunlock(&sc->sc_lock); + callout_drain(&ar->ar_callout); + sx_xlock(&sc->sc_lock); + uma_zfree(autofs_request_zone, ar); + } + + /* + * 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; + 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) { + 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(&sc->sc_lock); + pause("autofs_retry", autofs_retry_delay * hz); + sx_xlock(&sc->sc_lock); + } +} + +static int +autofs_ioctl_request(struct autofs_softc *sc, struct autofs_daemon_request *adr) +{ + struct autofs_request *ar; + int error; + + sx_xlock(&sc->sc_lock); + for (;;) { + TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) { + if (ar->ar_done) + continue; + if (ar->ar_in_progress) + continue; + + break; + } + + if (ar != NULL) + break; + + error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); + if (error != 0) { + /* + * XXX: For some reson this returns -1 instead + * of EINTR, wtf?! + */ + error = EINTR; + sx_xunlock(&sc->sc_lock); + AUTOFS_DEBUG("failed with error %d", error); + return (error); + } + } + + ar->ar_in_progress = true; + sx_xunlock(&sc->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); + sc->sc_dev_sid = curproc->p_session->s_sid; + PROC_UNLOCK(curproc); + + return (0); +} + +static int +autofs_ioctl_done(struct autofs_softc *sc, struct autofs_daemon_done *add) +{ + struct autofs_request *ar; + + sx_xlock(&sc->sc_lock); + TAILQ_FOREACH(ar, &sc->sc_requests, ar_next) { + if (ar->ar_id == add->add_id) + break; + } + + if (ar == NULL) { + sx_xunlock(&sc->sc_lock); + AUTOFS_DEBUG("id %d not found", add->add_id); + return (ESRCH); + } + + ar->ar_error = add->add_error; + ar->ar_done = true; + ar->ar_in_progress = false; + cv_broadcast(&sc->sc_cv); + + sx_xunlock(&sc->sc_lock); + + return (0); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408170944.s7H9igDr008156>